From 4887cd952a45bdd41e5799a9b11edc80ebb70883 Mon Sep 17 00:00:00 2001 From: Hossein Marzban Date: Sun, 25 Feb 2024 14:33:55 +0330 Subject: [PATCH] Revise `transport` Socket.io@3/4 (#6188) * feat :migrate socket.io 2 -> 3 * fix: backend test * fix: ts error * rm * reset the test timeout * fix: socket transports * fix: ts * fix: merge * fix: merge * resolve merge * clean * clean --- src/node/handler/PadMessageHandler.ts | 1 + src/node/hooks/express/socketio.ts | 35 ++++++++++++++------------- src/package.json | 5 ++-- src/static/js/socketio.js | 20 ++++++++++++++- 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/node/handler/PadMessageHandler.ts b/src/node/handler/PadMessageHandler.ts index bbeef736a..221af33d2 100644 --- a/src/node/handler/PadMessageHandler.ts +++ b/src/node/handler/PadMessageHandler.ts @@ -957,6 +957,7 @@ const handleClientReady = async (socket:any, message: typeof ChatMessage) => { rev: pad.getHeadRevisionNumber(), time: currentTime, }, + socketTransportProtocols: settings.socketTransportProtocols, colorPalette: authorManager.getColorPalette(), clientIp: '127.0.0.1', userColor: authorColorId, diff --git a/src/node/hooks/express/socketio.ts b/src/node/hooks/express/socketio.ts index 201289e83..896d0779f 100644 --- a/src/node/hooks/express/socketio.ts +++ b/src/node/hooks/express/socketio.ts @@ -70,29 +70,30 @@ exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Functio // there shouldn't be a browser that isn't compatible to all // transports in this list at once // e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling - io = new Server(args.server, { + io = new Server({ transports: settings.socketTransportProtocols, }) - function handleConnection() { - return (socket: any) => { - sockets.add(socket); - socketsEvents.emit('updated'); - // https://socket.io/docs/v3/faq/index.html - const session = socket.request.session; - session.connections++; - session.save(); - socket.on('disconnect', () => { - sockets.delete(socket); - socketsEvents.emit('updated'); - }); - }; - } + io.attach(args.server, { + cookie: false, + maxHttpBufferSize: settings.socketIo.maxHttpBufferSize, + }); - io.on('connection', handleConnection); + io.on('connection', (socket:any) => { + sockets.add(socket); + socketsEvents.emit('updated'); + // https://socket.io/docs/v3/faq/index.html + const session = socket.request.session; + session.connections++; + session.save(); + socket.on('disconnect', () => { + sockets.delete(socket); + socketsEvents.emit('updated'); + }); + }); io.use(exports.socketSessionMiddleware(args)); - + // Temporary workaround so all clients go through middleware and handle connection io.of('/pluginfw/installer').use(exports.socketSessionMiddleware(args)) io.of('/settings').use(exports.socketSessionMiddleware(args)) diff --git a/src/package.json b/src/package.json index dee0a66ab..8e2ebf533 100644 --- a/src/package.json +++ b/src/package.json @@ -63,7 +63,7 @@ "security": "1.0.0", "semver": "^7.6.0", "socket.io": "^3.1.2", - "socket.io-client": "^4.7.4", + "socket.io-client": "^3.1.2", "superagent": "^8.1.2", "terser": "^5.28.1", "threads": "^1.7.0", @@ -88,6 +88,7 @@ "@types/sinon": "^17.0.3", "@types/supertest": "^6.0.2", "@types/underscore": "^1.11.15", + "cypress": "^13.6.4", "eslint": "^8.56.0", "eslint-config-etherpad": "^3.0.22", "etherpad-cli-client": "^3.0.1", @@ -113,7 +114,7 @@ }, "scripts": { "lint": "eslint .", - "test": "mocha --import=tsx --timeout 120000 --recursive tests/backend/specs/**.ts tests/backend/specs/**/*.ts ../node_modules/ep_*/static/tests/backend/specs", + "test": "mocha --import=tsx --timeout 120000 --recursive tests/backend/specs/**.ts tests/backend/specs/**/*.ts", "test-container": "mocha --import=tsx --timeout 5000 tests/container/specs/api", "dev": "node --import tsx node/server.ts", "prod": "node --import tsx node/server.ts", diff --git a/src/static/js/socketio.js b/src/static/js/socketio.js index bf9cfd5d5..3bc7dba58 100644 --- a/src/static/js/socketio.js +++ b/src/static/js/socketio.js @@ -19,7 +19,25 @@ const connect = (etherpadBaseUrl, namespace = '/', options = {}) => { const baseUrl = new URL(etherpadBaseUrl, window.location); const socketioUrl = new URL('socket.io', baseUrl); const namespaceUrl = new URL(namespace, new URL('/', baseUrl)); - return io(namespaceUrl.href, Object.assign({path: socketioUrl.pathname}, options)); + + let socketOptions = { + path: socketioUrl.pathname, + upgrade: true, + transports: ["websocket"] + } + socketOptions = Object.assign(options, socketOptions); + + const socket = io(namespaceUrl.href, socketOptions); + + socket.on('connect_error', (error) => { + if (socket.io.engine.transports.indexOf('polling') === -1) { + console.warn('WebSocket connection failed. Falling back to long-polling.'); + socket.io.opts.transports = ['polling']; + socket.io.engine.upgrade = false; + } + }); + + return socket; }; if (typeof exports === 'object') {