From 303964c51e92dd207a0e8eecc0ce2993d134331c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 10 Dec 2020 17:24:28 -0500 Subject: [PATCH] socket.io: Factor out client connection logic --- src/node/utils/tar.json | 2 ++ src/static/js/admin/plugins.js | 13 +++---------- src/static/js/admin/settings.js | 13 +++---------- src/static/js/pad.js | 13 +++---------- src/static/js/socketio.js | 29 +++++++++++++++++++++++++++++ src/static/js/timeslider.js | 10 ++-------- src/templates/admin/plugins.html | 1 + src/templates/admin/settings.html | 1 + 8 files changed, 44 insertions(+), 38 deletions(-) create mode 100644 src/static/js/socketio.js diff --git a/src/node/utils/tar.json b/src/node/utils/tar.json index 30bc45ab2..c688816ad 100644 --- a/src/node/utils/tar.json +++ b/src/node/utils/tar.json @@ -22,6 +22,7 @@ , "excanvas.js" , "farbtastic.js" , "skin_variants.js" + , "socketio.js" ] , "timeslider.js": [ "timeslider.js" @@ -45,6 +46,7 @@ , "broadcast.js" , "broadcast_slider.js" , "broadcast_revisions.js" + , "socketio.js" ] , "ace2_inner.js": [ "ace2_inner.js" diff --git a/src/static/js/admin/plugins.js b/src/static/js/admin/plugins.js index 3fc4d45fc..a854e99da 100644 --- a/src/static/js/admin/plugins.js +++ b/src/static/js/admin/plugins.js @@ -1,16 +1,9 @@ 'use strict'; -$(document).ready(() => { - const loc = document.location; - const port = loc.port === '' ? (loc.protocol === 'https:' ? 443 : 80) : loc.port; - const url = `${loc.protocol}//${loc.hostname}:${port}/`; - const pathComponents = location.pathname.split('/'); - // Strip admin/plugins - const baseURL = `${pathComponents.slice(0, pathComponents.length - 2).join('/')}/`; +/* global socketio */ - // connect - const room = `${url}pluginfw/installer`; - const socket = io.connect(room, {path: `${baseURL}socket.io`}); +$(document).ready(() => { + const socket = socketio.connect('..', '/pluginfw/installer'); const search = (searchTerm, limit) => { if (search.searchTerm !== searchTerm) { diff --git a/src/static/js/admin/settings.js b/src/static/js/admin/settings.js index e54bef3d8..5809ed866 100644 --- a/src/static/js/admin/settings.js +++ b/src/static/js/admin/settings.js @@ -1,16 +1,9 @@ 'use strict'; -$(document).ready(() => { - const loc = document.location; - const port = loc.port === '' ? (loc.protocol === 'https:' ? 443 : 80) : loc.port; - const url = `${loc.protocol}//${loc.hostname}:${port}/`; - const pathComponents = location.pathname.split('/'); - // Strip admin/plugins - const baseURL = `${pathComponents.slice(0, pathComponents.length - 2).join('/')}/`; +/* global socketio */ - // connect - const room = `${url}settings`; - const socket = io.connect(room, {path: `${baseURL}socket.io`}); +$(document).ready(() => { + const socket = socketio.connect('..', '/settings'); socket.on('settings', (settings) => { /* Check whether the settings.json is authorized to be viewed */ diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 0656005f8..2211922a3 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -29,6 +29,7 @@ let socket; require('./jquery'); require('./farbtastic'); require('./excanvas'); +require('./gritter'); const Cookies = require('./pad_utils').Cookies; const chat = require('./chat').chat; @@ -44,7 +45,7 @@ const paduserlist = require('./pad_userlist').paduserlist; const padutils = require('./pad_utils').padutils; const colorutils = require('./colorutils').colorutils; const randomString = require('./pad_utils').randomString; -require('./gritter'); // Mutates the jQuery object to make $.gritter available. +const socketio = require('./socketio'); const hooks = require('./pluginfw/hooks'); @@ -218,15 +219,7 @@ const sendClientReady = (isReconnect, messageType) => { }; const handshake = () => { - const loc = document.location; - // get the correct port - const port = loc.port === '' ? (loc.protocol === 'https:' ? 443 : 80) : loc.port; - // create the url - const url = `${loc.protocol}//${loc.hostname}:${port}/`; - // connect - socket = pad.socket = io.connect(url, { - // Allow deployers to host Etherpad on a non-root path - path: `${exports.baseURL}socket.io`, + socket = pad.socket = socketio.connect(exports.baseURL, '/', { reconnectionAttempts: 5, reconnection: true, reconnectionDelay: 1000, diff --git a/src/static/js/socketio.js b/src/static/js/socketio.js new file mode 100644 index 000000000..bf9cfd5d5 --- /dev/null +++ b/src/static/js/socketio.js @@ -0,0 +1,29 @@ +'use strict'; + +/** + * Creates a socket.io connection. + * @param etherpadBaseUrl - Etherpad URL. If relative, it is assumed to be relative to + * window.location. + * @param namespace - socket.io namespace. + * @param options - socket.io client options. See + * https://socket.io/docs/v2/client-api/#new-Manager-url-options + * @return socket.io Socket object + */ +const connect = (etherpadBaseUrl, namespace = '/', options = {}) => { + // The API for socket.io's io() function is awkward. The documentation says that the first + // argument is a URL, but it is not the URL of the socket.io endpoint. The URL's path part is used + // as the name of the socket.io namespace to join, and the rest of the URL (including query + // parameters, if present) is combined with the `path` option (which defaults to '/socket.io', but + // is overridden here to allow users to host Etherpad at something like '/etherpad') to get the + // URL of the socket.io endpoint. + 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)); +}; + +if (typeof exports === 'object') { + exports.connect = connect; +} else { + window.socketio = {connect}; +} diff --git a/src/static/js/timeslider.js b/src/static/js/timeslider.js index 82ecd2fd3..e338b5cde 100644 --- a/src/static/js/timeslider.js +++ b/src/static/js/timeslider.js @@ -29,6 +29,7 @@ require('./jquery'); const Cookies = require('./pad_utils').Cookies; const randomString = require('./pad_utils').randomString; const hooks = require('./pluginfw/hooks'); +const socketio = require('./socketio'); let token, padId, exportLinks, socket, changesetLoader, BroadcastSlider; @@ -51,14 +52,7 @@ const init = () => { Cookies.set('token', token, {expires: 60}); } - const loc = document.location; - // get the correct port - const port = loc.port === '' ? (loc.protocol === 'https:' ? 443 : 80) : loc.port; - // create the url - const url = `${loc.protocol}//${loc.hostname}:${port}/`; - - // build up the socket io connection - socket = io.connect(url, {path: `${exports.baseURL}socket.io`}); + socket = socketio.connect(exports.baseURL); // send the ready message once we're connected socket.on('connect', () => { diff --git a/src/templates/admin/plugins.html b/src/templates/admin/plugins.html index 204e74735..76b01acbb 100644 --- a/src/templates/admin/plugins.html +++ b/src/templates/admin/plugins.html @@ -6,6 +6,7 @@ + diff --git a/src/templates/admin/settings.html b/src/templates/admin/settings.html index 74e259ffb..a75a9168a 100644 --- a/src/templates/admin/settings.html +++ b/src/templates/admin/settings.html @@ -6,6 +6,7 @@ +