mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 03:26:04 +01:00
feat: add req and socket to als, closes https://github.com/NodeBB/NodeBB/pull/10304
This commit is contained in:
@@ -21,6 +21,7 @@ exports.setDefaultPostData = function (reqOrSocket, data) {
|
|||||||
exports.buildReqObject = (req, payload) => {
|
exports.buildReqObject = (req, payload) => {
|
||||||
req = req || {};
|
req = req || {};
|
||||||
const headers = req.headers || (req.request && req.request.headers) || {};
|
const headers = req.headers || (req.request && req.request.headers) || {};
|
||||||
|
const session = req.session || (req.request && req.request.session) || {};
|
||||||
const encrypted = req.connection ? !!req.connection.encrypted : false;
|
const encrypted = req.connection ? !!req.connection.encrypted : false;
|
||||||
let { host } = headers;
|
let { host } = headers;
|
||||||
const referer = headers.referer || '';
|
const referer = headers.referer || '';
|
||||||
@@ -34,13 +35,15 @@ exports.buildReqObject = (req, payload) => {
|
|||||||
params: req.params,
|
params: req.params,
|
||||||
method: req.method,
|
method: req.method,
|
||||||
body: payload || req.body,
|
body: payload || req.body,
|
||||||
session: req.session,
|
session: session,
|
||||||
ip: req.ip,
|
ip: req.ip,
|
||||||
host: host,
|
host: host,
|
||||||
protocol: encrypted ? 'https' : 'http',
|
protocol: encrypted ? 'https' : 'http',
|
||||||
secure: encrypted,
|
secure: encrypted,
|
||||||
url: referer,
|
url: referer,
|
||||||
path: referer.slice(referer.indexOf(host) + host.length),
|
path: referer.slice(referer.indexOf(host) + host.length),
|
||||||
|
baseUrl: req.baseUrl,
|
||||||
|
originalUrl: req.originalUrl,
|
||||||
headers: headers,
|
headers: headers,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -84,9 +84,14 @@ function onConnection(socket) {
|
|||||||
|
|
||||||
onConnect(socket);
|
onConnect(socket);
|
||||||
socket.onAny((event, ...args) => {
|
socket.onAny((event, ...args) => {
|
||||||
const payload = { data: [event].concat(args) };
|
const payload = { event: event, ...deserializePayload(args) };
|
||||||
const als = require('../als');
|
const als = require('../als');
|
||||||
als.run({ uid: socket.uid }, onMessage, socket, payload);
|
const apiHelpers = require('../api/helpers');
|
||||||
|
als.run({
|
||||||
|
uid: socket.uid,
|
||||||
|
req: apiHelpers.buildReqObject(socket, payload),
|
||||||
|
socket: { ...payload },
|
||||||
|
}, onMessage, socket, payload);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
@@ -123,27 +128,29 @@ async function onConnect(socket) {
|
|||||||
plugins.hooks.fire('action:sockets.connect', { socket: socket });
|
plugins.hooks.fire('action:sockets.connect', { socket: socket });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onMessage(socket, payload) {
|
function deserializePayload(payload) {
|
||||||
if (!payload.data.length) {
|
if (!Array.isArray(payload) || !payload.length) {
|
||||||
return winston.warn('[socket.io] Empty payload');
|
winston.warn('[socket.io] Empty payload');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const params = typeof payload[0] === 'function' ? {} : payload[0];
|
||||||
|
const callback = typeof payload[payload.length - 1] === 'function' ? payload[payload.length - 1] : function () {};
|
||||||
|
return { params, callback };
|
||||||
}
|
}
|
||||||
|
|
||||||
let eventName = payload.data[0];
|
async function onMessage(socket, payload) {
|
||||||
const params = typeof payload.data[1] === 'function' ? {} : payload.data[1];
|
const { event, params, callback } = payload;
|
||||||
const callback = typeof payload.data[payload.data.length - 1] === 'function' ? payload.data[payload.data.length - 1] : function () {};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!eventName) {
|
if (!event) {
|
||||||
return winston.warn('[socket.io] Empty method name');
|
return winston.warn('[socket.io] Empty method name');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof eventName !== 'string') {
|
if (typeof event !== 'string') {
|
||||||
eventName = typeof eventName;
|
const escapedName = validator.escape(typeof event);
|
||||||
const escapedName = validator.escape(eventName);
|
|
||||||
return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
|
return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts = eventName.split('.');
|
const parts = event.split('.');
|
||||||
const namespace = parts[0];
|
const namespace = parts[0];
|
||||||
const methodToCall = parts.reduce((prev, cur) => {
|
const methodToCall = parts.reduce((prev, cur) => {
|
||||||
if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) {
|
if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) {
|
||||||
@@ -154,19 +161,19 @@ async function onMessage(socket, payload) {
|
|||||||
|
|
||||||
if (!methodToCall || typeof methodToCall !== 'function') {
|
if (!methodToCall || typeof methodToCall !== 'function') {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
winston.warn(`[socket.io] Unrecognized message: ${eventName}`);
|
winston.warn(`[socket.io] Unrecognized message: ${event}`);
|
||||||
}
|
}
|
||||||
const escapedName = validator.escape(String(eventName));
|
const escapedName = validator.escape(String(event));
|
||||||
return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
|
return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.previousEvents = socket.previousEvents || [];
|
socket.previousEvents = socket.previousEvents || [];
|
||||||
socket.previousEvents.push(eventName);
|
socket.previousEvents.push(event);
|
||||||
if (socket.previousEvents.length > 20) {
|
if (socket.previousEvents.length > 20) {
|
||||||
socket.previousEvents.shift();
|
socket.previousEvents.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eventName.startsWith('admin.') && ratelimit.isFlooding(socket)) {
|
if (!event.startsWith('admin.') && ratelimit.isFlooding(socket)) {
|
||||||
winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`);
|
winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`);
|
||||||
return socket.disconnect();
|
return socket.disconnect();
|
||||||
}
|
}
|
||||||
@@ -175,7 +182,7 @@ async function onMessage(socket, payload) {
|
|||||||
await validateSession(socket, '[[error:revalidate-failure]]');
|
await validateSession(socket, '[[error:revalidate-failure]]');
|
||||||
|
|
||||||
if (Namespaces[namespace].before) {
|
if (Namespaces[namespace].before) {
|
||||||
await Namespaces[namespace].before(socket, eventName, params);
|
await Namespaces[namespace].before(socket, event, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methodToCall.constructor && methodToCall.constructor.name === 'AsyncFunction') {
|
if (methodToCall.constructor && methodToCall.constructor.name === 'AsyncFunction') {
|
||||||
@@ -187,7 +194,7 @@ async function onMessage(socket, payload) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
winston.error(`${eventName}\n${err.stack ? err.stack : err.message}`);
|
winston.error(`${event}\n${err.stack ? err.stack : err.message}`);
|
||||||
callback({ message: err.message });
|
callback({ message: err.message });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,8 +176,12 @@ function setupExpressApp(app) {
|
|||||||
app.use(middleware.processRender);
|
app.use(middleware.processRender);
|
||||||
auth.initialize(app, middleware);
|
auth.initialize(app, middleware);
|
||||||
const als = require('./als');
|
const als = require('./als');
|
||||||
|
const apiHelpers = require('./api/helpers');
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
als.run({ uid: req.uid }, next);
|
als.run({
|
||||||
|
uid: req.uid,
|
||||||
|
req: apiHelpers.buildReqObject(req),
|
||||||
|
}, next);
|
||||||
});
|
});
|
||||||
app.use(middleware.autoLocale); // must be added after auth middlewares are added
|
app.use(middleware.autoLocale); // must be added after auth middlewares are added
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user