Lucid Projects

Blog - Day to day mumblings...
DataChannel Chat

DataChannel Chat

11 Nov 2020 - Jake Sherwood

datachannels DataChannel Chat

DataChannel Chat w/ Private Messages

We can do more than just send streams through simplepeer.js. We can use data channels.

The peer.send method allows us to send a few different types: String, Buffer, ArrayBufferView, ArrayBuffer, or Blob.

Building off the example from class I wanted to work with chat some more.

In class we had a simple example going that flashed a background color anytime a message was received.

I decided that to take that a little further and make it flash whatever color word was sent in the chat.

There are a few “easter egg” colors that will make further changes by setting background images etc.

I moved over some of my previous chat code to get local messages showing, choose/set and cookie username, style local and remote messages, tooltips etc.

I also added a right panel that shows all color options and hints to which ones have special functions.

The heavy lifting on this version was getting private messaging sorted it.

It seemed pretty straight forward, I could just set the value of the peer I wanted to message with a select. And instead of looping through all peers, I just send to which ever is selected in the dropdown.

if (chatSelectVal != 'all') {
	let userIndex = simplepeers.findIndex(u => u.user == chatSelectVal);

	let prvData = {
		data: data,
		prv: true
	};
	let stringPrvData = JSON.stringify(prvData);

	simplepeers[userIndex].sendData(stringPrvData, liveWebUser);
	myLocalMsg = "<br><div class=\"localmsg\"><span class=\"user\">" + liveWebUser + "</span>: " + prvData
		.data +
		"<span class=\"private_msg\"> pvtmsg to: " + chatSelectVal + "</span></div>";

}

That worked and properly send my private msg and showed my private msg style locally but getting the “message” to the peer that it was a private message and that it should use the private message style took a bit more work.

This is how I wanted it to look and the result after I eventually got it working.


datachannel chat private message detail

I tried to send another value in the function call. Something like true or false for private. message

simplepeers[i].sendData(stringPubData, liveWebUser, true); // true or false for pvt msg

That didn’t seem to work and after some time with the docs it looked like the peer.on('data', data => {}) can only receive the one ‘data’ attribute.

Ok, lets make a JSON object.

let prvData = {
	   data: data,
	   prv: true
   };

Sweet problem solved… nope.

I kept getting values like this.

Uint8Array(15) [91, 111, 98, 106, 101, 99, 116, 32, 79, 98, 106, 101, 99, 116, 93]

Umm… what the??!?

Console logging from the sending peer seemed to log my JSON properly. Head scratching…

Back to the docs…

Looking further I see in the signal examples it talks about stringfying the JSON before sending and then JSON.parse’ing it on the receiver side.

// JSON.stringify sender msg
let prvData = {
	data: data,
	prv: true
};
let stringPrvData = JSON.stringify(prvData);

...

// JSON.parse receiver msg
let recdData = JSON.parse(theData);

And voila it worked.


datachannel chat private messages

That was the meat of the project and hiccups on this one for me. I was happy to get it sorted and learn a few things along the way.

To make it a little more fun, certain colors sent will set background images. You can set them for the whole group, for individuals by private message, or for yourself by checking the “see” checkbox.


datachannel chat set backgrounds

As mentioned above, I added tooltips to help the user understand the UI. It seemed a little overbaring after a while so I added functionality to turn them off after 15 seconds. If you get confused about what does what you can turn them back on by clicking help.

/ turn off tooltips after 15 seconds
// destroy exampe found here.  modified to disable
// https://github.com/atomiks/tippyjs/issues/473#issuecomment-485055710

function hideTooltips() {
    setTimeout(function () {
        // tippy.hideAll();
        [...document.querySelectorAll('*')].forEach(node => {
            if (node._tippy) {
                node._tippy.disable();
            }
        });
    }, 15000);
}

hideTooltips();

function showTooltips() {
    [...document.querySelectorAll('*')].forEach(node => {
        if (node._tippy) {
            node._tippy.enable();
        }
    });

    hideTooltips();
}


datachannel chat tooltips

Github code here.

categories: liveweb

join me on this crazy ride. enter your email:

contact [at] jakesherwood [dot] com

contact me if you'd like to work together