diff --git a/src/components/Editor.vue b/src/components/Editor.vue index 25c1d1e44a0..b15a15b0920 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -354,12 +354,12 @@ export default { } unsubscribe('text:image-node:add', this.onAddImageNode) unsubscribe('text:image-node:delete', this.onDeleteImageNode) + unsubscribe('text:translate-modal:show', this.showTranslateModal) if (this.dirty) { const timeout = new Promise((resolve) => setTimeout(resolve, 2000)) await Promise.any([timeout, this.$syncService.save()]) } - this.$providers.forEach(p => p.destroy()) - unsubscribe('text:translate-modal:show', this.showTranslateModal) + this.close() }, methods: { initSession() { @@ -383,8 +383,6 @@ export default { this.listenSyncServiceEvents() - this.$providers.forEach(p => p?.destroy()) - this.$providers = [] const syncServiceProvider = createSyncServiceProvider({ ydoc: this.$ydoc, syncService: this.$syncService, @@ -432,7 +430,7 @@ export default { reconnect() { this.contentLoaded = false this.hasConnectionIssue = false - this.close().then(this.initSession) + this.disconnect().then(this.initSession) this.idle = false }, @@ -662,14 +660,19 @@ export default { await this.$syncService.save() }, + async disconnect() { + await this.$syncService.close() + this.unlistenSyncServiceEvents() + this.$providers.forEach(p => p?.destroy()) + this.$providers = [] + this.$syncService = null + // disallow editing while still showing the content + this.readOnly = true + }, + async close() { - if (this.currentSession && this.$syncService) { - await this.$syncService.close() - this.unlistenSyncServiceEvents() - this.$syncService = null - // disallow editing while still showing the content - this.readOnly = true - } + await this.$syncService.sendRemainingSteps(this.$queue) + await this.disconnect() if (this.$editor) { try { this.unlistenEditorEvents() diff --git a/src/services/SyncService.js b/src/services/SyncService.js index 52029465ac4..db37c133f90 100644 --- a/src/services/SyncService.js +++ b/src/services/SyncService.js @@ -10,6 +10,7 @@ import debounce from 'debounce' import PollingBackend from './PollingBackend.js' import SessionApi, { Connection } from './SessionApi.js' +import { encodeArrayBuffer } from '../helpers/base64.ts' import { logger } from '../helpers/logger.js' /** @@ -270,6 +271,29 @@ class SyncService { }) } + async sendRemainingSteps(queue) { + if (queue.length === 0) { + return + } + let outbox = [] + const steps = queue.map(s => encodeArrayBuffer(s)) + .filter(s => s < 'AQ') + const awareness = queue.map(s => encodeArrayBuffer(s)) + .findLast(s => s > 'AQ') || '' + return this.sendStepsNow(() => { + const data = { steps, awareness, version: this.version } + outbox = [...queue] + logger.debug('sending final steps ', data) + return data + })?.then(() => { + // only keep the steps that were not send yet + queue.splice(0, + queue.length, + ...queue.filter(s => !outbox.includes(s)), + ) + }, err => logger.error(err)) + } + async close() { // Make sure to leave no pending requests behind. this.autosave.clear() diff --git a/src/services/WebSocketPolyfill.js b/src/services/WebSocketPolyfill.js index 32eb0b96f68..aaad3df6a4b 100644 --- a/src/services/WebSocketPolyfill.js +++ b/src/services/WebSocketPolyfill.js @@ -97,37 +97,12 @@ export default function initWebSocketPolyfill(syncService, fileId, initialSessio } async close() { - await this.#sendRemainingSteps() Object.entries(this.#handlers) .forEach(([key, value]) => syncService.off(key, value)) this.#handlers = [] - syncService.close().then(() => { - this.onclose() - }) + this.onclose() logger.debug('Websocket closed') } - #sendRemainingSteps() { - if (queue.length) { - let outbox = [] - return syncService.sendStepsNow(() => { - const data = { - steps: this.#steps, - awareness: this.#awareness, - version: this.#version, - } - outbox = [...queue] - logger.debug('sending final steps ', data) - return data - })?.then(() => { - // only keep the steps that were not send yet - queue.splice(0, - queue.length, - ...queue.filter(s => !outbox.includes(s)), - ) - }, err => logger.error(err)) - } - } - } }