Skip to content
This repository has been archived by the owner on Apr 4, 2019. It is now read-only.

User Metadata in the DataChannel logic? #2

Open
LuckyCyborg opened this issue Oct 12, 2017 · 5 comments
Open

User Metadata in the DataChannel logic? #2

LuckyCyborg opened this issue Oct 12, 2017 · 5 comments

Comments

@LuckyCyborg
Copy link

LuckyCyborg commented Oct 12, 2017

First of all, congratulations for this wonderful project! It is ideal for implementing a public and/or private chat.

BUT, what I miss is the ability to send some local user metadata on connection and/or with the messages.

That will permit to have the ability to display some shiny list of user on-line, or message.

I made an implementation sending (back) JSON messages, resulting something like in the folowing screenshot, BUT it complicate a bit the logic.

next109

So, I need to do something like:

channel.onopen = function (userid) {
    console.debug(userid, 'is connected with you.');

    setTimeout(function() {
        sendUserInfo(userid);

        // Enable the input.
        chatInput.attr("disabled", false);
        chatButton.attr("disabled", false);

        chatInput.focus();

    }, 5000);
};

channel.onmessage = function(message, userid, latency) {
    console.log('Latency:', latency, 'milliseconds');

    console.debug('Message from', userid, ':', message);

    var data = JSON.parse(message);

    if (data.type == 'message') {
        addChatMessage(data.message, data.realname, data.picture, 'left');
    }

    // Further, we will handle only the INFO messages.
    else if (data.type != 'info') {
        return;
    }

    if (! chatUsers[userid]) {
        chatUsers[userid] = data;

        addOnlineUser(userid, data);

        //
        var text = sprintf("<?= __d('chat', '%s (%s) joined the chat.'); ?>", data.realname, data.username);

        addLogMessage(text, 'success');
    }
};

function sendUserInfo(userid) {
    var value = JSON.stringify({
        type:     'info',
        username: userInfo.username,
        realname: userInfo.realname,
        roles:    userInfo.roles,
        picture:  userInfo.picture,
    });

    console.debug('Sending User info to', userid);

    channel.channels[userid].send(value);
}

function sendMessage() {
    var message = chatInput.val();

    var value = JSON.stringify({
        type:     'message',
        username: userInfo.username,
        realname: userInfo.realname,
        picture:  userInfo.picture,
        message:  message
     });

    channel.send(value);

    //
    addChatMessage(message, userInfo.realname, userInfo.picture, 'right');

    chatInput.val('');
}

IF there would be the ability to specify some metadata for the local User, the code would be greatly simplified and would not be a need to encode in the JSON the messages. For example:

channel.onopen = function (userid, data) {
    console.debug(userid, 'is connected with you.');

    if (! chatUsers[userid]) {
        chatUsers[userid] = data;

        addOnlineUser(userid, data);

        //
        var text = sprintf("<?= __d('chat', '%s (%s) joined the chat.'); ?>", data.realname, data.username);

        addLogMessage(text, 'success');
    }

    // Enable the input.
    chatInput.attr("disabled", false);
    chatButton.attr("disabled", false);

    chatInput.focus();
};

channel.onmessage = function(message, userid, latency, data) {
    console.log('Latency:', latency, 'milliseconds');

    console.debug('Message from', userid, ':', message);

    addChatMessage(data.message, data.realname, data.picture, 'left');
};

function sendMessage() {
    var message = chatInput.val();

    channel.send(value);

    //
    addChatMessage(message, userInfo.realname, userInfo.picture, 'right');

    chatInput.val('');
}

Where to add that User Medata? I think at beginning, something like:

var channel = new DataChannel();

channel.metadata = {
    userid:   '<?= $user->id; ?>',
    username: '<?= $user->username; ?>',
    realname: '<?= $user->realname; ?>',
    picture:  '<?= $user->picture(); ?>'
};

BTW, in the previous snippet, I used a piece from a PHP application.

@muaz-khan
Copy link
Owner

RTCMultiConnection and this library (DataChannel) both are using similar API.

RTCMultiConnection supports this: http://www.rtcmulticonnection.org/docs/extra/

