Skip to content

Commit 132b671

Browse files
authored
Merge pull request #6241 from nextcloud/backport/6217/stable30
[stable30] fix: Ensure WebsocketPolyfill always has the latest session state and version
2 parents 7a8fabe + 98765fc commit 132b671

File tree

4 files changed

+38
-25
lines changed

4 files changed

+38
-25
lines changed

src/components/Editor.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ export default {
566566
},
567567

568568
onSync({ steps, document }) {
569-
this.hasConnectionIssue = !this.$providers[0].wsconnected || this.$syncService.pushError > 0
569+
this.hasConnectionIssue = this.$syncService.backend.fetcher === 0 || !this.$providers[0].wsconnected || this.$syncService.pushError > 0
570570
this.$nextTick(() => {
571571
this.emit('sync-service:sync')
572572
})

src/services/SyncService.js

+16-11
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,19 @@ class SyncService {
9494
return this.#connection && !this.#connection.isClosed
9595
}
9696

97+
get connectionState() {
98+
if (!this.#connection || this.version === undefined) {
99+
return null
100+
}
101+
return {
102+
...this.#connection.state,
103+
version: this.version,
104+
}
105+
}
106+
97107
async open({ fileId, initialSession }) {
98108
if (this.hasActiveConnection) {
99-
// We're already connected.
100-
return
109+
return this.connectionState
101110
}
102111
const connect = initialSession
103112
? Promise.resolve(new Connection({ data: initialSession }, {}))
@@ -106,19 +115,15 @@ class SyncService {
106115
this.#connection = await connect
107116
if (!this.#connection) {
108117
// Error was already emitted in connect
109-
return
118+
return null
110119
}
111120
this.backend = new PollingBackend(this, this.#connection)
112121
this.version = this.#connection.docStateVersion
113122
this.baseVersionEtag = this.#connection.document.baseVersionEtag
114-
this.emit('opened', {
115-
...this.#connection.state,
116-
version: this.version,
117-
})
118-
this.emit('loaded', {
119-
...this.#connection.state,
120-
version: this.version,
121-
})
123+
this.emit('opened', this.connectionState)
124+
this.emit('loaded', this.connectionState)
125+
126+
return this.connectionState
122127
}
123128

124129
startSync() {

src/services/WebSocketPolyfill.js

+11-6
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,11 @@ export default function initWebSocketPolyfill(syncService, fileId, initialSessio
3434
this.#notifyPushBus?.on('notify_push', this.#onNotifyPush.bind(this))
3535
this.url = url
3636
logger.debug('WebSocketPolyfill#constructor', { url, fileId, initialSession })
37-
if (syncService.hasActiveConnection) {
38-
setTimeout(() => this.onopen?.(), 0)
39-
}
4037
this.#registerHandlers({
4138
opened: ({ version, session }) => {
42-
this.#version = version
4339
logger.debug('opened ', { version, session })
40+
this.#version = version
4441
this.#session = session
45-
this.onopen?.()
4642
},
4743
loaded: ({ version, session, content }) => {
4844
logger.debug('loaded ', { version, session })
@@ -60,7 +56,16 @@ export default function initWebSocketPolyfill(syncService, fileId, initialSessio
6056
}
6157
},
6258
})
63-
syncService.open({ fileId, initialSession })
59+
60+
syncService.open({ fileId, initialSession }).then((data) => {
61+
if (syncService.hasActiveConnection) {
62+
const { version, session } = data
63+
this.#version = version
64+
this.#session = session
65+
66+
this.onopen?.()
67+
}
68+
})
6469
}
6570

6671
#registerHandlers(handlers) {

src/tests/services/WebsocketPolyfill.spec.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,21 @@ import initWebSocketPolyfill from '../../services/WebSocketPolyfill.js'
88
describe('Init function', () => {
99

1010
it('returns a websocket polyfill class', () => {
11-
const syncService = { on: jest.fn(), open: jest.fn() }
11+
const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) }
1212
const Polyfill = initWebSocketPolyfill(syncService)
1313
const websocket = new Polyfill('url')
1414
expect(websocket).toBeInstanceOf(Polyfill)
1515
})
1616

1717
it('registers handlers', () => {
18-
const syncService = { on: jest.fn(), open: jest.fn() }
18+
const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) }
1919
const Polyfill = initWebSocketPolyfill(syncService)
2020
const websocket = new Polyfill('url')
2121
expect(syncService.on).toHaveBeenCalled()
2222
})
2323

2424
it('opens sync service', () => {
25-
const syncService = { on: jest.fn(), open: jest.fn() }
25+
const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) }
2626
const fileId = 123
2727
const initialSession = { }
2828
const Polyfill = initWebSocketPolyfill(syncService, fileId, initialSession)
@@ -33,7 +33,7 @@ describe('Init function', () => {
3333
it('sends steps to sync service', async () => {
3434
const syncService = {
3535
on: jest.fn(),
36-
open: jest.fn(),
36+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
3737
sendSteps: async getData => getData(),
3838
}
3939
const queue = [ 'initial' ]
@@ -51,9 +51,10 @@ describe('Init function', () => {
5151
})
5252

5353
it('handles early reject', async () => {
54+
jest.spyOn(console, 'error').mockImplementation(() => {})
5455
const syncService = {
5556
on: jest.fn(),
56-
open: jest.fn(),
57+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
5758
sendSteps: jest.fn().mockRejectedValue('error before reading steps in sync service'),
5859
}
5960
const queue = [ 'initial' ]
@@ -69,9 +70,10 @@ describe('Init function', () => {
6970
})
7071

7172
it('handles reject after reading data', async () => {
73+
jest.spyOn(console, 'error').mockImplementation(() => {})
7274
const syncService = {
7375
on: jest.fn(),
74-
open: jest.fn(),
76+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
7577
sendSteps: jest.fn().mockImplementation( async getData => {
7678
getData()
7779
throw 'error when sending in sync service'
@@ -90,9 +92,10 @@ describe('Init function', () => {
9092
})
9193

9294
it('queue survives a close', async () => {
95+
jest.spyOn(console, 'error').mockImplementation(() => {})
9396
const syncService = {
9497
on: jest.fn(),
95-
open: jest.fn(),
98+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
9699
sendSteps: jest.fn().mockImplementation( async getData => {
97100
getData()
98101
throw 'error when sending in sync service'

0 commit comments

Comments
 (0)