Skip to content

Commit

Permalink
fix(Editor): separate close and disconnect functions
Browse files Browse the repository at this point in the history
* `close` is for closing the editor.
  It tries to save the document and clean everything up.
* `disconnect` is for cleaning up the current collaboration sessions.
  It will not save the document and asumes the editing will be resumed
  after a reconnect.

Move `sendRemainingSteps` out to the sync service.
Also make close in the websocket polyfill sync.
Just clean up the polyfills state.

Signed-off-by: Max <max@nextcloud.com>
  • Loading branch information
max-nextcloud committed Jul 2, 2024
1 parent 97da812 commit e214f6f
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 38 deletions.
27 changes: 15 additions & 12 deletions src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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,
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -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()
Expand Down
24 changes: 24 additions & 0 deletions src/services/SyncService.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'

/**
Expand Down Expand Up @@ -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()
Expand Down
27 changes: 1 addition & 26 deletions src/services/WebSocketPolyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}

}
}

0 comments on commit e214f6f

Please sign in to comment.