Source: api/WSS_Connect.js

/**
* @file WebSocket Session connection API endpoint. The handshake MUST be established prior to attempting
* a connection.
*
* @example
* Client Request -> {"jsonrpc":"2.0","method":"WSS_Connect","id":"2,"params":{"user_token":"7060939278321507","server_token":"9789091435706088"}}
* Server Response -> {"jsonrpc":"2.0","result":{"message":"open","options":{},"private_id":"021b92efb9954fa4244c729190e05d2d9b55530d5e4f18da2d3615fdbad9c44d"},"id":"2"}
* Note: SHA256("9789091435706088:7060939278321507") = "021b92efb9954fa4244c729190e05d2d9b55530d5e4f18da2d3615fdbad9c44d";
*
* @version 0.4.1
*/
async function WSS_Connect (sessionObj) {
   if (sessionObj.endpoint.startsWith("ws") == false) {
      sendError(JSONRPC_ERRORS.WRONG_TRANSPORT, "Session must be created through a WebSocket connection.", sessionObj);
      return (false);
   }
   try {
      if ((namespace.wss["connections"] == undefined) || (namespace.wss["connections"] == null)) {
         namespace.wss.connections = new Array();
      }
   } catch (err) {
      console.error(err.stack);
   }
   var requestData = sessionObj.requestObj;
   var requestParams = requestData.params;
   if (typeof(requestParams["options"]) != "object") {
      sendError(JSONRPC_ERRORS.INVALID_PARAMS_ERROR, "Connection options not supplied or not an object.", sessionObj);
      return (false);
   }
   var responseObj = new Object();
   var connectionID = namespace.wss.makeConnectionID(sessionObj); //makeConnectionID defined in WebSocket_Handshake.js
   var resultObj = new Object(); //result to send in response
   resultObj.message = null; //single word response message
   resultObj.connect = new Array(); //list of already connected peers (may be empty)
   resultObj.options = new Array(); //associated list of peer options (as of v0.4.1)
   if ((namespace.wss.connections[connectionID] == null) || (namespace.wss.connections[connectionID] == undefined)) {
      sendError(JSONRPC_ERRORS.SESSION_CLOSE, "Session handshake not established.", sessionObj);
      return (false);
   }
   if (namespace.wss.connections[connectionID].length == 0) {
      sendError(JSONRPC_ERRORS.SESSION_CLOSE, "Session handshake not established.", sessionObj);
      return (false);
   }
   for (var count = 0; count < namespace.wss.connections[connectionID].length; count++) {
      var connectionObj = namespace.wss.connections[connectionID][count];
      if (connectionObj.user_token == requestParams.user_token) {
         if (connectionObj.server_token == requestParams.server_token) {
            if (connectionObj.socket == null) {
               connectionObj.last_update = new Date();
               connectionObj.private_id = namespace.wss.makePrivateID(sessionObj); //as of v0.4.1
               connectionObj.options = requestParams.options; //as of v0.4.1
               connectionObj.socket = sessionObj.serverResponse; //assign outgoing WebSockket instance
               connectionObj.socket.addEventListener("close", handleWebSocketClose);
               resultObj.message = "open";
               resultObj.private_id = connectionObj.private_id;
               //notify other peers of new connection
               var activeSessions = namespace.wss.allSessions(true);
               for (var count = 0; count < activeSessions.length; count++) {
                  //don't include sender in broadcast
                  if (activeSessions[count].user_token != requestParams.user_token) {
                     var messageObj = buildJSONRPC();
                     messageObj.result.type = "session";
                     messageObj.result.connect = connectionObj.private_id;
                     messageObj.result.options = requestParams.options;
                     activeSessions[count].socket.send(JSON.stringify(messageObj));
                     resultObj.connect.push(activeSessions[count].private_id);
                     resultObj.options.push(activeSessions[count].options);
                  }
               }
               sendResult(resultObj, sessionObj);
               return(true);
            } else {
               //socket already exists! do nothing except return error
               sendError(JSONRPC_ERRORS.SESSION_CLOSE, "Socket session exists.", sessionObj);
               return(false);
            }
         } else {
            //server tokens match but user tokens do not (send generic error)
            sendError(JSONRPC_ERRORS.SESSION_CLOSE, "Token mismatch.", sessionObj);
            return(false);
         }
      }
   }
   //something else went wrong
   sendError(JSONRPC_ERRORS.SESSION_CLOSE, "Socket session can't be established at this time.", sessionObj);
   return(false);
}

/**
* Handles a WebSocket close / disconnect event and notifies all active / live
* sessions of the disconnection.
*
* @param {Event} event A standard WebSocket close event.
*/
function handleWebSocketClose(event) {
   try {
      for (var connectionID in namespace.wss.connections) {
         if ((namespace.wss.connections[connectionID] != undefined) && (namespace.wss.connections[connectionID] != null)) {
            for (var count = 0; count < namespace.wss.connections[connectionID].length; count++) {
               var connectionObj = namespace.wss.connections[connectionID][count];
               if (connectionObj.socket == event.target) {
                  namespace.wss.connections[connectionID].splice(count, 1); //remove disconnected session
                  var activeSessions = namespace.wss.allSessions(true); //get all remaining sessions to notify them
                  for (var count2 = 0; count2 < activeSessions.length; count2++) {
                     var messageObj = buildJSONRPC();
                     messageObj.result.type = "session";
                     messageObj.result.disconnect = connectionObj.private_id;
                     //readyState == 1 = OPEN
                     if (activeSessions[count2].socket.readyState == 1) {
                        activeSessions[count2].socket.send(JSON.stringify(messageObj));
                     }
                  }
                  if (namespace.wss.connections[connectionID].length == 0) {
                     //no more connections for IP, clear entire entry
                     namespace.wss.connections[connectionID] = undefined;
                     delete namespace.wss.connections[connectionID];
                  }
                  return;
               }
            }
         }
      }
   } catch (err) {
      console.error(err.stack);
   }
}

if (namespace.wss == undefined) {
   namespace.wss = new Object();
}