mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-21 07:56:16 -04:00
chat: Move chat message handling to handleMessage
hook
This commit is contained in:
parent
a177a622c4
commit
8d5fdd7dc9
6 changed files with 87 additions and 51 deletions
|
@ -92,6 +92,9 @@
|
||||||
* `padUpdate`: The `author` context property is deprecated; use the new
|
* `padUpdate`: The `author` context property is deprecated; use the new
|
||||||
`authorId` context property instead. Also, the hook now runs asynchronously.
|
`authorId` context property instead. Also, the hook now runs asynchronously.
|
||||||
* Chat API deprecations and removals (no replacements planned):
|
* Chat API deprecations and removals (no replacements planned):
|
||||||
|
* Server-side:
|
||||||
|
* The `sendChatMessageToPadClients()` function in
|
||||||
|
`src/node/handler/PadMessageHandler.js` is deprecated.
|
||||||
* Client-side:
|
* Client-side:
|
||||||
* The `pad.determineChatVisibility()` method was removed.
|
* The `pad.determineChatVisibility()` method was removed.
|
||||||
* The `pad.determineChatAndUsersVisibility()` method was removed.
|
* The `pad.determineChatAndUsersVisibility()` method was removed.
|
||||||
|
|
|
@ -1086,7 +1086,7 @@ exports.userLeave = async (hookName, {author, padId}) => {
|
||||||
|
|
||||||
## `chatNewMessage`
|
## `chatNewMessage`
|
||||||
|
|
||||||
Called from: `src/node/handler/PadMessageHandler.js`
|
Called from: `src/node/chat.js`
|
||||||
|
|
||||||
Called when a user (or plugin) generates a new chat message, just before it is
|
Called when a user (or plugin) generates a new chat message, just before it is
|
||||||
saved to the pad and relayed to all connected users.
|
saved to the pad and relayed to all connected users.
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
},
|
},
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"eejsBlock_mySettings": "ep_etherpad-lite/node/chat",
|
"eejsBlock_mySettings": "ep_etherpad-lite/node/chat",
|
||||||
"eejsBlock_stickyContainer": "ep_etherpad-lite/node/chat"
|
"eejsBlock_stickyContainer": "ep_etherpad-lite/node/chat",
|
||||||
|
"handleMessage": "ep_etherpad-lite/node/chat",
|
||||||
|
"socketio": "ep_etherpad-lite/node/chat"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,28 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const ChatMessage = require('../static/js/ChatMessage');
|
||||||
|
const api = require('./db/API');
|
||||||
|
const authorManager = require('./db/AuthorManager');
|
||||||
|
const hooks = require('../static/js/pluginfw/hooks.js');
|
||||||
|
const padManager = require('./db/PadManager');
|
||||||
|
const padMessageHandler = require('./handler/PadMessageHandler');
|
||||||
|
|
||||||
|
let socketio;
|
||||||
|
|
||||||
|
const sendChatMessageToPadClients = async (message, padId) => {
|
||||||
|
const pad = await padManager.getPad(padId, null, message.authorId);
|
||||||
|
await hooks.aCallAll('chatNewMessage', {message, pad, padId});
|
||||||
|
// pad.appendChatMessage() ignores the displayName property so we don't need to wait for
|
||||||
|
// authorManager.getAuthorName() to resolve before saving the message to the database.
|
||||||
|
const promise = pad.appendChatMessage(message);
|
||||||
|
message.displayName = await authorManager.getAuthorName(message.authorId);
|
||||||
|
socketio.sockets.in(padId).json.send({
|
||||||
|
type: 'COLLABROOM',
|
||||||
|
data: {type: 'CHAT_MESSAGE', message},
|
||||||
|
});
|
||||||
|
await promise;
|
||||||
|
};
|
||||||
|
|
||||||
exports.eejsBlock_mySettings = (hookName, context) => {
|
exports.eejsBlock_mySettings = (hookName, context) => {
|
||||||
context.content += `
|
context.content += `
|
||||||
<p class="hide-for-mobile">
|
<p class="hide-for-mobile">
|
||||||
|
@ -42,3 +65,49 @@ exports.eejsBlock_stickyContainer = (hookName, context) => {
|
||||||
`;
|
`;
|
||||||
/* eslint-enable max-len */
|
/* eslint-enable max-len */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.handleMessage = async (hookName, {message, sessionInfo, socket}) => {
|
||||||
|
const {authorId, padId, readOnly} = sessionInfo;
|
||||||
|
if (message.type !== 'COLLABROOM' || readOnly) return;
|
||||||
|
switch (message.data.type) {
|
||||||
|
case 'CHAT_MESSAGE': {
|
||||||
|
const chatMessage = ChatMessage.fromObject(message.data.message);
|
||||||
|
// Don't trust the user-supplied values.
|
||||||
|
chatMessage.time = Date.now();
|
||||||
|
chatMessage.authorId = authorId;
|
||||||
|
await sendChatMessageToPadClients(chatMessage, padId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'GET_CHAT_MESSAGES': {
|
||||||
|
const {start, end} = message.data;
|
||||||
|
if (!Number.isInteger(start)) throw new Error(`missing or invalid start: ${start}`);
|
||||||
|
if (!Number.isInteger(end)) throw new Error(`missing or invalid end: ${end}`);
|
||||||
|
const count = end - start;
|
||||||
|
if (count < 0 || count > 100) throw new Error(`invalid number of messages: ${count}`);
|
||||||
|
const pad = await padManager.getPad(padId, null, authorId);
|
||||||
|
socket.json.send({
|
||||||
|
type: 'COLLABROOM',
|
||||||
|
data: {
|
||||||
|
type: 'CHAT_MESSAGES',
|
||||||
|
messages: await pad.getChatMessages(start, end),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return null; // Important! Returning null (not undefined!) stops further processing.
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.socketio = (hookName, {io}) => {
|
||||||
|
socketio = io;
|
||||||
|
};
|
||||||
|
|
||||||
|
api.registerChatHandlers({
|
||||||
|
sendChatMessageToPadClients,
|
||||||
|
});
|
||||||
|
|
||||||
|
padMessageHandler.registerLegacyChatHandlers({
|
||||||
|
sendChatMessageToPadClients,
|
||||||
|
});
|
||||||
|
|
|
@ -289,6 +289,9 @@ exports.setHTML = async (padID, html, authorId = '') => {
|
||||||
* CHAT FUNCTIONS *
|
* CHAT FUNCTIONS *
|
||||||
**************** */
|
**************** */
|
||||||
|
|
||||||
|
let chat = null;
|
||||||
|
exports.registerChatHandlers = (handlers) => chat = handlers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
getChatHistory(padId, start, end), returns a part of or the whole chat-history of this pad
|
getChatHistory(padId, start, end), returns a part of or the whole chat-history of this pad
|
||||||
|
|
||||||
|
@ -363,7 +366,7 @@ exports.appendChatMessage = async (padID, text, authorID, time) => {
|
||||||
// @TODO - missing getPadSafe() call ?
|
// @TODO - missing getPadSafe() call ?
|
||||||
|
|
||||||
// save chat message to database and send message to all connected clients
|
// save chat message to database and send message to all connected clients
|
||||||
await padMessageHandler.sendChatMessageToPadClients(new ChatMessage(text, authorID, time), padID);
|
await chat.sendChatMessageToPadClients(new ChatMessage(text, authorID, time), padID);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ***************
|
/* ***************
|
||||||
|
|
|
@ -40,6 +40,7 @@ const assert = require('assert').strict;
|
||||||
const {RateLimiterMemory} = require('rate-limiter-flexible');
|
const {RateLimiterMemory} = require('rate-limiter-flexible');
|
||||||
const webaccess = require('../hooks/express/webaccess');
|
const webaccess = require('../hooks/express/webaccess');
|
||||||
|
|
||||||
|
let chat = null;
|
||||||
let rateLimiter;
|
let rateLimiter;
|
||||||
let socketio = null;
|
let socketio = null;
|
||||||
|
|
||||||
|
@ -54,6 +55,8 @@ const addContextToError = (err, pfx) => {
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.registerLegacyChatHandlers = (handlers) => chat = handlers;
|
||||||
|
|
||||||
exports.socketio = () => {
|
exports.socketio = () => {
|
||||||
// The rate limiter is created in this hook so that restarting the server resets the limiter. The
|
// The rate limiter is created in this hook so that restarting the server resets the limiter. The
|
||||||
// settings.commitRateLimiting object is passed directly to the rate limiter so that the limits
|
// settings.commitRateLimiting object is passed directly to the rate limiter so that the limits
|
||||||
|
@ -335,8 +338,6 @@ exports.handleMessage = async (socket, message) => {
|
||||||
await padChannels.enqueue(thisSession.padId, {socket, message});
|
await padChannels.enqueue(thisSession.padId, {socket, message});
|
||||||
break;
|
break;
|
||||||
case 'USERINFO_UPDATE': await handleUserInfoUpdate(socket, message); break;
|
case 'USERINFO_UPDATE': await handleUserInfoUpdate(socket, message); break;
|
||||||
case 'CHAT_MESSAGE': await handleChatMessage(socket, message); break;
|
|
||||||
case 'GET_CHAT_MESSAGES': await handleGetChatMessages(socket, message); break;
|
|
||||||
case 'SAVE_REVISION': await handleSaveRevisionMessage(socket, message); break;
|
case 'SAVE_REVISION': await handleSaveRevisionMessage(socket, message); break;
|
||||||
case 'CLIENT_MESSAGE': {
|
case 'CLIENT_MESSAGE': {
|
||||||
const {type} = message.data.payload;
|
const {type} = message.data.payload;
|
||||||
|
@ -413,23 +414,10 @@ exports.handleCustomMessage = (padID, msgString) => {
|
||||||
socketio.sockets.in(padID).json.send(msg);
|
socketio.sockets.in(padID).json.send(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles a Chat Message
|
|
||||||
* @param socket the socket.io Socket object for the client
|
|
||||||
* @param message the message from the client
|
|
||||||
*/
|
|
||||||
const handleChatMessage = async (socket, message) => {
|
|
||||||
const chatMessage = ChatMessage.fromObject(message.data.message);
|
|
||||||
const {padId, author: authorId} = sessioninfos[socket.id];
|
|
||||||
// Don't trust the user-supplied values.
|
|
||||||
chatMessage.time = Date.now();
|
|
||||||
chatMessage.authorId = authorId;
|
|
||||||
await exports.sendChatMessageToPadClients(chatMessage, padId);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new chat message to a pad and sends it to connected clients.
|
* Adds a new chat message to a pad and sends it to connected clients.
|
||||||
*
|
*
|
||||||
|
* @deprecated Use chat.sendChatMessageToPadClients() instead.
|
||||||
* @param {(ChatMessage|number)} mt - Either a chat message object (recommended) or the timestamp of
|
* @param {(ChatMessage|number)} mt - Either a chat message object (recommended) or the timestamp of
|
||||||
* the chat message in ms since epoch (deprecated).
|
* the chat message in ms since epoch (deprecated).
|
||||||
* @param {string} puId - If `mt` is a chat message object, this is the destination pad ID.
|
* @param {string} puId - If `mt` is a chat message object, this is the destination pad ID.
|
||||||
|
@ -439,40 +427,11 @@ const handleChatMessage = async (socket, message) => {
|
||||||
* object as the first argument and the destination pad ID as the second argument instead.
|
* object as the first argument and the destination pad ID as the second argument instead.
|
||||||
*/
|
*/
|
||||||
exports.sendChatMessageToPadClients = async (mt, puId, text = null, padId = null) => {
|
exports.sendChatMessageToPadClients = async (mt, puId, text = null, padId = null) => {
|
||||||
|
padutils.warnDeprecated('PadMessageHandler.sendChatMessageToPadClients() is deprecated; ' +
|
||||||
|
'use chat.sendChatMessageToPadClients() instead');
|
||||||
const message = mt instanceof ChatMessage ? mt : new ChatMessage(text, puId, mt);
|
const message = mt instanceof ChatMessage ? mt : new ChatMessage(text, puId, mt);
|
||||||
padId = mt instanceof ChatMessage ? puId : padId;
|
padId = mt instanceof ChatMessage ? puId : padId;
|
||||||
const pad = await padManager.getPad(padId, null, message.authorId);
|
await chat.sendChatMessageToPadClients(message, padId);
|
||||||
await hooks.aCallAll('chatNewMessage', {message, pad, padId});
|
|
||||||
// pad.appendChatMessage() ignores the displayName property so we don't need to wait for
|
|
||||||
// authorManager.getAuthorName() to resolve before saving the message to the database.
|
|
||||||
const promise = pad.appendChatMessage(message);
|
|
||||||
message.displayName = await authorManager.getAuthorName(message.authorId);
|
|
||||||
socketio.sockets.in(padId).json.send({
|
|
||||||
type: 'COLLABROOM',
|
|
||||||
data: {type: 'CHAT_MESSAGE', message},
|
|
||||||
});
|
|
||||||
await promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the clients request for more chat-messages
|
|
||||||
* @param socket the socket.io Socket object for the client
|
|
||||||
* @param message the message from the client
|
|
||||||
*/
|
|
||||||
const handleGetChatMessages = async (socket, {data: {start, end}}) => {
|
|
||||||
if (!Number.isInteger(start)) throw new Error(`missing or invalid start: ${start}`);
|
|
||||||
if (!Number.isInteger(end)) throw new Error(`missing or invalid end: ${end}`);
|
|
||||||
const count = end - start;
|
|
||||||
if (count < 0 || count > 100) throw new Error(`invalid number of messages: ${count}`);
|
|
||||||
const {padId, author: authorId} = sessioninfos[socket.id];
|
|
||||||
const pad = await padManager.getPad(padId, null, authorId);
|
|
||||||
socket.json.send({
|
|
||||||
type: 'COLLABROOM',
|
|
||||||
data: {
|
|
||||||
type: 'CHAT_MESSAGES',
|
|
||||||
messages: await pad.getChatMessages(start, end),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue