], function(err)
        {
          if(ERR(err, callback)) return;
          // next if session has not been deleted
          if(sessioninfos[session] == null)
          {
            callback(null);
            return;
          }
          if(author == sessioninfos[session].author)
          {
            socketio.sockets.sockets[session].json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}});
          }
          else
          {
            var forWire = Changeset.prepareForWire(revChangeset, pad.pool);
            var wireMsg = {"type":"COLLABROOM",
                           "data":{type:"NEW_CHANGES",
                                   newRev:r,
                                   changeset: forWire.translated,
                                   apool: forWire.pool,
                                   author: author,
                                   currentTime: currentTime,
                                   timeDelta: currentTime - sessioninfos[session].time
                                  }};        
                         
            socketio.sockets.sockets[session].json.send(wireMsg);
          }

           if(sessioninfos[session] != null)
           {
             sessioninfos[session].time = currentTime;
             sessioninfos[session].rev = r;
           }
          
          callback(null);
        });
Esempio n. 2
0
          function(revision, callback)
          {
            revCache[r] = revision;

            var author = revision.meta.author,
                revChangeset = revision.changeset,
                currentTime = revision.meta.timestamp;

            // next if session has not been deleted
            if(sessioninfos[sid] == null)
              return callback(null);

            if(author == sessioninfos[sid].author)
            {
              client.json.send({"type":"COLLABROOM","data":{type:"ACCEPT_COMMIT", newRev:r}});
            }
            else
            {
              var forWire = Changeset.prepareForWire(revChangeset, pad.pool);
              var wireMsg = {"type":"COLLABROOM",
                             "data":{type:"NEW_CHANGES",
                                     newRev:r,
                                     changeset: forWire.translated,
                                     apool: forWire.pool,
                                     author: author,
                                     currentTime: currentTime,
                                     timeDelta: currentTime - sessioninfos[sid].time
                                    }};        
                           
              client.json.send(wireMsg);
            }

            sessioninfos[sid].time = currentTime;
            sessioninfos[sid].rev = r;

            callback(null);
          }
    //glue the clientVars together, send them and tell the other clients that a new one is there
    function(callback)
    {
      //Check that the client is still here. It might have disconnected between callbacks.
      if(sessioninfos[client.id] === undefined)
      {
        callback();
        return;
      }

      //Check if this author is already on the pad, if yes, kick the other sessions!
      if(pad2sessions[padIds.padId])
      {
        for(var i in pad2sessions[padIds.padId])
        {
          if(sessioninfos[pad2sessions[padIds.padId][i]] && sessioninfos[pad2sessions[padIds.padId][i]].author == author)
          {
            var socket = socketio.sockets.sockets[pad2sessions[padIds.padId][i]];
            if(socket) socket.json.send({disconnect:"userdup"});
          }
        }
      }
      
      //Save in sessioninfos that this session belonges to this pad
      sessioninfos[client.id].padId = padIds.padId;
      sessioninfos[client.id].readOnlyPadId = padIds.readOnlyPadId;
      sessioninfos[client.id].readonly = padIds.readonly;
      
      //check if there is already a pad2sessions entry, if not, create one
      if(!pad2sessions[padIds.padId])
      {
        pad2sessions[padIds.padId] = [];
      }
      
      //Saves in pad2sessions that this session belongs to this pad
      pad2sessions[padIds.padId].push(client.id);
            
      //If this is a reconnect, we don't have to send the client the ClientVars again
      if(message.reconnect == true)
      {
        //Save the revision in sessioninfos, we take the revision from the info the client send to us
        sessioninfos[client.id].rev = message.client_rev;
      }
      //This is a normal first connect
      else
      {
        //prepare all values for the wire
        var atext = Changeset.cloneAText(pad.atext);
        var attribsForWire = Changeset.prepareForWire(atext.attribs, pad.pool);
        var apool = attribsForWire.pool.toJsonable();
        atext.attribs = attribsForWire.translated;
        
        // Warning: never ever send padIds.padId to the client. If the
        // client is read only you would open a security hole 1 swedish
        // mile wide...
        var clientVars = {
          "accountPrivs": {
              "maxRevisions": 100
          },
          "initialRevisionList": [],
          "initialOptions": {
              "guestPolicy": "deny"
          },
          "savedRevisions": pad.getSavedRevisions(),
          "collab_client_vars": {
              "initialAttributedText": atext,
              "clientIp": "127.0.0.1",
              "padId": message.padId,
              "historicalAuthorData": historicalAuthorData,
              "apool": apool,
              "rev": pad.getHeadRevisionNumber(),
              "globalPadId": message.padId,
              "time": currentTime,
          },
          "colorPalette": authorManager.getColorPalette(),
          "clientIp": "127.0.0.1",
          "userIsGuest": true,
          "userColor": authorColorId,
          "padId": message.padId,
          "initialTitle": "Pad: " + message.padId,
          "opts": {},
          // tell the client the number of the latest chat-message, which will be 
          // used to request the latest 100 chat-messages later (GET_CHAT_MESSAGES)
          "chatHead": pad.chatHead,
          "numConnectedUsers": pad2sessions[padIds.padId].length,
          "isProPad": false,
          "readOnlyId": padIds.readOnlyPadId,
          "readonly": padIds.readonly,
          "serverTimestamp": new Date().getTime(),
          "globalPadId": message.padId,
          "userId": author,
          "cookiePrefsToSet": {
              "fullWidth": false,
              "hideSidebar": false
          },
          "abiwordAvailable": settings.abiwordAvailable(), 
          "plugins": {
            "plugins": plugins.plugins,
            "parts": plugins.parts,
          },
          "initialChangesets": [] // FIXME: REMOVE THIS SHIT
        }

        //Add a username to the clientVars if one avaiable
        if(authorName != null)
        {
          clientVars.userName = authorName;
        }
        
        //call the clientVars-hook so plugins can modify them before they get sent to the client
        hooks.aCallAll("clientVars", { clientVars: clientVars, pad: pad }, function ( err, messages ) {
          if(ERR(err, callback)) return;
          
          _.each(messages, function(newVars) {
            //combine our old object with the new attributes from the hook
            for(var attr in newVars) {
              clientVars[attr] = newVars[attr];
            }
          });
        
          //Send the clientVars to the Client
          client.json.send({type: "CLIENT_VARS", data: clientVars});
          //Save the current revision in sessioninfos, should be the same as in clientVars
          sessioninfos[client.id].rev = pad.getHeadRevisionNumber();
        });
      }
        
      sessioninfos[client.id].author = author;
      
      //prepare the notification for the other users on the pad, that this user joined
      var messageToTheOtherUsers = {
        "type": "COLLABROOM",
        "data": {
          type: "USER_NEWINFO",
          userInfo: {
            "ip": "127.0.0.1",
            "colorId": authorColorId,
            "userAgent": "Anonymous",
            "userId": author
          }
        }
      };
      
      //Add the authorname of this new User, if avaiable
      if(authorName != null)
      {
        messageToTheOtherUsers.data.userInfo.name = authorName;
      }
      
      //Run trough all sessions of this pad
      async.forEach(pad2sessions[padIds.padId], function(sessionID, callback)
      {
        var author, socket, sessionAuthorName, sessionAuthorColorId;
        
        //Since sessioninfos might change while being enumerated, check if the 
        //sessionID is still assigned to a valid session
        if(sessioninfos[sessionID] !== undefined &&
          socketio.sockets.sockets[sessionID] !== undefined){
          author = sessioninfos[sessionID].author;
          socket = socketio.sockets.sockets[sessionID];
        }else {
          // If the sessionID is not valid, callback();
          callback();
          return;
        }
        async.series([
          //get the authorname & colorId
          function(callback)
          {
            async.parallel([
              function(callback)
              {
                authorManager.getAuthorColorId(author, function(err, value)
                {
                  if(ERR(err, callback)) return;
                  sessionAuthorColorId = value;
                  callback();
                })
              },
              function(callback)
              {
                authorManager.getAuthorName(author, function(err, value)
                {
                  if(ERR(err, callback)) return;
                  sessionAuthorName = value;
                  callback();
                })
              }
            ],callback);
          }, 
          function (callback)
          {
            //Jump over, if this session is the connection session
            if(sessionID != client.id)
            {
              //Send this Session the Notification about the new user
              socket.json.send(messageToTheOtherUsers);
            
              //Send the new User a Notification about this other user
              var messageToNotifyTheClientAboutTheOthers = {
                "type": "COLLABROOM",
                "data": {
                  type: "USER_NEWINFO",
                  userInfo: {
                    "ip": "127.0.0.1",
                    "colorId": sessionAuthorColorId,
                    "name": sessionAuthorName,
                    "userAgent": "Anonymous",
                    "userId": author
                  }
                }
              };
              client.json.send(messageToNotifyTheClientAboutTheOthers);
            }
          }
        ], callback);        
      }, callback);
    }
