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:
|
Things in context:
|
||||||
|
|
||||||
1. message - the message being handled
|
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
|
This hook allows plugins to drop or modify incoming socket.io messages from
|
||||||
clients, before Etherpad processes them.
|
clients, before Etherpad processes them.
|
||||||
|
@ -526,19 +527,19 @@ Examples:
|
||||||
|
|
||||||
```
|
```
|
||||||
// Using an async function:
|
// Using an async function:
|
||||||
exports.handleMessage = async (hookName, {message, client}) => {
|
exports.handleMessage = async (hookName, {message, socket}) => {
|
||||||
if (message.type === 'USERINFO_UPDATE') {
|
if (message.type === 'USERINFO_UPDATE') {
|
||||||
// Force the display name to the name associated with the account.
|
// 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;
|
if (user.name) message.data.userInfo.name = user.name;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Using a regular function:
|
// Using a regular function:
|
||||||
exports.handleMessage = (hookName, {message, client}, callback) => {
|
exports.handleMessage = (hookName, {message, socket}, callback) => {
|
||||||
if (message.type === 'USERINFO_UPDATE') {
|
if (message.type === 'USERINFO_UPDATE') {
|
||||||
// Force the display name to the name associated with the account.
|
// 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;
|
if (user.name) message.data.userInfo.name = user.name;
|
||||||
}
|
}
|
||||||
return cb();
|
return cb();
|
||||||
|
@ -551,7 +552,8 @@ Called from: src/node/handler/PadMessageHandler.js
|
||||||
Things in context:
|
Things in context:
|
||||||
|
|
||||||
1. message - the message being handled
|
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
|
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
|
for each incoming message from a client. If write access is granted, it applies
|
||||||
|
@ -568,14 +570,14 @@ Examples:
|
||||||
|
|
||||||
```
|
```
|
||||||
// Using an async function:
|
// Using an async function:
|
||||||
exports.handleMessageSecurity = async (hookName, {message, client}) => {
|
exports.handleMessageSecurity = async (hookName, {message, socket}) => {
|
||||||
if (shouldGrantWriteAccess(message, client)) return true;
|
if (shouldGrantWriteAccess(message, socket)) return true;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Using a regular function:
|
// Using a regular function:
|
||||||
exports.handleMessageSecurity = (hookName, {message, client}, callback) => {
|
exports.handleMessageSecurity = (hookName, {message, socket}, callback) => {
|
||||||
if (shouldGrantWriteAccess(message, client)) return callback(true);
|
if (shouldGrantWriteAccess(message, socket)) return callback(true);
|
||||||
return callback();
|
return callback();
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* global exports, process, require */
|
||||||
|
|
||||||
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");
|
||||||
|
@ -66,8 +67,8 @@ 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(function(data, callback) {
|
const padChannels = new channels.channels(({socket, message}, callback) => {
|
||||||
return nodeify(handleUserChanges(data), callback);
|
return nodeify(handleUserChanges(socket, message), callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,19 +87,17 @@ exports.setSocketIO = function(socket_io)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the connection of a new user
|
* 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();
|
stats.meter('connects').mark();
|
||||||
|
|
||||||
// Initalize sessioninfos for this new session
|
// Initalize sessioninfos for this new session
|
||||||
sessioninfos[client.id]={};
|
sessioninfos[socket.id] = {};
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kicks all sessions from a pad
|
* Kicks all sessions from a pad
|
||||||
* @param client the new client
|
|
||||||
*/
|
*/
|
||||||
exports.kickSessionsFromPad = function(padID)
|
exports.kickSessionsFromPad = function(padID)
|
||||||
{
|
{
|
||||||
|
@ -106,7 +105,7 @@ exports.kickSessionsFromPad = function(padID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// skip if there is nobody on this pad
|
// skip if there is nobody on this pad
|
||||||
if(_getRoomClients(padID).length === 0)
|
if(_getRoomSockets(padID).length === 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// disconnect everyone from this pad
|
// disconnect everyone from this pad
|
||||||
|
@ -115,22 +114,21 @@ exports.kickSessionsFromPad = function(padID)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the disconnection of a user
|
* 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();
|
stats.meter('disconnects').mark();
|
||||||
|
|
||||||
// save the padname of this session
|
// 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 this connection was already etablished with a handshake, send a disconnect message to the others
|
||||||
if (session && session.author) {
|
if (session && session.author) {
|
||||||
const {session: {user} = {}} = client.client.request;
|
const {session: {user} = {}} = socket.client.request;
|
||||||
accessLogger.info('[LEAVE]' +
|
accessLogger.info('[LEAVE]' +
|
||||||
` pad:${session.padId}` +
|
` pad:${session.padId}` +
|
||||||
` socket:${client.id}` +
|
` socket:${socket.id}` +
|
||||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : client.request.ip}` +
|
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : socket.request.ip}` +
|
||||||
` authorID:${session.author}` +
|
` authorID:${session.author}` +
|
||||||
((user && user.username) ? ` username:${user.username}` : ''));
|
((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
|
// 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
|
// 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
|
||||||
delete sessioninfos[client.id];
|
delete sessioninfos[socket.id];
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a message from a user
|
* 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
|
* @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';
|
var env = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
if (env === 'production') {
|
if (env === 'production') {
|
||||||
try {
|
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) {
|
} 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');
|
'that happens edit the rateLimit values in settings.json');
|
||||||
stats.meter('rateLimited').mark();
|
stats.meter('rateLimited').mark();
|
||||||
client.json.send({disconnect:"rateLimited"});
|
socket.json.send({disconnect: 'rateLimited'});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +188,7 @@ exports.handleMessage = async function(client, message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const thisSession = sessioninfos[client.id];
|
const thisSession = sessioninfos[socket.id];
|
||||||
|
|
||||||
if (!thisSession) {
|
if (!thisSession) {
|
||||||
messageLogger.warn("Dropped message from an unknown connection.")
|
messageLogger.warn("Dropped message from an unknown connection.")
|
||||||
|
@ -217,73 +214,74 @@ exports.handleMessage = async function(client, message)
|
||||||
padId = await readOnlyManager.getPadId(padId);
|
padId = await readOnlyManager.getPadId(padId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {session: {user} = {}} = client.client.request;
|
const {session: {user} = {}} = socket.client.request;
|
||||||
const {accessStatus, authorID} =
|
const {accessStatus, authorID} =
|
||||||
await securityManager.checkAccess(padId, auth.sessionID, auth.token, user);
|
await securityManager.checkAccess(padId, auth.sessionID, auth.token, user);
|
||||||
if (accessStatus !== 'grant') {
|
if (accessStatus !== 'grant') {
|
||||||
// Access denied. Send the reason to the user.
|
// Access denied. Send the reason to the user.
|
||||||
client.json.send({accessStatus});
|
socket.json.send({accessStatus});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (thisSession.author != null && thisSession.author !== authorID) {
|
if (thisSession.author != null && thisSession.author !== authorID) {
|
||||||
messageLogger.warn(
|
messageLogger.warn(
|
||||||
'Rejecting message from client because the author ID changed mid-session.' +
|
'Rejecting message from client because the author ID changed mid-session.' +
|
||||||
' Bad or missing token or sessionID?' +
|
' Bad or missing token or sessionID?' +
|
||||||
` socket:${client.id}` +
|
` socket:${socket.id}` +
|
||||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : client.request.ip}` +
|
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : socket.request.ip}` +
|
||||||
` originalAuthorID:${thisSession.author}` +
|
` originalAuthorID:${thisSession.author}` +
|
||||||
` newAuthorID:${authorID}` +
|
` newAuthorID:${authorID}` +
|
||||||
((user && user.username) ? ` username:${user.username}` : '') +
|
((user && user.username) ? ` username:${user.username}` : '') +
|
||||||
` message:${message}`);
|
` message:${message}`);
|
||||||
client.json.send({disconnect: 'rejected'});
|
socket.json.send({disconnect: 'rejected'});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
thisSession.author = authorID;
|
thisSession.author = authorID;
|
||||||
|
|
||||||
// Allow plugins to bypass the readonly message blocker
|
// 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;
|
thisSession.readonly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call handleMessage hook. If a plugin returns null, the message will be dropped.
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop the message if the client disconnected during the above processing.
|
// 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.')
|
messageLogger.warn('Dropping message from a connection that has gone away.')
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check what type of message we get and delegate to the other methods
|
// Check what type of message we get and delegate to the other methods
|
||||||
if (message.type === "CLIENT_READY") {
|
if (message.type === "CLIENT_READY") {
|
||||||
await handleClientReady(client, message, authorID);
|
await handleClientReady(socket, message, authorID);
|
||||||
} else if (message.type === "CHANGESET_REQ") {
|
} else if (message.type === "CHANGESET_REQ") {
|
||||||
await handleChangesetRequest(client, message);
|
await handleChangesetRequest(socket, message);
|
||||||
} else if(message.type === "COLLABROOM") {
|
} else if(message.type === "COLLABROOM") {
|
||||||
if (thisSession.readonly) {
|
if (thisSession.readonly) {
|
||||||
messageLogger.warn("Dropped message, COLLABROOM for readonly pad");
|
messageLogger.warn("Dropped message, COLLABROOM for readonly pad");
|
||||||
} else if (message.data.type === "USER_CHANGES") {
|
} else if (message.data.type === "USER_CHANGES") {
|
||||||
stats.counter('pendingEdits').inc()
|
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") {
|
} else if (message.data.type === "USERINFO_UPDATE") {
|
||||||
await handleUserInfoUpdate(client, message);
|
await handleUserInfoUpdate(socket, message);
|
||||||
} else if (message.data.type === "CHAT_MESSAGE") {
|
} else if (message.data.type === "CHAT_MESSAGE") {
|
||||||
await handleChatMessage(client, message);
|
await handleChatMessage(socket, message);
|
||||||
} else if (message.data.type === "GET_CHAT_MESSAGES") {
|
} else if (message.data.type === "GET_CHAT_MESSAGES") {
|
||||||
await handleGetChatMessages(client, message);
|
await handleGetChatMessages(socket, message);
|
||||||
} else if (message.data.type === "SAVE_REVISION") {
|
} else if (message.data.type === "SAVE_REVISION") {
|
||||||
await handleSaveRevisionMessage(client, message);
|
await handleSaveRevisionMessage(socket, message);
|
||||||
} else if (message.data.type === "CLIENT_MESSAGE" &&
|
} else if (message.data.type === "CLIENT_MESSAGE" &&
|
||||||
message.data.payload != null &&
|
message.data.payload != null &&
|
||||||
message.data.payload.type === "suggestUserName") {
|
message.data.payload.type === "suggestUserName") {
|
||||||
handleSuggestUserName(client, message);
|
handleSuggestUserName(socket, message);
|
||||||
} else {
|
} else {
|
||||||
messageLogger.warn("Dropped message, unknown COLLABROOM Data Type " + message.data.type);
|
messageLogger.warn("Dropped message, unknown COLLABROOM Data Type " + message.data.type);
|
||||||
}
|
}
|
||||||
} else if(message.type === "SWITCH_TO_PAD") {
|
} else if(message.type === "SWITCH_TO_PAD") {
|
||||||
await handleSwitchToPad(client, message, authorID);
|
await handleSwitchToPad(socket, message, authorID);
|
||||||
} else {
|
} else {
|
||||||
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
messageLogger.warn("Dropped message, unknown Message Type " + message.type);
|
||||||
}
|
}
|
||||||
|
@ -292,16 +290,13 @@ exports.handleMessage = async function(client, message)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a save revision 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
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
async function handleSaveRevisionMessage(client, message)
|
async function handleSaveRevisionMessage(socket, message) {
|
||||||
{
|
const {padId, author: authorId} = sessioninfos[socket.id];
|
||||||
var padId = sessioninfos[client.id].padId;
|
const pad = await padManager.getPad(padId);
|
||||||
var userId = sessioninfos[client.id].author;
|
await pad.addSavedRevision(pad.head, authorId);
|
||||||
|
|
||||||
let pad = await padManager.getPad(padId);
|
|
||||||
await pad.addSavedRevision(pad.head, userId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -343,17 +338,14 @@ exports.handleCustomMessage = function(padID, msgString) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a Chat Message
|
* 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
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
async function handleChatMessage(client, message)
|
async function handleChatMessage(socket, message) {
|
||||||
{
|
|
||||||
var time = Date.now();
|
var time = Date.now();
|
||||||
var userId = sessioninfos[client.id].author;
|
|
||||||
var text = message.data.text;
|
var text = message.data.text;
|
||||||
var padId = sessioninfos[client.id].padId;
|
const {padId, author: authorId} = sessioninfos[socket.id];
|
||||||
|
await exports.sendChatMessageToPadClients(time, authorId, text, padId);
|
||||||
await exports.sendChatMessageToPadClients(time, userId, text, padId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -387,11 +379,10 @@ exports.sendChatMessageToPadClients = async function(time, userId, text, padId)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the clients request for more chat-messages
|
* 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
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
async function handleGetChatMessages(client, message)
|
async function handleGetChatMessages(socket, 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!");
|
||||||
return;
|
return;
|
||||||
|
@ -411,7 +402,7 @@ async function handleGetChatMessages(client, message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let padId = sessioninfos[client.id].padId;
|
const padId = sessioninfos[socket.id].padId;
|
||||||
let pad = await padManager.getPad(padId);
|
let pad = await padManager.getPad(padId);
|
||||||
|
|
||||||
let chatMessages = await pad.getChatMessages(start, end);
|
let chatMessages = await pad.getChatMessages(start, end);
|
||||||
|
@ -424,16 +415,15 @@ async function handleGetChatMessages(client, message)
|
||||||
};
|
};
|
||||||
|
|
||||||
// send the messages back to the client
|
// 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
|
* 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
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
function handleSuggestUserName(client, message)
|
function handleSuggestUserName(socket, message) {
|
||||||
{
|
|
||||||
// check if all ok
|
// check if all ok
|
||||||
if (message.data.payload.newName == null) {
|
if (message.data.payload.newName == null) {
|
||||||
messageLogger.warn("Dropped message, suggestUserName Message has no newName!");
|
messageLogger.warn("Dropped message, suggestUserName Message has no newName!");
|
||||||
|
@ -445,25 +435,23 @@ function handleSuggestUserName(client, message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var padId = sessioninfos[client.id].padId;
|
const padId = sessioninfos[socket.id].padId;
|
||||||
var roomClients = _getRoomClients(padId);
|
|
||||||
|
|
||||||
// search the author and send him this message
|
// search the author and send him this message
|
||||||
roomClients.forEach(function(client) {
|
_getRoomSockets(padId).forEach((socket) => {
|
||||||
var session = sessioninfos[client.id];
|
const session = sessioninfos[socket.id];
|
||||||
if (session && session.author === message.data.payload.unnamedId) {
|
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
|
* 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
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
async function handleUserInfoUpdate(client, message)
|
async function handleUserInfoUpdate(socket, message) {
|
||||||
{
|
|
||||||
// check if all ok
|
// check if all ok
|
||||||
if (message.data.userInfo == null) {
|
if (message.data.userInfo == null) {
|
||||||
messageLogger.warn("Dropped message, USERINFO_UPDATE Message has no userInfo!");
|
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.
|
// 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) {
|
if (!session || !session.author || !session.padId) {
|
||||||
messageLogger.warn("Dropped message, USERINFO_UPDATE Session not ready." + message.data);
|
messageLogger.warn("Dropped message, USERINFO_UPDATE Session not ready." + message.data);
|
||||||
return;
|
return;
|
||||||
|
@ -517,7 +505,7 @@ async function handleUserInfoUpdate(client, message)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send the other clients on the pad the update 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.
|
// Block until the authorManager has stored the new attributes.
|
||||||
await p;
|
await p;
|
||||||
|
@ -534,14 +522,10 @@ async function handleUserInfoUpdate(client, message)
|
||||||
* This function is based on a similar one in the original Etherpad.
|
* 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()
|
* 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
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
async function handleUserChanges(data)
|
async function handleUserChanges(socket, message) {
|
||||||
{
|
|
||||||
var client = data.client
|
|
||||||
, message = data.message
|
|
||||||
|
|
||||||
// This one's no longer pending, as we're gonna process it now
|
// This one's no longer pending, as we're gonna process it now
|
||||||
stats.counter('pendingEdits').dec()
|
stats.counter('pendingEdits').dec()
|
||||||
|
|
||||||
|
@ -563,7 +547,7 @@ async function handleUserChanges(data)
|
||||||
|
|
||||||
// The client might disconnect between our callbacks. We should still
|
// The client might disconnect between our callbacks. We should still
|
||||||
// finish processing the changeset, so keep a reference to the session.
|
// 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
|
// 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
|
// 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) {
|
} catch(e) {
|
||||||
// There is an error in this changeset, so just refuse it
|
// 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();
|
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
|
// ex. applyUserChanges
|
||||||
|
@ -656,14 +640,14 @@ async function handleUserChanges(data)
|
||||||
// prevent eplite from accepting it TODO: better send the client a NEW_CHANGES
|
// prevent eplite from accepting it TODO: better send the client a NEW_CHANGES
|
||||||
// of that revision
|
// of that revision
|
||||||
if (baseRev + 1 === r && c === changeset) {
|
if (baseRev + 1 === r && c === changeset) {
|
||||||
client.json.send({disconnect:"badChangeset"});
|
socket.json.send({disconnect: 'badChangeset'});
|
||||||
stats.meter('failedChangesets').mark();
|
stats.meter('failedChangesets').mark();
|
||||||
throw new Error("Won't apply USER_CHANGES, because it contains an already accepted changeset");
|
throw new Error("Won't apply USER_CHANGES, because it contains an already accepted changeset");
|
||||||
}
|
}
|
||||||
|
|
||||||
changeset = Changeset.follow(c, changeset, false, apool);
|
changeset = Changeset.follow(c, changeset, false, apool);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
client.json.send({disconnect:"badChangeset"});
|
socket.json.send({disconnect: 'badChangeset'});
|
||||||
stats.meter('failedChangesets').mark();
|
stats.meter('failedChangesets').mark();
|
||||||
throw new Error("Can't apply USER_CHANGES, because " + e.message);
|
throw new Error("Can't apply USER_CHANGES, because " + e.message);
|
||||||
}
|
}
|
||||||
|
@ -672,7 +656,7 @@ async function handleUserChanges(data)
|
||||||
let prevText = pad.text();
|
let prevText = pad.text();
|
||||||
|
|
||||||
if (Changeset.oldLen(changeset) !== prevText.length) {
|
if (Changeset.oldLen(changeset) !== prevText.length) {
|
||||||
client.json.send({disconnect:"badChangeset"});
|
socket.json.send({disconnect: 'badChangeset'});
|
||||||
stats.meter('failedChangesets').mark();
|
stats.meter('failedChangesets').mark();
|
||||||
throw new Error("Can't apply USER_CHANGES "+changeset+" with oldLen " + Changeset.oldLen(changeset) + " to document of length " + prevText.length);
|
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 {
|
try {
|
||||||
await pad.appendRevision(changeset, thisSession.author);
|
await pad.appendRevision(changeset, thisSession.author);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
client.json.send({ disconnect: "badChangeset" });
|
socket.json.send({disconnect: 'badChangeset'});
|
||||||
stats.meter('failedChangesets').mark();
|
stats.meter('failedChangesets').mark();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
@ -707,11 +691,8 @@ async function handleUserChanges(data)
|
||||||
exports.updatePadClients = async function(pad)
|
exports.updatePadClients = async function(pad)
|
||||||
{
|
{
|
||||||
// skip this if no-one is on this pad
|
// skip this if no-one is on this pad
|
||||||
let roomClients = _getRoomClients(pad.id);
|
const roomSockets = _getRoomSockets(pad.id);
|
||||||
|
if (roomSockets.length === 0) return;
|
||||||
if (roomClients.length === 0) {
|
|
||||||
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
|
||||||
// to remove unnecessary roundtrip to the datalayer
|
// to remove unnecessary roundtrip to the datalayer
|
||||||
|
@ -723,8 +704,8 @@ exports.updatePadClients = async function(pad)
|
||||||
let revCache = {};
|
let revCache = {};
|
||||||
|
|
||||||
// go through all sessions on this pad
|
// go through all sessions on this pad
|
||||||
for (let client of roomClients) {
|
for (const socket of roomSockets) {
|
||||||
let sid = client.id;
|
const sid = socket.id;
|
||||||
|
|
||||||
// send them all new changesets
|
// send them all new changesets
|
||||||
while (sessioninfos[sid] && sessioninfos[sid].rev < pad.getHeadRevisionNumber()) {
|
while (sessioninfos[sid] && sessioninfos[sid].rev < pad.getHeadRevisionNumber()) {
|
||||||
|
@ -745,7 +726,7 @@ exports.updatePadClients = async function(pad)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (author === sessioninfos[sid].author) {
|
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 {
|
} else {
|
||||||
let forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
let forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
||||||
let wireMsg = {"type": "COLLABROOM",
|
let wireMsg = {"type": "COLLABROOM",
|
||||||
|
@ -758,7 +739,7 @@ exports.updatePadClients = async function(pad)
|
||||||
timeDelta: currentTime - sessioninfos[sid].time
|
timeDelta: currentTime - sessioninfos[sid].time
|
||||||
}};
|
}};
|
||||||
|
|
||||||
client.json.send(wireMsg);
|
socket.json.send(wireMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sessioninfos[sid]) {
|
if (sessioninfos[sid]) {
|
||||||
|
@ -817,19 +798,18 @@ function _correctMarkersInPad(atext, apool) {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSwitchToPad(client, message, _authorID)
|
async function handleSwitchToPad(socket, message, _authorID) {
|
||||||
{
|
const currentSessionInfo = sessioninfos[socket.id];
|
||||||
const currentSessionInfo = sessioninfos[client.id];
|
|
||||||
const padId = currentSessionInfo.padId;
|
const padId = currentSessionInfo.padId;
|
||||||
|
|
||||||
// Check permissions for the new pad.
|
// Check permissions for the new pad.
|
||||||
const newPadIds = await readOnlyManager.getIds(message.padId);
|
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(
|
const {accessStatus, authorID} = await securityManager.checkAccess(
|
||||||
newPadIds.padId, message.sessionID, message.token, user);
|
newPadIds.padId, message.sessionID, message.token, user);
|
||||||
if (accessStatus !== 'grant') {
|
if (accessStatus !== 'grant') {
|
||||||
// Access denied. Send the reason to the user.
|
// Access denied. Send the reason to the user.
|
||||||
client.json.send({accessStatus});
|
socket.json.send({accessStatus});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The same token and session ID were passed to checkAccess in handleMessage, so this second call
|
// 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);
|
assert(authorID === currentSessionInfo.author);
|
||||||
|
|
||||||
// Check if the connection dropped during the access check.
|
// 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
|
// clear the session and leave the room
|
||||||
_getRoomClients(padId).forEach(client => {
|
_getRoomSockets(padId).forEach((socket) => {
|
||||||
let sinfo = sessioninfos[client.id];
|
const sinfo = sessioninfos[socket.id];
|
||||||
if (sinfo && sinfo.author === currentSessionInfo.author) {
|
if (sinfo && sinfo.author === currentSessionInfo.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[socket.id] = {};
|
||||||
client.leave(padId);
|
socket.leave(padId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// start up the new pad
|
// start up the new pad
|
||||||
const newSessionInfo = sessioninfos[client.id];
|
const newSessionInfo = sessioninfos[socket.id];
|
||||||
createSessionInfoAuth(newSessionInfo, message);
|
createSessionInfoAuth(newSessionInfo, message);
|
||||||
await handleClientReady(client, message, authorID);
|
await handleClientReady(socket, message, authorID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates/replaces the auth object in the given session info.
|
// 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
|
* 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
|
* 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
|
* @param message the message from the client
|
||||||
*/
|
*/
|
||||||
async function handleClientReady(client, message, authorID)
|
async function handleClientReady(socket, message, authorID) {
|
||||||
{
|
|
||||||
// check if all ok
|
// check if all ok
|
||||||
if (!message.token) {
|
if (!message.token) {
|
||||||
messageLogger.warn("Dropped message, CLIENT_READY Message has no 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
|
// 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.
|
// 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;
|
if (sessionInfo == null) return;
|
||||||
|
|
||||||
// Check if this author is already on the pad, if yes, kick the other sessions!
|
// 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) {
|
for (const socket of roomSockets) {
|
||||||
let sinfo = sessioninfos[client.id];
|
const sinfo = sessioninfos[socket.id];
|
||||||
if (sinfo && sinfo.author === authorID) {
|
if (sinfo && sinfo.author === authorID) {
|
||||||
// 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[socket.id] = {};
|
||||||
client.leave(padIds.padId);
|
socket.leave(padIds.padId);
|
||||||
client.json.send({disconnect:"userdup"});
|
socket.json.send({disconnect: 'userdup'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,20 +934,20 @@ async function handleClientReady(client, message, authorID)
|
||||||
sessionInfo.padId = padIds.padId;
|
sessionInfo.padId = padIds.padId;
|
||||||
sessionInfo.readOnlyPadId = padIds.readOnlyPadId;
|
sessionInfo.readOnlyPadId = padIds.readOnlyPadId;
|
||||||
sessionInfo.readonly =
|
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'}]` +
|
accessLogger.info(`[${pad.head > 0 ? 'ENTER' : 'CREATE'}]` +
|
||||||
` pad:${padIds.padId}` +
|
` pad:${padIds.padId}` +
|
||||||
` socket:${client.id}` +
|
` socket:${socket.id}` +
|
||||||
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : client.request.ip}` +
|
` IP:${settings.disableIPlogging ? 'ANONYMOUS' : socket.request.ip}` +
|
||||||
` authorID:${authorID}` +
|
` authorID:${authorID}` +
|
||||||
((user && user.username) ? ` username:${user.username}` : ''));
|
((user && user.username) ? ` username:${user.username}` : ''));
|
||||||
|
|
||||||
if (message.reconnect) {
|
if (message.reconnect) {
|
||||||
// If this is a reconnect, we don't have to send the client the ClientVars again
|
// If this is a reconnect, we don't have to send the client the ClientVars again
|
||||||
// Join the pad and start receiving updates
|
// 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
|
// Save the revision in sessioninfos, we take the revision from the info the client send to us
|
||||||
sessionInfo.rev = message.client_rev;
|
sessionInfo.rev = message.client_rev;
|
||||||
|
@ -1019,7 +998,7 @@ async function handleClientReady(client, message, authorID)
|
||||||
author: changesets[r]['author'],
|
author: changesets[r]['author'],
|
||||||
currentTime: changesets[r]['timestamp']
|
currentTime: changesets[r]['timestamp']
|
||||||
}};
|
}};
|
||||||
client.json.send(wireMsg);
|
socket.json.send(wireMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startNum === endNum) {
|
if (startNum === endNum) {
|
||||||
|
@ -1028,7 +1007,7 @@ async function handleClientReady(client, message, authorID)
|
||||||
noChanges: true,
|
noChanges: true,
|
||||||
newRev: pad.getHeadRevisionNumber()
|
newRev: pad.getHeadRevisionNumber()
|
||||||
}};
|
}};
|
||||||
client.json.send(Msg);
|
socket.json.send(Msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1042,7 +1021,7 @@ async function handleClientReady(client, message, authorID)
|
||||||
atext.attribs = attribsForWire.translated;
|
atext.attribs = attribsForWire.translated;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e.stack || e)
|
console.error(e.stack || e)
|
||||||
client.json.send({ disconnect:"corruptPad" }); // pull the brakes
|
socket.json.send({disconnect: 'corruptPad'}); // pull the brakes
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1084,7 +1063,7 @@ async function handleClientReady(client, message, authorID)
|
||||||
// tell the client the number of the latest chat-message, which will be
|
// 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)
|
// used to request the latest 100 chat-messages later (GET_CHAT_MESSAGES)
|
||||||
"chatHead": pad.chatHead,
|
"chatHead": pad.chatHead,
|
||||||
"numConnectedUsers": roomClients.length,
|
"numConnectedUsers": roomSockets.length,
|
||||||
"readOnlyId": padIds.readOnlyPadId,
|
"readOnlyId": padIds.readOnlyPadId,
|
||||||
"readonly": sessionInfo.readonly,
|
"readonly": sessionInfo.readonly,
|
||||||
"serverTimestamp": Date.now(),
|
"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
|
// 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
|
// combine our old object with the new attributes from the hook
|
||||||
for (let msg of messages) {
|
for (let msg of messages) {
|
||||||
|
@ -1123,10 +1102,10 @@ async function handleClientReady(client, message, authorID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join the pad and start receiving updates
|
// Join the pad and start receiving updates
|
||||||
client.join(padIds.padId);
|
socket.join(padIds.padId);
|
||||||
|
|
||||||
// Send the clientVars to the Client
|
// 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
|
// Save the current revision in sessioninfos, should be the same as in clientVars
|
||||||
sessionInfo.rev = pad.getHeadRevisionNumber();
|
sessionInfo.rev = pad.getHeadRevisionNumber();
|
||||||
|
@ -1151,20 +1130,19 @@ async function handleClientReady(client, message, authorID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify all existing users about new user
|
// 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)
|
// Get sessions for this pad and update them (in parallel)
|
||||||
roomClients = _getRoomClients(pad.id);
|
await Promise.all(_getRoomSockets(pad.id).map(async (roomSocket) => {
|
||||||
await Promise.all(_getRoomClients(pad.id).map(async roomClient => {
|
|
||||||
|
|
||||||
// Jump over, if this session is the connection session
|
// Jump over, if this session is the connection session
|
||||||
if (roomClient.id === client.id) {
|
if (roomSocket.id === socket.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since sessioninfos might change while being enumerated, check if the
|
// Since sessioninfos might change while being enumerated, check if the
|
||||||
// sessionID is still assigned to a valid session
|
// sessionID is still assigned to a valid session
|
||||||
const sessionInfo = sessioninfos[roomClient.id];
|
const sessionInfo = sessioninfos[roomSocket.id];
|
||||||
if (sessionInfo == null) return;
|
if (sessionInfo == null) return;
|
||||||
|
|
||||||
// get the authorname & colorId
|
// 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
|
* 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
|
// check if all ok
|
||||||
if (message.data == null) {
|
if (message.data == null) {
|
||||||
messageLogger.warn("Dropped message, changeset request has no data!");
|
messageLogger.warn("Dropped message, changeset request has no data!");
|
||||||
|
@ -1263,7 +1240,7 @@ async function handleChangesetRequest(client, message)
|
||||||
try {
|
try {
|
||||||
let data = await getChangesetInfo(padIds.padId, start, end, granularity);
|
let data = await getChangesetInfo(padIds.padId, start, end, granularity);
|
||||||
data.requestID = message.data.requestID;
|
data.requestID = message.data.requestID;
|
||||||
client.json.send({ type: "CHANGESET_REQ", data });
|
socket.json.send({type: 'CHANGESET_REQ', data});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error while handling a changeset request for ' + padIds.padId, err.toString(), message.data);
|
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) {
|
function _getRoomSockets(padID) {
|
||||||
var roomClients = [];
|
const roomSockets = [];
|
||||||
var room = socketio.sockets.adapter.rooms[padID];
|
var room = socketio.sockets.adapter.rooms[padID];
|
||||||
|
|
||||||
if (room) {
|
if (room) {
|
||||||
for (var id in room.sockets) {
|
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) {
|
exports.padUsersCount = function(padID) {
|
||||||
return {
|
return {
|
||||||
padUsersCount: _getRoomClients(padID).length
|
padUsersCount: _getRoomSockets(padID).length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1459,11 +1436,10 @@ exports.padUsersCount = function(padID) {
|
||||||
exports.padUsers = async function(padID) {
|
exports.padUsers = async function(padID) {
|
||||||
|
|
||||||
let padUsers = [];
|
let padUsers = [];
|
||||||
let roomClients = _getRoomClients(padID);
|
|
||||||
|
|
||||||
// iterate over all clients (in parallel)
|
// iterate over all clients (in parallel)
|
||||||
await Promise.all(roomClients.map(async roomClient => {
|
await Promise.all(_getRoomSockets(padID).map(async (roomSocket) => {
|
||||||
let s = sessioninfos[roomClient.id];
|
const s = sessioninfos[roomSocket.id];
|
||||||
if (s) {
|
if (s) {
|
||||||
return authorManager.getAuthor(s.author).then(author => {
|
return authorManager.getAuthor(s.author).then(author => {
|
||||||
// Fixes: https://github.com/ether/etherpad-lite/issues/4120
|
// Fixes: https://github.com/ether/etherpad-lite/issues/4120
|
||||||
|
|
Loading…
Reference in a new issue