diff --git a/src/components/Editor.vue b/src/components/Editor.vue index fb3497e1a06..05133005f9d 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -578,7 +578,7 @@ export default { }, onSync({ steps, document }) { - this.hasConnectionIssue = !this.$providers[0].wsconnected || this.$syncService.pushError > 0 + this.hasConnectionIssue = this.$syncService.backend.fetcher === 0 || !this.$providers[0].wsconnected || this.$syncService.pushError > 0 this.$nextTick(() => { this.emit('sync-service:sync') }) diff --git a/src/services/SyncService.js b/src/services/SyncService.js index 3921b7115a3..577b932294d 100644 --- a/src/services/SyncService.js +++ b/src/services/SyncService.js @@ -109,10 +109,19 @@ class SyncService { return this.#connection && !this.#connection.isClosed } + get connectionState() { + if (!this.#connection || this.version === undefined) { + return null + } + return { + ...this.#connection.state, + version: this.version, + } + } + async open({ fileId, initialSession }) { if (this.hasActiveConnection) { - // We're already connected. - return + return this.connectionState } const connect = initialSession ? Promise.resolve(new Connection({ data: initialSession }, {})) @@ -121,19 +130,15 @@ class SyncService { this.#connection = await connect if (!this.#connection) { // Error was already emitted in connect - return + return null } this.backend = new PollingBackend(this, this.#connection) this.version = this.#connection.docStateVersion this.baseVersionEtag = this.#connection.document.baseVersionEtag - this.emit('opened', { - ...this.#connection.state, - version: this.version, - }) - this.emit('loaded', { - ...this.#connection.state, - version: this.version, - }) + this.emit('opened', this.connectionState) + this.emit('loaded', this.connectionState) + + return this.connectionState } startSync() { diff --git a/src/services/WebSocketPolyfill.js b/src/services/WebSocketPolyfill.js index 8394b8dfaa3..861204dfc9d 100644 --- a/src/services/WebSocketPolyfill.js +++ b/src/services/WebSocketPolyfill.js @@ -47,15 +47,11 @@ export default function initWebSocketPolyfill(syncService, fileId, initialSessio constructor(url) { this.url = url logger.debug('WebSocketPolyfill#constructor', { url, fileId, initialSession }) - if (syncService.hasActiveConnection) { - setTimeout(() => this.onopen?.(), 0) - } this.#registerHandlers({ opened: ({ version, session }) => { - this.#version = version logger.debug('opened ', { version, session }) + this.#version = version this.#session = session - this.onopen?.() }, loaded: ({ version, session, content }) => { logger.debug('loaded ', { version, session }) @@ -73,7 +69,16 @@ export default function initWebSocketPolyfill(syncService, fileId, initialSessio } }, }) - syncService.open({ fileId, initialSession }) + + syncService.open({ fileId, initialSession }).then((data) => { + if (syncService.hasActiveConnection) { + const { version, session } = data + this.#version = version + this.#session = session + + this.onopen?.() + } + }) } #registerHandlers(handlers) { diff --git a/src/tests/services/WebsocketPolyfill.spec.js b/src/tests/services/WebsocketPolyfill.spec.js index 1536d6e6992..060bab71e67 100644 --- a/src/tests/services/WebsocketPolyfill.spec.js +++ b/src/tests/services/WebsocketPolyfill.spec.js @@ -3,21 +3,21 @@ import initWebSocketPolyfill from '../../services/WebSocketPolyfill.js' describe('Init function', () => { it('returns a websocket polyfill class', () => { - const syncService = { on: jest.fn(), open: jest.fn() } + const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) } const Polyfill = initWebSocketPolyfill(syncService) const websocket = new Polyfill('url') expect(websocket).toBeInstanceOf(Polyfill) }) it('registers handlers', () => { - const syncService = { on: jest.fn(), open: jest.fn() } + const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) } const Polyfill = initWebSocketPolyfill(syncService) const websocket = new Polyfill('url') expect(syncService.on).toHaveBeenCalled() }) it('opens sync service', () => { - const syncService = { on: jest.fn(), open: jest.fn() } + const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) } const fileId = 123 const initialSession = { } const Polyfill = initWebSocketPolyfill(syncService, fileId, initialSession) @@ -28,7 +28,7 @@ describe('Init function', () => { it('sends steps to sync service', async () => { const syncService = { on: jest.fn(), - open: jest.fn(), + open: jest.fn(() => Promise.resolve({ version: 123, session: {} })), sendSteps: async getData => getData(), } const queue = [ 'initial' ] @@ -46,9 +46,10 @@ describe('Init function', () => { }) it('handles early reject', async () => { + jest.spyOn(console, 'error').mockImplementation(() => {}) const syncService = { on: jest.fn(), - open: jest.fn(), + open: jest.fn(() => Promise.resolve({ version: 123, session: {} })), sendSteps: jest.fn().mockRejectedValue('error before reading steps in sync service'), } const queue = [ 'initial' ] @@ -64,9 +65,10 @@ describe('Init function', () => { }) it('handles reject after reading data', async () => { + jest.spyOn(console, 'error').mockImplementation(() => {}) const syncService = { on: jest.fn(), - open: jest.fn(), + open: jest.fn(() => Promise.resolve({ version: 123, session: {} })), sendSteps: jest.fn().mockImplementation( async getData => { getData() throw 'error when sending in sync service' @@ -85,9 +87,10 @@ describe('Init function', () => { }) it('queue survives a close', async () => { + jest.spyOn(console, 'error').mockImplementation(() => {}) const syncService = { on: jest.fn(), - open: jest.fn(), + open: jest.fn(() => Promise.resolve({ version: 123, session: {} })), sendSteps: jest.fn().mockImplementation( async getData => { getData() throw 'error when sending in sync service'