Skip to content

Commit 6bd8b24

Browse files
juliusknorrmejo-
authored andcommitted
fix: Ensure WebsocketPolyfill always has the latest session state and version
Signed-off-by: Julius Härtl <[email protected]>
1 parent 943b55d commit 6bd8b24

4 files changed

Lines changed: 38 additions & 25 deletions

File tree

src/components/Editor.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ export default {
578578
},
579579
580580
onSync({ steps, document }) {
581-
this.hasConnectionIssue = !this.$providers[0].wsconnected || this.$syncService.pushError > 0
581+
this.hasConnectionIssue = this.$syncService.backend.fetcher === 0 || !this.$providers[0].wsconnected || this.$syncService.pushError > 0
582582
this.$nextTick(() => {
583583
this.emit('sync-service:sync')
584584
})

src/services/SyncService.js

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,19 @@ class SyncService {
109109
return this.#connection && !this.#connection.isClosed
110110
}
111111

112+
get connectionState() {
113+
if (!this.#connection || this.version === undefined) {
114+
return null
115+
}
116+
return {
117+
...this.#connection.state,
118+
version: this.version,
119+
}
120+
}
121+
112122
async open({ fileId, initialSession }) {
113123
if (this.hasActiveConnection) {
114-
// We're already connected.
115-
return
124+
return this.connectionState
116125
}
117126
const connect = initialSession
118127
? Promise.resolve(new Connection({ data: initialSession }, {}))
@@ -121,19 +130,15 @@ class SyncService {
121130
this.#connection = await connect
122131
if (!this.#connection) {
123132
// Error was already emitted in connect
124-
return
133+
return null
125134
}
126135
this.backend = new PollingBackend(this, this.#connection)
127136
this.version = this.#connection.docStateVersion
128137
this.baseVersionEtag = this.#connection.document.baseVersionEtag
129-
this.emit('opened', {
130-
...this.#connection.state,
131-
version: this.version,
132-
})
133-
this.emit('loaded', {
134-
...this.#connection.state,
135-
version: this.version,
136-
})
138+
this.emit('opened', this.connectionState)
139+
this.emit('loaded', this.connectionState)
140+
141+
return this.connectionState
137142
}
138143

139144
startSync() {

src/services/WebSocketPolyfill.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,11 @@ export default function initWebSocketPolyfill(syncService, fileId, initialSessio
4747
constructor(url) {
4848
this.url = url
4949
logger.debug('WebSocketPolyfill#constructor', { url, fileId, initialSession })
50-
if (syncService.hasActiveConnection) {
51-
setTimeout(() => this.onopen?.(), 0)
52-
}
5350
this.#registerHandlers({
5451
opened: ({ version, session }) => {
55-
this.#version = version
5652
logger.debug('opened ', { version, session })
53+
this.#version = version
5754
this.#session = session
58-
this.onopen?.()
5955
},
6056
loaded: ({ version, session, content }) => {
6157
logger.debug('loaded ', { version, session })
@@ -73,7 +69,16 @@ export default function initWebSocketPolyfill(syncService, fileId, initialSessio
7369
}
7470
},
7571
})
76-
syncService.open({ fileId, initialSession })
72+
73+
syncService.open({ fileId, initialSession }).then((data) => {
74+
if (syncService.hasActiveConnection) {
75+
const { version, session } = data
76+
this.#version = version
77+
this.#session = session
78+
79+
this.onopen?.()
80+
}
81+
})
7782
}
7883

7984
#registerHandlers(handlers) {

src/tests/services/WebsocketPolyfill.spec.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@ import initWebSocketPolyfill from '../../services/WebSocketPolyfill.js'
33
describe('Init function', () => {
44

55
it('returns a websocket polyfill class', () => {
6-
const syncService = { on: jest.fn(), open: jest.fn() }
6+
const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) }
77
const Polyfill = initWebSocketPolyfill(syncService)
88
const websocket = new Polyfill('url')
99
expect(websocket).toBeInstanceOf(Polyfill)
1010
})
1111

1212
it('registers handlers', () => {
13-
const syncService = { on: jest.fn(), open: jest.fn() }
13+
const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) }
1414
const Polyfill = initWebSocketPolyfill(syncService)
1515
const websocket = new Polyfill('url')
1616
expect(syncService.on).toHaveBeenCalled()
1717
})
1818

1919
it('opens sync service', () => {
20-
const syncService = { on: jest.fn(), open: jest.fn() }
20+
const syncService = { on: jest.fn(), open: jest.fn(() => Promise.resolve({ version: 123, session: {} })) }
2121
const fileId = 123
2222
const initialSession = { }
2323
const Polyfill = initWebSocketPolyfill(syncService, fileId, initialSession)
@@ -28,7 +28,7 @@ describe('Init function', () => {
2828
it('sends steps to sync service', async () => {
2929
const syncService = {
3030
on: jest.fn(),
31-
open: jest.fn(),
31+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
3232
sendSteps: async getData => getData(),
3333
}
3434
const queue = [ 'initial' ]
@@ -46,9 +46,10 @@ describe('Init function', () => {
4646
})
4747

4848
it('handles early reject', async () => {
49+
jest.spyOn(console, 'error').mockImplementation(() => {})
4950
const syncService = {
5051
on: jest.fn(),
51-
open: jest.fn(),
52+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
5253
sendSteps: jest.fn().mockRejectedValue('error before reading steps in sync service'),
5354
}
5455
const queue = [ 'initial' ]
@@ -64,9 +65,10 @@ describe('Init function', () => {
6465
})
6566

6667
it('handles reject after reading data', async () => {
68+
jest.spyOn(console, 'error').mockImplementation(() => {})
6769
const syncService = {
6870
on: jest.fn(),
69-
open: jest.fn(),
71+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
7072
sendSteps: jest.fn().mockImplementation( async getData => {
7173
getData()
7274
throw 'error when sending in sync service'
@@ -85,9 +87,10 @@ describe('Init function', () => {
8587
})
8688

8789
it('queue survives a close', async () => {
90+
jest.spyOn(console, 'error').mockImplementation(() => {})
8891
const syncService = {
8992
on: jest.fn(),
90-
open: jest.fn(),
93+
open: jest.fn(() => Promise.resolve({ version: 123, session: {} })),
9194
sendSteps: jest.fn().mockImplementation( async getData => {
9295
getData()
9396
throw 'error when sending in sync service'

0 commit comments

Comments
 (0)