From c87d83553301a41f53ed35a2253a34f4b4af0a6d Mon Sep 17 00:00:00 2001 From: George Gevoian Date: Tue, 2 Apr 2024 22:24:50 -0700 Subject: [PATCH] (core) Update WS deps after grist-core sync Summary: Some WS-related code was touched in a recent PR to grist-core. This extends those changes to the rest of the codebase so that builds work again. Test Plan: N/A Reviewers: dsagal Reviewed By: dsagal Subscribers: dsagal Differential Revision: https://phab.getgrist.com/D4224 --- app/client/components/GristClientSocket.ts | 9 ++++-- app/client/components/GristWSConnection.ts | 32 +++++++++++++++------- app/server/lib/GristSocketServer.ts | 2 +- app/server/lib/requestUtils.ts | 2 +- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/app/client/components/GristClientSocket.ts b/app/client/components/GristClientSocket.ts index b7eb27da..ed2d2d6f 100644 --- a/app/client/components/GristClientSocket.ts +++ b/app/client/components/GristClientSocket.ts @@ -56,7 +56,8 @@ export class GristClientSocket { } } - // pause() and resume() are used for tests and assume a WS.WebSocket transport + // pause(), resume(), and isOpen() are only used by tests and assume + // a WS.WebSocket transport. public pause() { (this._wsSocket as WS.WebSocket)?.pause(); } @@ -65,6 +66,10 @@ export class GristClientSocket { (this._wsSocket as WS.WebSocket)?.resume(); } + public isOpen() { + return (this._wsSocket as WS.WebSocket)?.readyState === WS.OPEN; + } + private _createWSSocket() { if (typeof WebSocket !== 'undefined') { this._wsSocket = new WebSocket(this._url); @@ -149,4 +154,4 @@ export class GristClientSocket { private _onEIOClose() { this._closeHandler?.(); } -} \ No newline at end of file +} diff --git a/app/client/components/GristWSConnection.ts b/app/client/components/GristWSConnection.ts index f1d77732..912cd336 100644 --- a/app/client/components/GristWSConnection.ts +++ b/app/client/components/GristWSConnection.ts @@ -330,6 +330,15 @@ export class GristWSConnection extends Disposable { this._reconnectAttempts++; } + let url: string; + try { + url = this._buildWebsocketUrl(isReconnecting, timezone); + } catch (e) { + this._warn('Failed to get the URL for the worker serving the document'); + this._scheduleReconnect(isReconnecting); + return; + } + // Note that if a WebSocket can't establish a connection it will trigger onclose() // As per http://dev.w3.org/html5/websockets/ // "If the establish a WebSocket connection algorithm fails, @@ -337,7 +346,6 @@ export class GristWSConnection extends Disposable { // which then invokes the close the WebSocket connection algorithm, // which then establishes that the WebSocket connection is closed, // which fires the close event." - const url = this._buildWebsocketUrl(isReconnecting, timezone); this._log("GristWSConnection connecting to: " + url); this._ws = this._settings.makeWebSocket(url); @@ -367,18 +375,22 @@ export class GristWSConnection extends Disposable { this.trigger('connectState', false); if (!this._wantReconnect) { return; } - const reconnectTimeout = gutil.getReconnectTimeout(this._reconnectAttempts, reconnectInterval); - this._log("Trying to reconnect in", reconnectTimeout, "ms"); - this.trigger('connectionStatus', 'Trying to reconnect...', 'WARNING'); - this._reconnectTimeout = setTimeout(async () => { - this._reconnectTimeout = null; - // Make sure we've gotten through all lazy-loading. - await this._initialConnection; - await this.connect(true); - }, reconnectTimeout); + this._scheduleReconnect(true); }; } + private _scheduleReconnect(isReconnecting: boolean) { + const reconnectTimeout = gutil.getReconnectTimeout(this._reconnectAttempts, reconnectInterval); + this._log('Trying to reconnect in', reconnectTimeout, 'ms'); + this.trigger('connectionStatus', 'Trying to reconnect...', 'WARNING'); + this._reconnectTimeout = setTimeout(async () => { + this._reconnectTimeout = null; + // Make sure we've gotten through all lazy-loading. + await this._initialConnection; + await this.connect(isReconnecting); + }, reconnectTimeout); + } + private _buildWebsocketUrl(isReconnecting: boolean, timezone: any): string { const url = new URL(this.docWorkerUrl); url.protocol = (url.protocol === 'https:') ? 'wss:' : 'ws:'; diff --git a/app/server/lib/GristSocketServer.ts b/app/server/lib/GristSocketServer.ts index aab417d6..5a098f06 100644 --- a/app/server/lib/GristSocketServer.ts +++ b/app/server/lib/GristSocketServer.ts @@ -108,4 +108,4 @@ export class GristSocketServer { (socket as any).request = null; // Free initial request as recommended in the Engine.IO documentation this._connectionHandler?.(new GristServerSocketEIO(socket), req); } -} \ No newline at end of file +} diff --git a/app/server/lib/requestUtils.ts b/app/server/lib/requestUtils.ts index 0b928f93..e7cd3a10 100644 --- a/app/server/lib/requestUtils.ts +++ b/app/server/lib/requestUtils.ts @@ -350,7 +350,7 @@ export function getEndUserProtocol(req: IncomingMessage) { } // TODO we shouldn't blindly trust X-Forwarded-Proto. See the Express approach: // https://expressjs.com/en/5x/api.html#trust.proxy.options.table - return req.headers["x-forwarded-proto"] || ((req.socket as TLSSocket).encrypted ? 'https' : 'http'); + return req.headers["x-forwarded-proto"] || ((req.socket as TLSSocket)?.encrypted ? 'https' : 'http'); } /**