Skip to content

Commit d3653d7

Browse files
committed
force recreation of websocket connection when a ws connection is manually closed
1 parent aa42204 commit d3653d7

File tree

1 file changed

+45
-31
lines changed

1 file changed

+45
-31
lines changed

src/y-websocket.js

+45-31
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,48 @@ const readMessage = (provider, buf, emitSynced) => {
124124
return encoder
125125
}
126126

127+
/**
128+
* Outsource this function so that a new websocket connection is created immediately.
129+
* I suspect that the `ws.onclose` event is not always fired if there are network issues.
130+
*
131+
* @param {WebsocketProvider} provider
132+
* @param {WebSocket} ws
133+
*/
134+
const closeWebsocketConnection = (provider, ws) => {
135+
if (ws === provider.ws) {
136+
provider.ws = null
137+
ws.close()
138+
provider.wsconnecting = false
139+
if (provider.wsconnected) {
140+
provider.wsconnected = false
141+
provider.synced = false
142+
// update awareness (all users except local left)
143+
awarenessProtocol.removeAwarenessStates(
144+
provider.awareness,
145+
Array.from(provider.awareness.getStates().keys()).filter((client) =>
146+
client !== provider.doc.clientID
147+
),
148+
provider
149+
)
150+
provider.emit('status', [{
151+
status: 'disconnected'
152+
}])
153+
} else {
154+
provider.wsUnsuccessfulReconnects++
155+
}
156+
// Start with no reconnect timeout and increase timeout by
157+
// using exponential backoff starting with 100ms
158+
setTimeout(
159+
setupWS,
160+
math.min(
161+
math.pow(2, provider.wsUnsuccessfulReconnects) * 100,
162+
provider.maxBackoffTime
163+
),
164+
provider
165+
)
166+
}
167+
}
168+
127169
/**
128170
* @param {WebsocketProvider} provider
129171
*/
@@ -148,35 +190,7 @@ const setupWS = (provider) => {
148190
}
149191
websocket.onclose = (event) => {
150192
provider.emit('connection-close', [event, provider])
151-
provider.ws = null
152-
provider.wsconnecting = false
153-
if (provider.wsconnected) {
154-
provider.wsconnected = false
155-
provider.synced = false
156-
// update awareness (all users except local left)
157-
awarenessProtocol.removeAwarenessStates(
158-
provider.awareness,
159-
Array.from(provider.awareness.getStates().keys()).filter((client) =>
160-
client !== provider.doc.clientID
161-
),
162-
provider
163-
)
164-
provider.emit('status', [{
165-
status: 'disconnected'
166-
}])
167-
} else {
168-
provider.wsUnsuccessfulReconnects++
169-
}
170-
// Start with no reconnect timeout and increase timeout by
171-
// using exponential backoff starting with 100ms
172-
setTimeout(
173-
setupWS,
174-
math.min(
175-
math.pow(2, provider.wsUnsuccessfulReconnects) * 100,
176-
provider.maxBackoffTime
177-
),
178-
provider
179-
)
193+
closeWebsocketConnection(provider, websocket)
180194
}
181195
websocket.onopen = () => {
182196
provider.wsLastMessageReceived = time.getUnixTime()
@@ -377,7 +391,7 @@ export class WebsocketProvider extends Observable {
377391
) {
378392
// no message received in a long time - not even your own awareness
379393
// updates (which are updated every 15 seconds)
380-
/** @type {WebSocket} */ (this.ws).close()
394+
closeWebsocketConnection(this, /** @type {WebSocket} */ (this.ws))
381395
}
382396
}, messageReconnectTimeout / 10))
383397
if (connect) {
@@ -484,7 +498,7 @@ export class WebsocketProvider extends Observable {
484498
this.shouldConnect = false
485499
this.disconnectBc()
486500
if (this.ws !== null) {
487-
this.ws.close()
501+
closeWebsocketConnection(this, this.ws)
488502
}
489503
}
490504

0 commit comments

Comments
 (0)