Esempio n. 4
0
    //glue the clientVars together, send them and tell the other clients that a new one is there
    function(callback)
    {
      //Check that the client is still here. It might have disconnected between callbacks.
      if(sessioninfos[client.id] === undefined)
        return callback();

      //Check if this author is already on the pad, if yes, kick the other sessions!
      var roomClients = socketio.sockets.clients(padIds.padId);
      for(var i = 0; i < roomClients.length; i++) {
        var sinfo = sessioninfos[roomClients[i].id];
        if(sinfo && sinfo.author == author) {
          // fix user's counter, works on page refresh or if user closes browser window and then rejoins
          sessioninfos[roomClients[i].id] = {};
          roomClients[i].leave(padIds.padId);
          roomClients[i].json.send({disconnect:"userdup"});
        }
      }
      
      //Save in sessioninfos that this session belonges to this pad
      sessioninfos[client.id].padId = padIds.padId;
      sessioninfos[client.id].readOnlyPadId = padIds.readOnlyPadId;
      sessioninfos[client.id].readonly = padIds.readonly;
      
      //Log creation/(re-)entering of a pad
      client.get('remoteAddress', function(er, ip) {
        if(pad.head > 0) {
          accessLogger.info('[ENTER] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" entered the pad');
        }
        else if(pad.head == 0) {
          accessLogger.info('[CREATE] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" created the pad');
        }
      })

      //If this is a reconnect, we don't have to send the client the ClientVars again
      if(message.reconnect == true)
      {
        //Join the pad and start receiving updates
        client.join(padIds.padId);
        //Save the revision in sessioninfos, we take the revision from the info the client send to us
        sessioninfos[client.id].rev = message.client_rev;
      }
      //This is a normal first connect
      else
      {
        //prepare all values for the wire
        var atext = Changeset.cloneAText(pad.atext);
        var attribsForWire = Changeset.prepareForWire(atext.attribs, pad.pool);
        var apool = attribsForWire.pool.toJsonable();
        atext.attribs = attribsForWire.translated;
        
        // Warning: never ever send padIds.padId to the client. If the
        // client is read only you would open a security hole 1 swedish
        // mile wide...
        var clientVars = {
          "accountPrivs": {
              "maxRevisions": 100
          },
          "initialRevisionList": [],
          "initialOptions": {
              "guestPolicy": "deny"
          },
          "savedRevisions": pad.getSavedRevisions(),
          "collab_client_vars": {
              "initialAttributedText": atext,
              "clientIp": "127.0.0.1",
              "padId": message.padId,
              "historicalAuthorData": historicalAuthorData,
              "apool": apool,
              "rev": pad.getHeadRevisionNumber(),
              "globalPadId": message.padId,
              "time": currentTime,
          },
          "colorPalette": authorManager.getColorPalette(),
          "clientIp": "127.0.0.1",
          "userIsGuest": true,
          "userColor": authorColorId,
          "padId": message.padId,
          "initialTitle": "Pad: " + message.padId,
          "opts": {},
          // tell the client the number of the latest chat-message, which will be 
          // used to request the latest 100 chat-messages later (GET_CHAT_MESSAGES)
          "chatHead": pad.chatHead,
          "numConnectedUsers": roomClients.length,
          "readOnlyId": padIds.readOnlyPadId,
          "readonly": padIds.readonly,
          "serverTimestamp": new Date().getTime(),
          "globalPadId": message.padId,
          "userId": author,
          "abiwordAvailable": settings.abiwordAvailable(), 
          "plugins": {
            "plugins": plugins.plugins,
            "parts": plugins.parts,
          },
          "initialChangesets": [] // FIXME: REMOVE THIS SHIT
        }

        //Add a username to the clientVars if one avaiable
        if(authorName != null)
        {
          clientVars.userName = authorName;
        }
        
        //call the clientVars-hook so plugins can modify them before they get sent to the client
        hooks.aCallAll("clientVars", { clientVars: clientVars, pad: pad }, function ( err, messages ) {
          if(ERR(err, callback)) return;
          
          _.each(messages, function(newVars) {
            //combine our old object with the new attributes from the hook
            for(var attr in newVars) {
              clientVars[attr] = newVars[attr];
            }
          });
        
          //Join the pad and start receiving updates
          client.join(padIds.padId);
          //Send the clientVars to the Client
          client.json.send({type: "CLIENT_VARS", data: clientVars});
          //Save the current revision in sessioninfos, should be the same as in clientVars
          sessioninfos[client.id].rev = pad.getHeadRevisionNumber();
        });
      }
        
      sessioninfos[client.id].author = author;
      
      //prepare the notification for the other users on the pad, that this user joined
      var messageToTheOtherUsers = {
        "type": "COLLABROOM",
        "data": {
          type: "USER_NEWINFO",
          userInfo: {
            "ip": "127.0.0.1",
            "colorId": authorColorId,
            "userAgent": "Anonymous",
            "userId": author
          }
        }
      };
      
      //Add the authorname of this new User, if avaiable
      if(authorName != null)
      {
        messageToTheOtherUsers.data.userInfo.name = authorName;
      }

      // notify all existing users about new user
      client.broadcast.to(padIds.padId).json.send(messageToTheOtherUsers);
      
      //Run trough all sessions of this pad
      async.forEach(socketio.sockets.clients(padIds.padId), function(roomClient, callback)
      {
        var author;

        //Jump over, if this session is the connection session
        if(roomClient.id == client.id)
          return callback();
          
        
        //Since sessioninfos might change while being enumerated, check if the 
        //sessionID is still assigned to a valid session
        if(sessioninfos[roomClient.id] !== undefined)
          author = sessioninfos[roomClient.id].author;
        else // If the client id is not valid, callback();
          return callback();

        async.waterfall([
          //get the authorname & colorId
          function(callback)
          {
            // reuse previously created cache of author's data
            if(historicalAuthorData[author])
              callback(null, historicalAuthorData[author]);
            else
              authorManager.getAuthor(author, callback);
          }, 
          function (authorInfo, callback)
          {
            //Send the new User a Notification about this other user
            var msg = {
              "type": "COLLABROOM",
              "data": {
                type: "USER_NEWINFO",
                userInfo: {
                  "ip": "127.0.0.1",
                  "colorId": authorInfo.colorId,
                  "name": authorInfo.name,
                  "userAgent": "Anonymous",
                  "userId": author
                }
              }
            };
            client.json.send(msg);
          }
        ], callback);
      }, callback);
    }