Sending peer-to-peer messages with PeerJS

Greetings, dear readers. In a previous article, I talked about how to make a simple dialer in a browser using PeerJS . And today I plan to consider how to exchange messages between two users directly without delay.



Who cares? If you are developing an online game in which you need a quick exchange of data between players, then direct messaging is perhaps what you need.



Markup and initialization



I will show how the technology works, using an example of a simple chat between two users , and also tell you how to adapt the code for exchanging game data.



Let's start with the initial markup and initialization of the peer object



<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>PeerJS  </title> <script src="https://unpkg.com/peerjs@1.0.0/dist/peerjs.min.js"></script> </head> <body> <h3> ID: <span id=myid ></span></h3> <input id=otherPeerId type=text placeholder="otherPeerId" ><button onclick="connectToNode(document.getElementById('otherPeerId').value)"></button> <div id=messages style="width:400px;height:60vh; background:#ADD8E6;margin:5px;"> </div><br> <textarea id=mess style="width:400px;height:15vh" ></textarea><br> <button onclick="sendMess(document.getElementById('mess'))"></button> <script> var messList=[]; function addMess(mess) { messList.push(mess); document.getElementById('messages').innerHTML=messList.join(""); } var peer=new Peer(); // peer var conn; //,   peer.on('open', function(peerID) { document.getElementById('myid').innerHTML=peerID; }); </script> </body>
      
      





In the heading we connect PeerJS. What role do the elements with myid and otherPeerId indices play in the call article



The messList array will store the message feed. The addMess function will add elements to this array and output its contents to the correspondence container.



Next up is the initialization of the peer object, which is also described in the last article .



Now a little about connections. To establish a connection, it is necessary that one participant, knowing the peerID of another, start a connection with him, and the second one receives this connection.



Establish a connection



 peer.on('connection', function(c) { // ... conn=c; initConn(); }); function connectToNode(partnerPeer) { // ... conn = peer.connect(partnerPeer); conn.partnerPeer=partnerPeer; initConn(); }
      
      





The 'connection' event for the peer object occurs on an incoming connection. And the connect function of the peer object establishes such a connection. In both cases, we will save the connection object to the variable conn . Since further actions with the connection for the current training example will be identical (although there may be a difference in the combat project), I put initConn into a separate function.



 function initConn() { conn.on ('open', function () { //  addMess("<div><h4> </h4></div>"); conn.on ('data', function (data) { //  addMess("<div><b>: </b>"+data+"</div>"); }); }); conn.on('close',function() {addMess('----------- -------------');}); }
      
      





Here we hang 2 handlers: to open and to close the connection. In the handler for opening a connection, we add the handler to receive data, which will add an incoming message to the dialog container.



It remains only to implement a function that will send a message by pressing the Send button, which:



  1. adds a message to his feed
  2. sends a message to the partner (send method of the connection object)
  3. clears the message entry field



     function sendMess(elem) { addMess("<div><b>: </b>"+elem.value+"</div>"); conn.send(elem.value); elem.value=""; }
          
          





Adaptation to transfer game data



What needs to be done in order to send in the same way not ordinary text, but data that needs to be exchanged during games? Nothing really special. In JS, there are JSON.stringify and JSON.parse methods that convert an object to a string and vice versa. Just wrap your data object, convert the object to a string (JSON.stringify) before sending and turn the received data into an object (JSON.parse) when received



 // gameObject={x:2,y:5,...} conn.send(JSON.stringify(gameObject)); // conn.on ('data', function (data) { //  gameObject=JSON.parse(data); });
      
      





Typically, large amounts of data are not needed to send game objects and text messages. But if you are going to forward the contents of the entire container on the page (a bunch of HTML code), keep in mind that a large connection may not reach unchanged.



From personal experience I’ll say: you should not forward messages more than 10 KB (~ 10 000 characters) in this way. It is better to write such a message to a temporary file and send a command to the partner to read the code from this file (I think you got the point).



We could stop at this, if not ...



Connection break



Yes, this is happening. The reason for this is unstable Internet. Has it ever happened that you have almost won, but the connection is broken and you lose all your progress? To avoid this, let's add a code that will raise a fallen connection. We will handle the event 'close' for this. This event occurs if:



  1. the connection was intentionally closed
  2. connection was lost due to poor internet or the partner simply closed the tab



     conn.on('close',function() { setTimeout(function() { if(conn.partnerPeer) { var pp=conn.partnerPeer; conn = peer.connect(conn.partnerPeer); conn.partnerPeer=pp; initConn(); } else conn=null; } ,2000); addMess('----------- -------------'); });
          
          





Here we, with a delay of 2 seconds after a disconnection, are simply trying to establish a new one.



The partnerPeer of the conn object is present only in the partner who established the connection for the first time, which means that only one of the 2 sides of the connection will start to restore it when it breaks.



And now the whole code:



 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>PeerJS  </title> <script src="https://unpkg.com/peerjs@1.0.0/dist/peerjs.min.js"></script> </head> <body> <h3> ID: <span id=myid ></span></h3> <input id=otherPeerId type=text placeholder="otherPeerId" ><button onclick="connectToNode(document.getElementById('otherPeerId').value)"></button> <div id=messages style="width:400px;height:60vh; background:#ADD8E6;margin:5px;"> </div><br> <textarea id=mess style="width:400px;height:15vh" ></textarea><br> <button onclick="sendMess(document.getElementById('mess'))"></button> <script> var messList=[]; function addMess(mess) { messList.push(mess); document.getElementById('messages').innerHTML=messList.join(""); } var peer=new Peer(); var conn; //,   peer.on('open', function(peerID) { document.getElementById('myid').innerHTML=peerID; }); peer.on('connection', function(c) { // ... conn=c; initConn(); }); function connectToNode(partnerPeer) { // ... conn = peer.connect(partnerPeer); initConn(); } function initConn() { conn.on ('open', function () { //  addMess("<div><h4> </h4></div>"); conn.on ('data', function (data) { //  addMess("<div><b>: </b>"+data+"</div>"); }); }); conn.on('close',function() {addMess('----------- -------------');}); } function sendMess(elem) { addMess("<div><b>: </b>"+elem.value+"</div>"); conn.send(elem.value); elem.value=""; } </script> </body>
      
      






All Articles