You an set connection.extra object before starting or joining room. You can set this object anytime during a live session a well.

var channel = new RTCMultiConnection(); // using RTCMultiConnection

channel.extra = {    // using "extra" object
    userid:   '<?= $user->id; ?>',
    username: '<?= $user->username; ?>',
    realname: '<?= $user->realname; ?>',
    picture:  '<?= $user->picture(); ?>'
};

channel.onopen = function(event) {
   alert(event.extra.realname);
   alert(event.extra.username);
};

channel.onmessage = function(event) {
   alert(event.extra.realname);
   alert(event.extra.username);
   alert(event.data); // the actual chat message
};

// below 3 lines are different comparing DataChannel.js
channel .session = { data: true }; // tell that you need only chat/data connection
channel.socketURL = 'https://rtcmulticonnection.herokuapp.com:443/'; // socket.io signaling
channel.openOrJoin('room-id'); // open and/or join the room

Each and every event (whether it is onopen, onmessage, onclose etc.) will pass event object. That event object looks like this:

var event = {
    userid: 'unique username or userid of the user',
    extra: {}, // extra information/metadata
};

Which means that you an access extra information from any event using event.extra object.

You can find the documentation here: http://www.rtcmulticonnection.org/

RTCMultiConnection comes with these new events as well:

So you have a separate event to listen for all realtime extra metadata (information that are set/updated during live session).

You can update metadata during live session using following snippet:

channel.extra.picture = 'new picture';
channel.extra.realname = 'new realname';
channel.updateExtraData(); // this line will update changes to all connected users
```

@LuckyCyborg
Copy link
Author

LuckyCyborg commented Oct 13, 2017

Thanks you for your detailed response!

What you describe is exactly what I "miss" on DataChannel.

BUT, I have a very reason why I want that on DataChannel and not wanting to use RTCMultiConnection instead:

Basically, I written a (text) Chat module for the Nova Framework, where I am co-author.

It is here: https://github.com/nova-framework/framework/tree/3.0/app/Modules/Chat

The screenshot which I shown is made using this Chat module, BTW...

So, while for the public examples and tests I intend to use your own signaling servers, made in NodeJS, for the production applications, I want to reserve my ability, well... to have the ability to use a signaling server over WebSocket made in Ratchet PHP, for example.

In other hand, the DataChannel's signaling server is simple enough to be ported to Ratchet PHP in reasonable time.

And as a bottom line, I do not need all those nice features from RTCMultiConnection, but which make a bit rocket science from its signaling server. 😉

All I need is this DataChannel, with this metadata (or extra how you call it), to write that feature of a text Chat with a public room, and associated private chats. And its signaling server is simple enough to emulate it in another programming language and framework.

So, there is the question: you can add this extra metadata to DataChannel, without complicating also its signaling server too much and you to give too much effort? 😄

Eventually, I can help a bit, but I am not a JS Guru, to be honest.

PS. Also channel.openOrJoin('room-id'); is a very nice feature to have... 🥇

@muaz-khan
Copy link
Owner

I'll add extra object in the next commit.

openOrJoin relies on checkPresence. Presence detection relies totally on server. Presence detection is not reliable if we handle it inside the browser i.e.

  1. Sent presence detection request to room owner
  2. Wait about 5 seconds for his response; if he doesn't replies then consider room "NOT Available"
  3. If room owner replies under 5 seconds, then simply join the room

5 seconds waiter isn't a good idea. That's why presence detection should be handled on server side instead.

A server can check whether channel/room exist or not.

@LuckyCyborg
Copy link
Author

LuckyCyborg commented Oct 13, 2017

Well, the 5 seconds waiting time was an workaround... 😏

After all, the DataChannel has this magic checkPresence() today?

And thanks for you kindness, and for time which you spent on my particular request!

BTW, if you want to look in my current JS implementation of that Chat, it is there:

https://github.com/nova-framework/framework/blob/3.0/app/Modules/Chat/Views/Chat/Index.php

@LuckyCyborg
Copy link
Author

Another thing...

Is there a way in the DataChannel to customize the used ICE servers?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants