Skip to content

Commit 70e8481

Browse files
committed
fix(sync): bump version after loading document state
* Emit the documents last saved version in the push response if document state is send as well. * Otherwise send the version as 0 so it cannot increase the sync service version. * Use the versions returned by create and push requests alongside the document state to construct a consistent step with the last saved version that matches the document state. This will result in the sync service version getting bumped to the documents last saved version once the coresponding document state has been processed. Signed-off-by: Max <max@nextcloud.com>
1 parent e6f2257 commit 70e8481

5 files changed

Lines changed: 20 additions & 12 deletions

File tree

cypress/component/helpers/yjs.cy.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ describe('Yjs base64 wrapped with our helpers', function() {
2121
sourceMap.set('keyA', 'valueA')
2222

2323
const stateA = getDocumentState(source)
24-
const step0A = documentStateToStep(stateA)
24+
const step0A = documentStateToStep(stateA, 123)
2525
applyStep(target, step0A)
2626
expect(targetMap.get('keyA')).to.be.eq('valueA')
2727

2828
// Add keyB to source, don't apply to target yet
2929
sourceMap.set('keyB', 'valueB')
3030
const stateB = getDocumentState(source)
31-
const step0B = documentStateToStep(stateB)
31+
const step0B = documentStateToStep(stateB, 124)
3232

3333
// Add keyC to source, apply to target
3434
sourceMap.set('keyC', 'valueC')

cypress/e2e/api/SessionApi.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe('The session Api', function() {
9393
const version = 0
9494
cy.pushSteps({ connection, steps, version })
9595
.its('version')
96-
.should('be.at.least', 1)
96+
.should('eql', 0)
9797
cy.syncSteps(connection)
9898
.its('steps[0].data')
9999
.should('eql', steps)
@@ -151,7 +151,7 @@ describe('The session Api', function() {
151151
it('saves', function() {
152152
cy.pushSteps({ connection, steps: [messages.update], version })
153153
.its('version')
154-
.should('be.at.least', 1)
154+
.should('be', 0)
155155
cy.save(connection, { version: 1, autosaveContent: '# Heading 1', manualSave: true })
156156
cy.downloadFile(filePath)
157157
.its('data')

lib/Service/DocumentService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ public function addStep(Document $document, Session $session, array $steps, int
265265

266266
return [
267267
'steps' => $stepsToReturn,
268-
'version' => $newVersion,
268+
'version' => isset($documentState) ? $document->getLastSavedVersion() : 0,
269269
'documentState' => $documentState
270270
];
271271
}

src/helpers/yjs.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ export function applyDocumentState(
4343
* and encode it and wrap it in a step data structure.
4444
*
4545
* @param documentState - base64 encoded doc state
46+
* @param version - last saved version for the document state
4647
* @return base64 encoded yjs sync protocol update message and version
4748
*/
48-
export function documentStateToStep(documentState: string): Step {
49+
export function documentStateToStep(documentState: string, version: number): Step {
4950
const message = documentStateToUpdateMessage(documentState)
50-
return { data: [encodeArrayBuffer(message)], sessionId: 0, version: -1 }
51+
return { data: [encodeArrayBuffer(message)], sessionId: 0, version }
5152
}
5253

5354
/**

src/services/SyncService.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,10 @@ class SyncService {
201201
this.bus.emit('loaded', connectionState)
202202
// Emit sync after opened, so websocket onmessage comes after onopen.
203203
if (connectionState.documentState) {
204-
this._emitDocumentStateStep(connectionState.documentState)
204+
this._emitDocumentStateStep(
205+
connectionState.documentState,
206+
connectionState.document.lastSavedVersion,
207+
)
205208
}
206209
return connectionState
207210
}
@@ -222,8 +225,8 @@ class SyncService {
222225
}
223226
}
224227

225-
_emitDocumentStateStep(documentState: string) {
226-
const documentStateStep = documentStateToStep(documentState)
228+
_emitDocumentStateStep(documentState: string, version: number) {
229+
const documentStateStep = documentStateToStep(documentState, version)
227230
this.bus.emit('sync', {
228231
steps: [documentStateStep],
229232
})
@@ -277,9 +280,13 @@ class SyncService {
277280
return this.connection?.push({ ...sendable, version: this.version })
278281
.then((response) => {
279282
this.#outbox.clearSentData(sendable)
280-
const { steps, documentState } = response.data
283+
const { steps, documentState, version } = response.data as {
284+
steps: Step[]
285+
documentState: string
286+
version: number
287+
}
281288
if (documentState) {
282-
this._emitDocumentStateStep(documentState)
289+
this._emitDocumentStateStep(documentState, version)
283290
}
284291
this.pushError = 0
285292
this.sending = false

0 commit comments

Comments
 (0)