mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-21 07:56:16 -04:00
PadMessageHandler.js: completed conversion
This commit is contained in:
parent
9246a1de26
commit
bb80325d2c
2 changed files with 115 additions and 188 deletions
|
@ -289,10 +289,10 @@ exports.doImport = function(req, res, padId)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
padMessageHandler.updatePadClients(pad, function(){
|
// @TODO: not waiting for updatePadClients to finish
|
||||||
|
padMessageHandler.updatePadClients(pad);
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
var ERR = require("async-stacktrace");
|
|
||||||
var async = require("async");
|
|
||||||
var padManager = require("../db/PadManager");
|
var padManager = require("../db/PadManager");
|
||||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
||||||
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
|
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
|
||||||
|
@ -38,7 +36,6 @@ var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
|
||||||
var channels = require("channels");
|
var channels = require("channels");
|
||||||
var stats = require('../stats');
|
var stats = require('../stats');
|
||||||
var remoteAddress = require("../utils/RemoteAddress").remoteAddress;
|
var remoteAddress = require("../utils/RemoteAddress").remoteAddress;
|
||||||
const thenify = require("thenify").withCallback;
|
|
||||||
const nodeify = require("nodeify");
|
const nodeify = require("nodeify");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,16 +59,14 @@ stats.gauge('totalUsers', function() {
|
||||||
/**
|
/**
|
||||||
* A changeset queue per pad that is processed by handleUserChanges()
|
* A changeset queue per pad that is processed by handleUserChanges()
|
||||||
*/
|
*/
|
||||||
var padChannels = new channels.channels(handleUserChangesCB);
|
var padChannels = new channels.channels(function(data, callback) {
|
||||||
|
|
||||||
function handleUserChangesCB(data, callback) {
|
|
||||||
return nodeify(handleUserChanges(data), callback);
|
return nodeify(handleUserChanges(data), callback);
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the Socket class we need to send and receive data from the client
|
* Saves the Socket class we need to send and receive data from the client
|
||||||
*/
|
*/
|
||||||
var socketio;
|
let socketio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Method is called by server.js to tell the message handler on which socket it should send
|
* This Method is called by server.js to tell the message handler on which socket it should send
|
||||||
|
@ -115,17 +110,17 @@ exports.kickSessionsFromPad = function(padID)
|
||||||
* Handles the disconnection of a user
|
* Handles the disconnection of a user
|
||||||
* @param client the client that leaves
|
* @param client the client that leaves
|
||||||
*/
|
*/
|
||||||
exports.handleDisconnect = function(client)
|
exports.handleDisconnect = async function(client)
|
||||||
{
|
{
|
||||||
stats.meter('disconnects').mark();
|
stats.meter('disconnects').mark();
|
||||||
|
|
||||||
// save the padname of this session
|
// save the padname of this session
|
||||||
var session = sessioninfos[client.id];
|
let session = sessioninfos[client.id];
|
||||||
|
|
||||||
// if this connection was already etablished with a handshake, send a disconnect message to the others
|
// if this connection was already etablished with a handshake, send a disconnect message to the others
|
||||||
if (session && session.author) {
|
if (session && session.author) {
|
||||||
// Get the IP address from our persistant object
|
// Get the IP address from our persistant object
|
||||||
var ip = remoteAddress[client.id];
|
let ip = remoteAddress[client.id];
|
||||||
|
|
||||||
// Anonymize the IP address if IP logging is disabled
|
// Anonymize the IP address if IP logging is disabled
|
||||||
if (settings.disableIPlogging) {
|
if (settings.disableIPlogging) {
|
||||||
|
@ -135,11 +130,10 @@ exports.handleDisconnect = function(client)
|
||||||
accessLogger.info('[LEAVE] Pad "' + session.padId + '": Author "' + session.author + '" on client ' + client.id + ' with IP "' + ip + '" left the pad');
|
accessLogger.info('[LEAVE] Pad "' + session.padId + '": Author "' + session.author + '" on client ' + client.id + ' with IP "' + ip + '" left the pad');
|
||||||
|
|
||||||
// get the author color out of the db
|
// get the author color out of the db
|
||||||
authorManager.getAuthorColorId(session.author, function(err, color) {
|
let color = await authorManager.getAuthorColorId(session.author);
|
||||||
ERR(err);
|
|
||||||
|
|
||||||
// prepare the notification for the other users on the pad, that this user left
|
// prepare the notification for the other users on the pad, that this user left
|
||||||
var messageToTheOtherUsers = {
|
let messageToTheOtherUsers = {
|
||||||
"type": "COLLABROOM",
|
"type": "COLLABROOM",
|
||||||
"data": {
|
"data": {
|
||||||
type: "USER_LEAVE",
|
type: "USER_LEAVE",
|
||||||
|
@ -157,7 +151,6 @@ exports.handleDisconnect = function(client)
|
||||||
|
|
||||||
// Allow plugins to hook into users leaving the pad
|
// Allow plugins to hook into users leaving the pad
|
||||||
hooks.callAll("userLeave", session);
|
hooks.callAll("userLeave", session);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the sessioninfos entrys of this session
|
// Delete the sessioninfos entrys of this session
|
||||||
|
@ -179,7 +172,7 @@ exports.handleMessage = async function(client, message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var thisSession = sessioninfos[client.id];
|
let thisSession = sessioninfos[client.id];
|
||||||
|
|
||||||
if (!thisSession) {
|
if (!thisSession) {
|
||||||
messageLogger.warn("Dropped message from an unknown connection.")
|
messageLogger.warn("Dropped message from an unknown connection.")
|
||||||
|
@ -248,7 +241,7 @@ exports.handleMessage = async function(client, message)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In a previous version of this code, an "if (message)" wrapped the
|
* In a previous version of this code, an "if (message)" wrapped the
|
||||||
* following async.series().
|
* following series of async calls [now replaced with await calls]
|
||||||
* This ugly "!Boolean(message)" is a lame way to exactly negate the truthy
|
* This ugly "!Boolean(message)" is a lame way to exactly negate the truthy
|
||||||
* condition and replace it with an early return, while being sure to leave
|
* condition and replace it with an early return, while being sure to leave
|
||||||
* the original behaviour unchanged.
|
* the original behaviour unchanged.
|
||||||
|
@ -310,15 +303,13 @@ exports.handleMessage = async function(client, message)
|
||||||
* @param client the client that send this message
|
* @param client the client that send this message
|
||||||
* @param message the message from the client
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
function handleSaveRevisionMessage(client, message){
|
async function handleSaveRevisionMessage(client, message)
|
||||||
|
{
|
||||||
var padId = sessioninfos[client.id].padId;
|
var padId = sessioninfos[client.id].padId;
|
||||||
var userId = sessioninfos[client.id].author;
|
var userId = sessioninfos[client.id].author;
|
||||||
|
|
||||||
padManager.getPad(padId, function(err, pad) {
|
let pad = await padManager.getPad(padId);
|
||||||
if (ERR(err)) return;
|
|
||||||
|
|
||||||
pad.addSavedRevision(pad.head, userId);
|
pad.addSavedRevision(pad.head, userId);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -328,7 +319,7 @@ function handleSaveRevisionMessage(client, message){
|
||||||
* @param msg {Object} the message we're sending
|
* @param msg {Object} the message we're sending
|
||||||
* @param sessionID {string} the socketIO session to which we're sending this message
|
* @param sessionID {string} the socketIO session to which we're sending this message
|
||||||
*/
|
*/
|
||||||
exports.handleCustomObjectMessage = async function(msg, sessionID) {
|
exports.handleCustomObjectMessage = function(msg, sessionID) {
|
||||||
if (msg.data.type === "CUSTOM") {
|
if (msg.data.type === "CUSTOM") {
|
||||||
if (sessionID){
|
if (sessionID){
|
||||||
// a sessionID is targeted: directly to this sessionID
|
// a sessionID is targeted: directly to this sessionID
|
||||||
|
@ -346,9 +337,9 @@ exports.handleCustomObjectMessage = async function(msg, sessionID) {
|
||||||
* @param padID {Pad} the pad to which we're sending this message
|
* @param padID {Pad} the pad to which we're sending this message
|
||||||
* @param msgString {String} the message we're sending
|
* @param msgString {String} the message we're sending
|
||||||
*/
|
*/
|
||||||
exports.handleCustomMessage = thenify(function(padID, msgString, cb) {
|
exports.handleCustomMessage = function(padID, msgString) {
|
||||||
var time = Date.now();
|
let time = Date.now();
|
||||||
var msg = {
|
let msg = {
|
||||||
type: 'COLLABROOM',
|
type: 'COLLABROOM',
|
||||||
data: {
|
data: {
|
||||||
type: msgString,
|
type: msgString,
|
||||||
|
@ -356,9 +347,7 @@ exports.handleCustomMessage = thenify(function(padID, msgString, cb) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
socketio.sockets.in(padID).json.send(msg);
|
socketio.sockets.in(padID).json.send(msg);
|
||||||
|
}
|
||||||
cb(null, {});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a Chat Message
|
* Handles a Chat Message
|
||||||
|
@ -382,55 +371,24 @@ function handleChatMessage(client, message)
|
||||||
* @param text the text of the chat message
|
* @param text the text of the chat message
|
||||||
* @param padId the padId to send the chat message to
|
* @param padId the padId to send the chat message to
|
||||||
*/
|
*/
|
||||||
exports.sendChatMessageToPadClients = function(time, userId, text, padId) {
|
exports.sendChatMessageToPadClients = async function(time, userId, text, padId)
|
||||||
var pad;
|
{
|
||||||
var userName;
|
|
||||||
|
|
||||||
async.series([
|
|
||||||
// get the pad
|
// get the pad
|
||||||
function(callback) {
|
let pad = await padManager.getPad(padId);
|
||||||
padManager.getPad(padId, function(err, _pad) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
pad = _pad;
|
// get the author
|
||||||
callback();
|
let userName = await authorManager.getAuthorName(userId);
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
function(callback) {
|
|
||||||
authorManager.getAuthorName(userId, function(err, _userName) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
userName = _userName;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// save the chat message and broadcast it
|
|
||||||
function(callback) {
|
|
||||||
// save the chat message
|
// save the chat message
|
||||||
pad.appendChatMessage(text, userId, time);
|
pad.appendChatMessage(text, userId, time);
|
||||||
|
|
||||||
var msg = {
|
let msg = {
|
||||||
type: "COLLABROOM",
|
type: "COLLABROOM",
|
||||||
data: {
|
data: { type: "CHAT_MESSAGE", userId, userName, time, text }
|
||||||
type: "CHAT_MESSAGE",
|
|
||||||
userId: userId,
|
|
||||||
userName: userName,
|
|
||||||
time: time,
|
|
||||||
text: text
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// broadcast the chat message to everyone on the pad
|
// broadcast the chat message to everyone on the pad
|
||||||
socketio.sockets.in(padId).json.send(msg);
|
socketio.sockets.in(padId).json.send(msg);
|
||||||
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
],
|
|
||||||
function(err) {
|
|
||||||
ERR(err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -438,7 +396,7 @@ exports.sendChatMessageToPadClients = function(time, userId, text, padId) {
|
||||||
* @param client the client that send this message
|
* @param client the client that send this message
|
||||||
* @param message the message from the client
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
function handleGetChatMessages(client, message)
|
async function handleGetChatMessages(client, message)
|
||||||
{
|
{
|
||||||
if (message.data.start == null) {
|
if (message.data.start == null) {
|
||||||
messageLogger.warn("Dropped message, GetChatMessages Message has no start!");
|
messageLogger.warn("Dropped message, GetChatMessages Message has no start!");
|
||||||
|
@ -450,34 +408,20 @@ function handleGetChatMessages(client, message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = message.data.start;
|
let start = message.data.start;
|
||||||
var end = message.data.end;
|
let end = message.data.end;
|
||||||
var count = end - start;
|
let count = end - start;
|
||||||
|
|
||||||
if (count < 0 || count > 100) {
|
if (count < 0 || count > 100) {
|
||||||
messageLogger.warn("Dropped message, GetChatMessages Message, client requested invalid amount of messages!");
|
messageLogger.warn("Dropped message, GetChatMessages Message, client requested invalid amount of messages!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var padId = sessioninfos[client.id].padId;
|
let padId = sessioninfos[client.id].padId;
|
||||||
var pad;
|
let pad = await padManager.getPad(padId);
|
||||||
|
|
||||||
async.series([
|
let chatMessages = await pad.getChatMessages(start, end);
|
||||||
// get the pad
|
let infoMsg = {
|
||||||
function(callback) {
|
|
||||||
padManager.getPad(padId, function(err, _pad) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
pad = _pad;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
function(callback) {
|
|
||||||
pad.getChatMessages(start, end, function(err, chatMessages) {
|
|
||||||
if (ERR(err, callback)) return;
|
|
||||||
|
|
||||||
var infoMsg = {
|
|
||||||
type: "COLLABROOM",
|
type: "COLLABROOM",
|
||||||
data: {
|
data: {
|
||||||
type: "CHAT_MESSAGES",
|
type: "CHAT_MESSAGES",
|
||||||
|
@ -487,8 +431,6 @@ function handleGetChatMessages(client, message)
|
||||||
|
|
||||||
// send the messages back to the client
|
// send the messages back to the client
|
||||||
client.json.send(infoMsg);
|
client.json.send(infoMsg);
|
||||||
});
|
|
||||||
}]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -763,13 +705,13 @@ async function handleUserChanges(data)
|
||||||
stopWatch.end();
|
stopWatch.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.updatePadClients = thenify(function(pad, callback)
|
exports.updatePadClients = async function(pad)
|
||||||
{
|
{
|
||||||
// skip this if no-one is on this pad
|
// skip this if no-one is on this pad
|
||||||
var roomClients = _getRoomClients(pad.id);
|
let roomClients = _getRoomClients(pad.id);
|
||||||
|
|
||||||
if (roomClients.length == 0) {
|
if (roomClients.length == 0) {
|
||||||
return callback();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// since all clients usually get the same set of changesets, store them in local cache
|
// since all clients usually get the same set of changesets, store them in local cache
|
||||||
|
@ -778,45 +720,35 @@ exports.updatePadClients = thenify(function(pad, callback)
|
||||||
// BEFORE first result will be landed to our cache object. The solution is to replace parallel processing
|
// BEFORE first result will be landed to our cache object. The solution is to replace parallel processing
|
||||||
// via async.forEach with sequential for() loop. There is no real benefits of running this in parallel,
|
// via async.forEach with sequential for() loop. There is no real benefits of running this in parallel,
|
||||||
// but benefit of reusing cached revision object is HUGE
|
// but benefit of reusing cached revision object is HUGE
|
||||||
var revCache = {};
|
let revCache = {};
|
||||||
|
|
||||||
// go through all sessions on this pad
|
// go through all sessions on this pad
|
||||||
async.forEach(roomClients, function(client, callback){
|
for (let client of roomClients) {
|
||||||
var sid = client.id;
|
let sid = client.id;
|
||||||
// https://github.com/caolan/async#whilst
|
|
||||||
// send them all new changesets
|
// send them all new changesets
|
||||||
async.whilst(
|
while (sessioninfos[sid] && sessioninfos[sid].rev < pad.getHeadRevisionNumber()) {
|
||||||
function() { return sessioninfos[sid] && sessioninfos[sid].rev < pad.getHeadRevisionNumber()},
|
let r = sessioninfos[sid].rev + 1;
|
||||||
function(callback)
|
let revision = revCache[r];
|
||||||
{
|
if (!revision) {
|
||||||
var r = sessioninfos[sid].rev + 1;
|
revision = await pad.getRevision(r);
|
||||||
|
|
||||||
async.waterfall([
|
|
||||||
function(callback) {
|
|
||||||
if(revCache[r]) {
|
|
||||||
callback(null, revCache[r]);
|
|
||||||
} else {
|
|
||||||
pad.getRevision(r, callback);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
function(revision, callback) {
|
|
||||||
revCache[r] = revision;
|
revCache[r] = revision;
|
||||||
|
}
|
||||||
|
|
||||||
var author = revision.meta.author,
|
let author = revision.meta.author,
|
||||||
revChangeset = revision.changeset,
|
revChangeset = revision.changeset,
|
||||||
currentTime = revision.meta.timestamp;
|
currentTime = revision.meta.timestamp;
|
||||||
|
|
||||||
// next if session has not been deleted
|
// next if session has not been deleted
|
||||||
if (sessioninfos[sid] == null) {
|
if (sessioninfos[sid] == null) {
|
||||||
return callback(null);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (author == sessioninfos[sid].author) {
|
if (author == sessioninfos[sid].author) {
|
||||||
client.json.send({ "type": "COLLABROOM", "data":{ type: "ACCEPT_COMMIT", newRev: r }});
|
client.json.send({ "type": "COLLABROOM", "data":{ type: "ACCEPT_COMMIT", newRev: r }});
|
||||||
} else {
|
} else {
|
||||||
var forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
let forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
||||||
var wireMsg = {"type":"COLLABROOM",
|
let wireMsg = {"type": "COLLABROOM",
|
||||||
"data": { type:"NEW_CHANGES",
|
"data": { type:"NEW_CHANGES",
|
||||||
newRev:r,
|
newRev:r,
|
||||||
changeset: forWire.translated,
|
changeset: forWire.translated,
|
||||||
|
@ -833,14 +765,9 @@ exports.updatePadClients = thenify(function(pad, callback)
|
||||||
sessioninfos[sid].time = currentTime;
|
sessioninfos[sid].time = currentTime;
|
||||||
sessioninfos[sid].rev = r;
|
sessioninfos[sid].rev = r;
|
||||||
}
|
}
|
||||||
callback(null);
|
|
||||||
}
|
}
|
||||||
], callback);
|
}
|
||||||
},
|
}
|
||||||
callback
|
|
||||||
);
|
|
||||||
},callback);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copied from the Etherpad Source Code. Don't know what this method does excatly...
|
* Copied from the Etherpad Source Code. Don't know what this method does excatly...
|
||||||
|
@ -893,12 +820,12 @@ function _correctMarkersInPad(atext, apool) {
|
||||||
function handleSwitchToPad(client, message)
|
function handleSwitchToPad(client, message)
|
||||||
{
|
{
|
||||||
// clear the session and leave the room
|
// clear the session and leave the room
|
||||||
var currentSession = sessioninfos[client.id];
|
let currentSession = sessioninfos[client.id];
|
||||||
var padId = currentSession.padId;
|
let padId = currentSession.padId;
|
||||||
var roomClients = _getRoomClients(padId);
|
let roomClients = _getRoomClients(padId);
|
||||||
|
|
||||||
async.forEach(roomClients, function(client, callback) {
|
roomClients.forEach(client => {
|
||||||
var sinfo = sessioninfos[client.id];
|
let sinfo = sessioninfos[client.id];
|
||||||
if (sinfo && sinfo.author == currentSession.author) {
|
if (sinfo && sinfo.author == currentSession.author) {
|
||||||
// fix user's counter, works on page refresh or if user closes browser window and then rejoins
|
// fix user's counter, works on page refresh or if user closes browser window and then rejoins
|
||||||
sessioninfos[client.id] = {};
|
sessioninfos[client.id] = {};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue