mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 14:13:34 +01:00
PadMessageHandler: Rename client
to socket
The `client` variable is actually a socket.io Socket object. Rename it to reduce confusion.
This commit is contained in:
parent
cfc7e47db0
commit
91268e14b7
2 changed files with 137 additions and 159 deletions
|
@ -513,7 +513,8 @@ Called from: src/node/handler/PadMessageHandler.js
|
|||
Things in context:
|
||||
|
||||
1. message - the message being handled
|
||||
2. client - the socket.io Socket object
|
||||
2. socket - the socket.io Socket object
|
||||
3. client - **deprecated** synonym of socket
|
||||
|
||||
This hook allows plugins to drop or modify incoming socket.io messages from
|
||||
clients, before Etherpad processes them.
|
||||
|
@ -526,19 +527,19 @@ Examples:
|
|||
|
||||
```
|
||||
// Using an async function:
|
||||
exports.handleMessage = async (hookName, {message, client}) => {
|
||||
exports.handleMessage = async (hookName, {message, socket}) => {
|
||||
if (message.type === 'USERINFO_UPDATE') {
|
||||
// Force the display name to the name associated with the account.
|
||||
const user = client.client.request.session.user || {};
|
||||
const user = socket.client.request.session.user || {};
|
||||
if (user.name) message.data.userInfo.name = user.name;
|
||||
}
|
||||
};
|
||||
|
||||
// Using a regular function:
|
||||
exports.handleMessage = (hookName, {message, client}, callback) => {
|
||||
exports.handleMessage = (hookName, {message, socket}, callback) => {
|
||||
if (message.type === 'USERINFO_UPDATE') {
|
||||
// Force the display name to the name associated with the account.
|
||||
const user = client.client.request.session.user || {};
|
||||
const user = socket.client.request.session.user || {};
|
||||
if (user.name) message.data.userInfo.name = user.name;
|
||||
}
|
||||
return cb();
|
||||
|
@ -551,7 +552,8 @@ Called from: src/node/handler/PadMessageHandler.js
|
|||
Things in context:
|
||||
|
||||
1. message - the message being handled
|
||||
2. client - the socket.io Socket object
|
||||
2. socket - the socket.io Socket object
|
||||
3. client - **deprecated** synonym of socket
|
||||
|
||||
This hook allows plugins to grant temporary write access to a pad. It is called
|
||||
for each incoming message from a client. If write access is granted, it applies
|
||||
|
@ -568,14 +570,14 @@ Examples:
|
|||
|
||||
```
|
||||
// Using an async function:
|
||||
exports.handleMessageSecurity = async (hookName, {message, client}) => {
|
||||
if (shouldGrantWriteAccess(message, client)) return true;
|
||||
exports.handleMessageSecurity = async (hookName, {message, socket}) => {
|
||||
if (shouldGrantWriteAccess(message, socket)) return true;
|
||||
return;
|
||||
};
|
||||
|
||||
// Using a regular function:
|
||||
exports.handleMessageSecurity = (hookName, {message, client}, callback) => {
|
||||
if (shouldGrantWriteAccess(message, client)) return callback(true);
|
||||
exports.handleMessageSecurity = (hookName, {message, socket}, callback) => {
|
||||
if (shouldGrantWriteAccess(message, socket)) return callback(true);
|
||||
return callback();
|
||||
};
|
||||
```
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* global exports, process, require */
|
||||
|
||||
var padManager = require("../db/PadManager");
|
||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
||||
|
@ -66,8 +67,8 @@ stats.gauge('totalUsers', function() {
|
|||
/**
|
||||
* A changeset queue per pad that is processed by handleUserChanges()
|
||||
*/
|
||||
var padChannels = new channels.channels(function(data, callback) {
|
||||
return nodeify(handleUserChanges(data), callback);
|
||||
const padChannels = new channels.channels(({socket, message}, callback) => {
|
||||
return nodeify(handleUserChanges(socket, message), callback);
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -86,19 +87,17 @@ exports.setSocketIO = function(socket_io)
|
|||
|
||||
/**
|
||||
* Handles the connection of a new user
|
||||
* @param client the new client
|
||||
* @param socket the socket.io Socket object for the new connection from the client
|
||||
*/
|
||||
exports.handleConnect = function(client)
|
||||
{
|
||||
exports.handleConnect = (socket) => {
|
||||
stats.meter('connects').mark();
|
||||
|
||||
// Initalize sessioninfos for this new session
|
||||
sessioninfos[client.id]={};
|
||||
}
|
||||
sessioninfos[socket.id] = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Kicks all sessions from a pad
|
||||
* @param client the new client
|
||||
*/
|
||||
exports.kickSessionsFromPad = function(padID)
|
||||
{
|
||||
|
@ -106,7 +105,7 @@ exports.kickSessionsFromPad = function(padID)
|
|||
return;
|
||||
|
||||
// skip if there is nobody on this pad
|
||||
if(_getRoomClients(padID).length === 0)
|
||||
if(_getRoomSockets(padID).length === 0)
|
||||
return;
|
||||
|
||||
// disconnect everyone from this pad
|
||||
|
@ -115,22 +114,21 @@ exports.kickSessionsFromPad = function(padID)
|
|||
|
||||
/**
|
||||
* Handles the disconnection of a user
|
||||
* @param client the client that leaves
|
||||
* @param socket the socket.io Socket object for the client
|
||||
*/
|
||||
exports.handleDisconnect = async function(client)
|
||||
{
|
||||
exports.handleDisconnect = async (socket) => {
|
||||
stats.meter('disconnects').mark();
|
||||
|
||||
// save the padname of this session
|
||||
let session = sessioninfos[client.id];
|
||||
const session = sessioninfos[socket.id];
|
||||
|
||||
// if this connection was already etablished with a handshake, send a disconnect message to the others
|
||||
if (session && session.author) {
|
||||
const {session: {user} = {}} = client.client.request;
|
||||
const {session: {user} = {}} = socket.client.request;
|
||||
accessLogger.info('[LEAVE]' +
|
||||
` pad:${session.padId}` +
|
||||
` socket:${client.id}` +
|
||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : client.request.ip}` +
|
||||
` socket:${socket.id}` +
|
||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : socket.request.ip}` +
|
||||
` authorID:${session.author}` +
|
||||
((user && user.username) ? ` username:${user.username}` : ''));
|
||||
|
||||
|
@ -152,33 +150,32 @@ exports.handleDisconnect = async function(client)
|
|||
};
|
||||
|
||||
// Go through all user that are still on the pad, and send them the USER_LEAVE message
|
||||
client.broadcast.to(session.padId).json.send(messageToTheOtherUsers);
|
||||
socket.broadcast.to(session.padId).json.send(messageToTheOtherUsers);
|
||||
|
||||
// Allow plugins to hook into users leaving the pad
|
||||
hooks.callAll("userLeave", session);
|
||||
}
|
||||
|
||||
// Delete the sessioninfos entrys of this session
|
||||
delete sessioninfos[client.id];
|
||||
}
|
||||
delete sessioninfos[socket.id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a message from a user
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
exports.handleMessage = async function(client, message)
|
||||
{
|
||||
exports.handleMessage = async (socket, message) => {
|
||||
var env = process.env.NODE_ENV || 'development';
|
||||
|
||||
if (env === 'production') {
|
||||
try {
|
||||
await rateLimiter.consume(client.request.ip); // consume 1 point per event from IP
|
||||
await rateLimiter.consume(socket.request.ip); // consume 1 point per event from IP
|
||||
} catch (e) {
|
||||
console.warn(`Rate limited: ${client.request.ip} to reduce the amount of rate limiting ` +
|
||||
console.warn(`Rate limited: ${socket.request.ip} to reduce the amount of rate limiting ` +
|
||||
'that happens edit the rateLimit values in settings.json');
|
||||
stats.meter('rateLimited').mark();
|
||||
client.json.send({disconnect:"rateLimited"});
|
||||
socket.json.send({disconnect: 'rateLimited'});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +188,7 @@ exports.handleMessage = async function(client, message)
|
|||
return;
|
||||
}
|
||||
|
||||
const thisSession = sessioninfos[client.id];
|
||||
const thisSession = sessioninfos[socket.id];
|
||||
|
||||
if (!thisSession) {
|
||||
messageLogger.warn("Dropped message from an unknown connection.")
|
||||
|
@ -217,73 +214,74 @@ exports.handleMessage = async function(client, message)
|
|||
padId = await readOnlyManager.getPadId(padId);
|
||||
}
|
||||
|
||||
const {session: {user} = {}} = client.client.request;
|
||||
const {session: {user} = {}} = socket.client.request;
|
||||
const {accessStatus, authorID} =
|
||||
await securityManager.checkAccess(padId, auth.sessionID, auth.token, user);
|
||||
if (accessStatus !== 'grant') {
|
||||
// Access denied. Send the reason to the user.
|
||||
client.json.send({accessStatus});
|
||||
socket.json.send({accessStatus});
|
||||
return;
|
||||
}
|
||||
if (thisSession.author != null && thisSession.author !== authorID) {
|
||||
messageLogger.warn(
|
||||
'Rejecting message from client because the author ID changed mid-session.' +
|
||||
' Bad or missing token or sessionID?' +
|
||||
` socket:${client.id}` +
|
||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : client.request.ip}` +
|
||||
` socket:${socket.id}` +
|
||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : socket.request.ip}` +
|
||||
` originalAuthorID:${thisSession.author}` +
|
||||
` newAuthorID:${authorID}` +
|
||||
((user && user.username) ? ` username:${user.username}` : '') +
|
||||
` message:${message}`);
|
||||
client.json.send({disconnect: 'rejected'});
|
||||
socket.json.send({disconnect: 'rejected'});
|
||||
return;
|
||||
}
|
||||
thisSession.author = authorID;
|
||||
|
||||
// Allow plugins to bypass the readonly message blocker
|
||||
if ((await hooks.aCallAll('handleMessageSecurity', {client, message})).some((w) => w === true)) {
|
||||
const context = {message, socket, client: socket}; // `client` for backwards compatibility.
|
||||
if ((await hooks.aCallAll('handleMessageSecurity', context)).some((w) => w === true)) {
|
||||
thisSession.readonly = false;
|
||||
}
|
||||
|
||||
// Call handleMessage hook. If a plugin returns null, the message will be dropped.
|
||||
if ((await hooks.aCallAll('handleMessage', {client, message})).some((m) => m === null)) {
|
||||
if ((await hooks.aCallAll('handleMessage', context)).some((m) => m === null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop the message if the client disconnected during the above processing.
|
||||
if (sessioninfos[client.id] !== thisSession) {
|
||||
if (sessioninfos[socket.id] !== thisSession) {
|
||||
messageLogger.warn('Dropping message from a connection that has gone away.')
|
||||
return;
|
||||
}
|
||||
|
||||
// Check what type of message we get and delegate to the other methods
|
||||
if (message.type === "CLIENT_READY") {
|
||||
await handleClientReady(client, message, authorID);
|
||||
await handleClientReady(socket, message, authorID);
|
||||
} else if (message.type === "CHANGESET_REQ") {
|
||||
await handleChangesetRequest(client, message);
|
||||
await handleChangesetRequest(socket, message);
|
||||
} else if(message.type === "COLLABROOM") {
|
||||
if (thisSession.readonly) {
|
||||
messageLogger.warn("Dropped message, COLLABROOM for readonly pad");
|
||||
} else if (message.data.type === "USER_CHANGES") {
|
||||
stats.counter('pendingEdits').inc()
|
||||
padChannels.emit(message.padId, {client: client, message: message}); // add to pad queue
|
||||
padChannels.emit(message.padId, {socket, message}); // add to pad queue
|
||||
} else if (message.data.type === "USERINFO_UPDATE") {
|
||||
await handleUserInfoUpdate(client, message);
|
||||
await handleUserInfoUpdate(socket, message);
|
||||
} else if (message.data.type === "CHAT_MESSAGE") {
|
||||
await handleChatMessage(client, message);
|
||||
await handleChatMessage(socket, message);
|
||||
} else if (message.data.type === "GET_CHAT_MESSAGES") {
|
||||
await handleGetChatMessages(client, message);
|
||||
await handleGetChatMessages(socket, message);
|
||||
} else if (message.data.type === "SAVE_REVISION") {
|
||||
await handleSaveRevisionMessage(client, message);
|
||||
await handleSaveRevisionMessage(socket, message);
|
||||
} else if (message.data.type === "CLIENT_MESSAGE" &&
|
||||
message.data.payload != null &&
|
||||
message.data.payload.type === "suggestUserName") {
|
||||
handleSuggestUserName(client, message);
|
||||
handleSuggestUserName(socket, message);
|
||||
} else {
|
||||
messageLogger.warn("Dropped message, unknown COLLABROOM Data Type " + message.data.type);
|
||||
}
|
||||
} else if(message.type === "SWITCH_TO_PAD") {
|
||||
await handleSwitchToPad(client, message, authorID);
|
||||
await handleSwitchToPad(socket, message, authorID);
|
||||
} else {
|
||||
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
||||
}
|
||||
|
@ -292,16 +290,13 @@ exports.handleMessage = async function(client, message)
|
|||
|
||||
/**
|
||||
* Handles a save revision message
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
async function handleSaveRevisionMessage(client, message)
|
||||
{
|
||||
var padId = sessioninfos[client.id].padId;
|
||||
var userId = sessioninfos[client.id].author;
|
||||
|
||||
let pad = await padManager.getPad(padId);
|
||||
await pad.addSavedRevision(pad.head, userId);
|
||||
async function handleSaveRevisionMessage(socket, message) {
|
||||
const {padId, author: authorId} = sessioninfos[socket.id];
|
||||
const pad = await padManager.getPad(padId);
|
||||
await pad.addSavedRevision(pad.head, authorId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,17 +338,14 @@ exports.handleCustomMessage = function(padID, msgString) {
|
|||
|
||||
/**
|
||||
* Handles a Chat Message
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
async function handleChatMessage(client, message)
|
||||
{
|
||||
async function handleChatMessage(socket, message) {
|
||||
var time = Date.now();
|
||||
var userId = sessioninfos[client.id].author;
|
||||
var text = message.data.text;
|
||||
var padId = sessioninfos[client.id].padId;
|
||||
|
||||
await exports.sendChatMessageToPadClients(time, userId, text, padId);
|
||||
const {padId, author: authorId} = sessioninfos[socket.id];
|
||||
await exports.sendChatMessageToPadClients(time, authorId, text, padId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -387,11 +379,10 @@ exports.sendChatMessageToPadClients = async function(time, userId, text, padId)
|
|||
|
||||
/**
|
||||
* Handles the clients request for more chat-messages
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
async function handleGetChatMessages(client, message)
|
||||
{
|
||||
async function handleGetChatMessages(socket, message) {
|
||||
if (message.data.start == null) {
|
||||
messageLogger.warn("Dropped message, GetChatMessages Message has no start!");
|
||||
return;
|
||||
|
@ -411,7 +402,7 @@ async function handleGetChatMessages(client, message)
|
|||
return;
|
||||
}
|
||||
|
||||
let padId = sessioninfos[client.id].padId;
|
||||
const padId = sessioninfos[socket.id].padId;
|
||||
let pad = await padManager.getPad(padId);
|
||||
|
||||
let chatMessages = await pad.getChatMessages(start, end);
|
||||
|
@ -424,16 +415,15 @@ async function handleGetChatMessages(client, message)
|
|||
};
|
||||
|
||||
// send the messages back to the client
|
||||
client.json.send(infoMsg);
|
||||
socket.json.send(infoMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a handleSuggestUserName, that means a user have suggest a userName for a other user
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
function handleSuggestUserName(client, message)
|
||||
{
|
||||
function handleSuggestUserName(socket, message) {
|
||||
// check if all ok
|
||||
if (message.data.payload.newName == null) {
|
||||
messageLogger.warn("Dropped message, suggestUserName Message has no newName!");
|
||||
|
@ -445,25 +435,23 @@ function handleSuggestUserName(client, message)
|
|||
return;
|
||||
}
|
||||
|
||||
var padId = sessioninfos[client.id].padId;
|
||||
var roomClients = _getRoomClients(padId);
|
||||
const padId = sessioninfos[socket.id].padId;
|
||||
|
||||
// search the author and send him this message
|
||||
roomClients.forEach(function(client) {
|
||||
var session = sessioninfos[client.id];
|
||||
_getRoomSockets(padId).forEach((socket) => {
|
||||
const session = sessioninfos[socket.id];
|
||||
if (session && session.author === message.data.payload.unnamedId) {
|
||||
client.json.send(message);
|
||||
socket.json.send(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a USERINFO_UPDATE, that means that a user have changed his color or name. Anyway, we get both informations
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
async function handleUserInfoUpdate(client, message)
|
||||
{
|
||||
async function handleUserInfoUpdate(socket, message) {
|
||||
// check if all ok
|
||||
if (message.data.userInfo == null) {
|
||||
messageLogger.warn("Dropped message, USERINFO_UPDATE Message has no userInfo!");
|
||||
|
@ -476,7 +464,7 @@ async function handleUserInfoUpdate(client, message)
|
|||
}
|
||||
|
||||
// Check that we have a valid session and author to update.
|
||||
var session = sessioninfos[client.id];
|
||||
const session = sessioninfos[socket.id];
|
||||
if (!session || !session.author || !session.padId) {
|
||||
messageLogger.warn("Dropped message, USERINFO_UPDATE Session not ready." + message.data);
|
||||
return;
|
||||
|
@ -517,7 +505,7 @@ async function handleUserInfoUpdate(client, message)
|
|||
};
|
||||
|
||||
// Send the other clients on the pad the update message
|
||||
client.broadcast.to(padId).json.send(infoMsg);
|
||||
socket.broadcast.to(padId).json.send(infoMsg);
|
||||
|
||||
// Block until the authorManager has stored the new attributes.
|
||||
await p;
|
||||
|
@ -534,14 +522,10 @@ async function handleUserInfoUpdate(client, message)
|
|||
* This function is based on a similar one in the original Etherpad.
|
||||
* See https://github.com/ether/pad/blob/master/etherpad/src/etherpad/collab/collab_server.js in the function applyUserChanges()
|
||||
*
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
async function handleUserChanges(data)
|
||||
{
|
||||
var client = data.client
|
||||
, message = data.message
|
||||
|
||||
async function handleUserChanges(socket, message) {
|
||||
// This one's no longer pending, as we're gonna process it now
|
||||
stats.counter('pendingEdits').dec()
|
||||
|
||||
|
@ -563,7 +547,7 @@ async function handleUserChanges(data)
|
|||
|
||||
// The client might disconnect between our callbacks. We should still
|
||||
// finish processing the changeset, so keep a reference to the session.
|
||||
const thisSession = sessioninfos[client.id];
|
||||
const thisSession = sessioninfos[socket.id];
|
||||
|
||||
// TODO: this might happen with other messages too => find one place to copy the session
|
||||
// and always use the copy. atm a message will be ignored if the session is gone even
|
||||
|
@ -629,9 +613,9 @@ async function handleUserChanges(data)
|
|||
|
||||
} catch(e) {
|
||||
// There is an error in this changeset, so just refuse it
|
||||
client.json.send({ disconnect: "badChangeset" });
|
||||
socket.json.send({disconnect: 'badChangeset'});
|
||||
stats.meter('failedChangesets').mark();
|
||||
throw new Error(`Can't apply USER_CHANGES from Socket ${client.id} because: ${e.message}`);
|
||||
throw new Error(`Can't apply USER_CHANGES from Socket ${socket.id} because: ${e.message}`);
|
||||
}
|
||||
|
||||
// ex. applyUserChanges
|
||||
|
@ -656,14 +640,14 @@ async function handleUserChanges(data)
|
|||
// prevent eplite from accepting it TODO: better send the client a NEW_CHANGES
|
||||
// of that revision
|
||||
if (baseRev + 1 === r && c === changeset) {
|
||||
client.json.send({disconnect:"badChangeset"});
|
||||
socket.json.send({disconnect: 'badChangeset'});
|
||||
stats.meter('failedChangesets').mark();
|
||||
throw new Error("Won't apply USER_CHANGES, because it contains an already accepted changeset");
|
||||
}
|
||||
|
||||
changeset = Changeset.follow(c, changeset, false, apool);
|
||||
} catch(e) {
|
||||
client.json.send({disconnect:"badChangeset"});
|
||||
socket.json.send({disconnect: 'badChangeset'});
|
||||
stats.meter('failedChangesets').mark();
|
||||
throw new Error("Can't apply USER_CHANGES, because " + e.message);
|
||||
}
|
||||
|
@ -672,7 +656,7 @@ async function handleUserChanges(data)
|
|||
let prevText = pad.text();
|
||||
|
||||
if (Changeset.oldLen(changeset) !== prevText.length) {
|
||||
client.json.send({disconnect:"badChangeset"});
|
||||
socket.json.send({disconnect: 'badChangeset'});
|
||||
stats.meter('failedChangesets').mark();
|
||||
throw new Error("Can't apply USER_CHANGES "+changeset+" with oldLen " + Changeset.oldLen(changeset) + " to document of length " + prevText.length);
|
||||
}
|
||||
|
@ -680,7 +664,7 @@ async function handleUserChanges(data)
|
|||
try {
|
||||
await pad.appendRevision(changeset, thisSession.author);
|
||||
} catch(e) {
|
||||
client.json.send({ disconnect: "badChangeset" });
|
||||
socket.json.send({disconnect: 'badChangeset'});
|
||||
stats.meter('failedChangesets').mark();
|
||||
throw e;
|
||||
}
|
||||
|
@ -707,11 +691,8 @@ async function handleUserChanges(data)
|
|||
exports.updatePadClients = async function(pad)
|
||||
{
|
||||
// skip this if no-one is on this pad
|
||||
let roomClients = _getRoomClients(pad.id);
|
||||
|
||||
if (roomClients.length === 0) {
|
||||
return;
|
||||
}
|
||||
const roomSockets = _getRoomSockets(pad.id);
|
||||
if (roomSockets.length === 0) return;
|
||||
|
||||
// since all clients usually get the same set of changesets, store them in local cache
|
||||
// to remove unnecessary roundtrip to the datalayer
|
||||
|
@ -723,8 +704,8 @@ exports.updatePadClients = async function(pad)
|
|||
let revCache = {};
|
||||
|
||||
// go through all sessions on this pad
|
||||
for (let client of roomClients) {
|
||||
let sid = client.id;
|
||||
for (const socket of roomSockets) {
|
||||
const sid = socket.id;
|
||||
|
||||
// send them all new changesets
|
||||
while (sessioninfos[sid] && sessioninfos[sid].rev < pad.getHeadRevisionNumber()) {
|
||||
|
@ -745,7 +726,7 @@ exports.updatePadClients = async function(pad)
|
|||
}
|
||||
|
||||
if (author === sessioninfos[sid].author) {
|
||||
client.json.send({ "type": "COLLABROOM", "data":{ type: "ACCEPT_COMMIT", newRev: r }});
|
||||
socket.json.send({type: 'COLLABROOM', data: {type: 'ACCEPT_COMMIT', newRev: r}});
|
||||
} else {
|
||||
let forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
||||
let wireMsg = {"type": "COLLABROOM",
|
||||
|
@ -758,7 +739,7 @@ exports.updatePadClients = async function(pad)
|
|||
timeDelta: currentTime - sessioninfos[sid].time
|
||||
}};
|
||||
|
||||
client.json.send(wireMsg);
|
||||
socket.json.send(wireMsg);
|
||||
}
|
||||
|
||||
if (sessioninfos[sid]) {
|
||||
|
@ -817,19 +798,18 @@ function _correctMarkersInPad(atext, apool) {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
async function handleSwitchToPad(client, message, _authorID)
|
||||
{
|
||||
const currentSessionInfo = sessioninfos[client.id];
|
||||
async function handleSwitchToPad(socket, message, _authorID) {
|
||||
const currentSessionInfo = sessioninfos[socket.id];
|
||||
const padId = currentSessionInfo.padId;
|
||||
|
||||
// Check permissions for the new pad.
|
||||
const newPadIds = await readOnlyManager.getIds(message.padId);
|
||||
const {session: {user} = {}} = client.client.request;
|
||||
const {session: {user} = {}} = socket.client.request;
|
||||
const {accessStatus, authorID} = await securityManager.checkAccess(
|
||||
newPadIds.padId, message.sessionID, message.token, user);
|
||||
if (accessStatus !== 'grant') {
|
||||
// Access denied. Send the reason to the user.
|
||||
client.json.send({accessStatus});
|
||||
socket.json.send({accessStatus});
|
||||
return;
|
||||
}
|
||||
// The same token and session ID were passed to checkAccess in handleMessage, so this second call
|
||||
|
@ -838,22 +818,22 @@ async function handleSwitchToPad(client, message, _authorID)
|
|||
assert(authorID === currentSessionInfo.author);
|
||||
|
||||
// Check if the connection dropped during the access check.
|
||||
if (sessioninfos[client.id] !== currentSessionInfo) return;
|
||||
if (sessioninfos[socket.id] !== currentSessionInfo) return;
|
||||
|
||||
// clear the session and leave the room
|
||||
_getRoomClients(padId).forEach(client => {
|
||||
let sinfo = sessioninfos[client.id];
|
||||
_getRoomSockets(padId).forEach((socket) => {
|
||||
const sinfo = sessioninfos[socket.id];
|
||||
if (sinfo && sinfo.author === currentSessionInfo.author) {
|
||||
// fix user's counter, works on page refresh or if user closes browser window and then rejoins
|
||||
sessioninfos[client.id] = {};
|
||||
client.leave(padId);
|
||||
sessioninfos[socket.id] = {};
|
||||
socket.leave(padId);
|
||||
}
|
||||
});
|
||||
|
||||
// start up the new pad
|
||||
const newSessionInfo = sessioninfos[client.id];
|
||||
const newSessionInfo = sessioninfos[socket.id];
|
||||
createSessionInfoAuth(newSessionInfo, message);
|
||||
await handleClientReady(client, message, authorID);
|
||||
await handleClientReady(socket, message, authorID);
|
||||
}
|
||||
|
||||
// Creates/replaces the auth object in the given session info.
|
||||
|
@ -874,11 +854,10 @@ function createSessionInfoAuth(sessionInfo, message)
|
|||
/**
|
||||
* Handles a CLIENT_READY. A CLIENT_READY is the first message from the client to the server. The Client sends his token
|
||||
* and the pad it wants to enter. The Server answers with the inital values (clientVars) of the pad
|
||||
* @param client the client that send this message
|
||||
* @param socket the socket.io Socket object for the client
|
||||
* @param message the message from the client
|
||||
*/
|
||||
async function handleClientReady(client, message, authorID)
|
||||
{
|
||||
async function handleClientReady(socket, message, authorID) {
|
||||
// check if all ok
|
||||
if (!message.token) {
|
||||
messageLogger.warn("Dropped message, CLIENT_READY Message has no token!");
|
||||
|
@ -935,19 +914,19 @@ async function handleClientReady(client, message, authorID)
|
|||
// glue the clientVars together, send them and tell the other clients that a new one is there
|
||||
|
||||
// Check that the client is still here. It might have disconnected between callbacks.
|
||||
const sessionInfo = sessioninfos[client.id];
|
||||
const sessionInfo = sessioninfos[socket.id];
|
||||
if (sessionInfo == null) return;
|
||||
|
||||
// Check if this author is already on the pad, if yes, kick the other sessions!
|
||||
let roomClients = _getRoomClients(pad.id);
|
||||
const roomSockets = _getRoomSockets(pad.id);
|
||||
|
||||
for (let client of roomClients) {
|
||||
let sinfo = sessioninfos[client.id];
|
||||
for (const socket of roomSockets) {
|
||||
const sinfo = sessioninfos[socket.id];
|
||||
if (sinfo && sinfo.author === authorID) {
|
||||
// fix user's counter, works on page refresh or if user closes browser window and then rejoins
|
||||
sessioninfos[client.id] = {};
|
||||
client.leave(padIds.padId);
|
||||
client.json.send({disconnect:"userdup"});
|
||||
sessioninfos[socket.id] = {};
|
||||
socket.leave(padIds.padId);
|
||||
socket.json.send({disconnect: 'userdup'});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -955,20 +934,20 @@ async function handleClientReady(client, message, authorID)
|
|||
sessionInfo.padId = padIds.padId;
|
||||
sessionInfo.readOnlyPadId = padIds.readOnlyPadId;
|
||||
sessionInfo.readonly =
|
||||
padIds.readonly || !webaccess.userCanModify(message.padId, client.client.request);
|
||||
padIds.readonly || !webaccess.userCanModify(message.padId, socket.client.request);
|
||||
|
||||
const {session: {user} = {}} = client.client.request;
|
||||
const {session: {user} = {}} = socket.client.request;
|
||||
accessLogger.info(`[${pad.head > 0 ? 'ENTER' : 'CREATE'}]` +
|
||||
` pad:${padIds.padId}` +
|
||||
` socket:${client.id}` +
|
||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : client.request.ip}` +
|
||||
` socket:${socket.id}` +
|
||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : socket.request.ip}` +
|
||||
` authorID:${authorID}` +
|
||||
((user && user.username) ? ` username:${user.username}` : ''));
|
||||
|
||||
if (message.reconnect) {
|
||||
// If this is a reconnect, we don't have to send the client the ClientVars again
|
||||
// Join the pad and start receiving updates
|
||||
client.join(padIds.padId);
|
||||
socket.join(padIds.padId);
|
||||
|
||||
// Save the revision in sessioninfos, we take the revision from the info the client send to us
|
||||
sessionInfo.rev = message.client_rev;
|
||||
|
@ -1019,7 +998,7 @@ async function handleClientReady(client, message, authorID)
|
|||
author: changesets[r]['author'],
|
||||
currentTime: changesets[r]['timestamp']
|
||||
}};
|
||||
client.json.send(wireMsg);
|
||||
socket.json.send(wireMsg);
|
||||
}
|
||||
|
||||
if (startNum === endNum) {
|
||||
|
@ -1028,7 +1007,7 @@ async function handleClientReady(client, message, authorID)
|
|||
noChanges: true,
|
||||
newRev: pad.getHeadRevisionNumber()
|
||||
}};
|
||||
client.json.send(Msg);
|
||||
socket.json.send(Msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1042,7 +1021,7 @@ async function handleClientReady(client, message, authorID)
|
|||
atext.attribs = attribsForWire.translated;
|
||||
} catch(e) {
|
||||
console.error(e.stack || e)
|
||||
client.json.send({ disconnect:"corruptPad" }); // pull the brakes
|
||||
socket.json.send({disconnect: 'corruptPad'}); // pull the brakes
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1084,7 +1063,7 @@ async function handleClientReady(client, message, authorID)
|
|||
// 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,
|
||||
"numConnectedUsers": roomSockets.length,
|
||||
"readOnlyId": padIds.readOnlyPadId,
|
||||
"readonly": sessionInfo.readonly,
|
||||
"serverTimestamp": Date.now(),
|
||||
|
@ -1115,7 +1094,7 @@ async function handleClientReady(client, message, authorID)
|
|||
}
|
||||
|
||||
// call the clientVars-hook so plugins can modify them before they get sent to the client
|
||||
let messages = await hooks.aCallAll('clientVars', {clientVars, pad, socket: client});
|
||||
const messages = await hooks.aCallAll('clientVars', {clientVars, pad, socket});
|
||||
|
||||
// combine our old object with the new attributes from the hook
|
||||
for (let msg of messages) {
|
||||
|
@ -1123,10 +1102,10 @@ async function handleClientReady(client, message, authorID)
|
|||
}
|
||||
|
||||
// Join the pad and start receiving updates
|
||||
client.join(padIds.padId);
|
||||
socket.join(padIds.padId);
|
||||
|
||||
// Send the clientVars to the Client
|
||||
client.json.send({type: "CLIENT_VARS", data: clientVars});
|
||||
socket.json.send({type: 'CLIENT_VARS', data: clientVars});
|
||||
|
||||
// Save the current revision in sessioninfos, should be the same as in clientVars
|
||||
sessionInfo.rev = pad.getHeadRevisionNumber();
|
||||
|
@ -1151,20 +1130,19 @@ async function handleClientReady(client, message, authorID)
|
|||
}
|
||||
|
||||
// notify all existing users about new user
|
||||
client.broadcast.to(padIds.padId).json.send(messageToTheOtherUsers);
|
||||
socket.broadcast.to(padIds.padId).json.send(messageToTheOtherUsers);
|
||||
|
||||
// Get sessions for this pad and update them (in parallel)
|
||||
roomClients = _getRoomClients(pad.id);
|
||||
await Promise.all(_getRoomClients(pad.id).map(async roomClient => {
|
||||
await Promise.all(_getRoomSockets(pad.id).map(async (roomSocket) => {
|
||||
|
||||
// Jump over, if this session is the connection session
|
||||
if (roomClient.id === client.id) {
|
||||
if (roomSocket.id === socket.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since sessioninfos might change while being enumerated, check if the
|
||||
// sessionID is still assigned to a valid session
|
||||
const sessionInfo = sessioninfos[roomClient.id];
|
||||
const sessionInfo = sessioninfos[roomSocket.id];
|
||||
if (sessionInfo == null) return;
|
||||
|
||||
// get the authorname & colorId
|
||||
|
@ -1211,7 +1189,7 @@ async function handleClientReady(client, message, authorID)
|
|||
}
|
||||
};
|
||||
|
||||
client.json.send(msg);
|
||||
socket.json.send(msg);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -1219,8 +1197,7 @@ async function handleClientReady(client, message, authorID)
|
|||
/**
|
||||
* Handles a request for a rough changeset, the timeslider client needs it
|
||||
*/
|
||||
async function handleChangesetRequest(client, message)
|
||||
{
|
||||
async function handleChangesetRequest(socket, message) {
|
||||
// check if all ok
|
||||
if (message.data == null) {
|
||||
messageLogger.warn("Dropped message, changeset request has no data!");
|
||||
|
@ -1263,7 +1240,7 @@ async function handleChangesetRequest(client, message)
|
|||
try {
|
||||
let data = await getChangesetInfo(padIds.padId, start, end, granularity);
|
||||
data.requestID = message.data.requestID;
|
||||
client.json.send({ type: "CHANGESET_REQ", data });
|
||||
socket.json.send({type: 'CHANGESET_REQ', data});
|
||||
} catch (err) {
|
||||
console.error('Error while handling a changeset request for ' + padIds.padId, err.toString(), message.data);
|
||||
}
|
||||
|
@ -1431,17 +1408,17 @@ async function composePadChangesets (padId, startNum, endNum)
|
|||
}
|
||||
}
|
||||
|
||||
function _getRoomClients(padID) {
|
||||
var roomClients = [];
|
||||
function _getRoomSockets(padID) {
|
||||
const roomSockets = [];
|
||||
var room = socketio.sockets.adapter.rooms[padID];
|
||||
|
||||
if (room) {
|
||||
for (var id in room.sockets) {
|
||||
roomClients.push(socketio.sockets.sockets[id]);
|
||||
roomSockets.push(socketio.sockets.sockets[id]);
|
||||
}
|
||||
}
|
||||
|
||||
return roomClients;
|
||||
return roomSockets;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1449,7 +1426,7 @@ function _getRoomClients(padID) {
|
|||
*/
|
||||
exports.padUsersCount = function(padID) {
|
||||
return {
|
||||
padUsersCount: _getRoomClients(padID).length
|
||||
padUsersCount: _getRoomSockets(padID).length
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1459,11 +1436,10 @@ exports.padUsersCount = function(padID) {
|
|||
exports.padUsers = async function(padID) {
|
||||
|
||||
let padUsers = [];
|
||||
let roomClients = _getRoomClients(padID);
|
||||
|
||||
// iterate over all clients (in parallel)
|
||||
await Promise.all(roomClients.map(async roomClient => {
|
||||
let s = sessioninfos[roomClient.id];
|
||||
await Promise.all(_getRoomSockets(padID).map(async (roomSocket) => {
|
||||
const s = sessioninfos[roomSocket.id];
|
||||
if (s) {
|
||||
return authorManager.getAuthor(s.author).then(author => {
|
||||
// Fixes: https://github.com/ether/etherpad-lite/issues/4120
|
||||
|
|
Loading…
Reference in a new issue