reconnect when no message received in a long time
This commit is contained in:
parent
397164d7bc
commit
953aa592fe
@ -64,6 +64,7 @@ class WSSharedDoc extends Y.Doc {
|
|||||||
* @type {awarenessProtocol.Awareness}
|
* @type {awarenessProtocol.Awareness}
|
||||||
*/
|
*/
|
||||||
this.awareness = new awarenessProtocol.Awareness(this)
|
this.awareness = new awarenessProtocol.Awareness(this)
|
||||||
|
this.awareness.setLocalState(null)
|
||||||
/**
|
/**
|
||||||
* @param {{ added: Array<number>, updated: Array<number>, removed: Array<number> }} changes
|
* @param {{ added: Array<number>, updated: Array<number>, removed: Array<number> }} changes
|
||||||
* @param {Object | null} conn Origin is the connection that made the change
|
* @param {Object | null} conn Origin is the connection that made the change
|
||||||
|
|||||||
18
package-lock.json
generated
18
package-lock.json
generated
@ -995,9 +995,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.11",
|
"version": "4.17.15",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
|
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"loose-envify": {
|
"loose-envify": {
|
||||||
@ -1699,17 +1699,17 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"y-protocols": {
|
"y-protocols": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-0.0.7.tgz",
|
||||||
"integrity": "sha512-XgUBKrFesfUYN3wXmVp9Exy7dOUOeX3A56gHNuI1ZNy9N7OdwoBv2TGfbvSH6+YpV1IEvEq7u5v0/je5MwXKJg==",
|
"integrity": "sha512-vimoF3v/H9kMRBKQcbYppObK6FUITPL+huyvbYdPhLiLTSSm5dS7/BT1E/Wyl488CyoPoZTxiOqfu1WphwTe6A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lib0": "0.0.5"
|
"lib0": "0.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"yjs": {
|
"yjs": {
|
||||||
"version": "13.0.0-83",
|
"version": "13.0.0-94",
|
||||||
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.0.0-83.tgz",
|
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.0.0-94.tgz",
|
||||||
"integrity": "sha512-8M1X8fZ95odf2VU8BHrKcYr0PeEsx8tspV5svh4oLp8BVcIprbp0J2hzCvJDlOFOlyJVgvNf00UJ4uiyDKmk5A==",
|
"integrity": "sha512-4HETCv/BZ4Mg9rZU+nLZXW8GGp9ugWDA1ImcyIW2hZA2n0YsIgwvROPqWpflwi/l02kfLlvLKF8nEXYk/cOsjQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"lib0": "0.0.5"
|
"lib0": "0.0.5"
|
||||||
|
|||||||
@ -40,17 +40,17 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"y-protocols": "0.0.6",
|
"y-protocols": "0.0.7",
|
||||||
"lib0": "0.0.5"
|
"lib0": "0.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"rollup": "^1.1.2",
|
"rollup": "^1.1.2",
|
||||||
"rollup-cli": "^1.0.9",
|
"rollup-cli": "^1.0.9",
|
||||||
"standard": "^12.0.1",
|
"standard": "^12.0.1",
|
||||||
"yjs": "13.0.0-83"
|
"yjs": "13.0.0-94"
|
||||||
},
|
},
|
||||||
"peerDependenies": {
|
"peerDependenies": {
|
||||||
"yjs": ">=13.0.0-83"
|
"yjs": ">=13.0.0-94"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"ws": "^6.2.1"
|
"ws": "^6.2.1"
|
||||||
|
|||||||
@ -10,6 +10,7 @@ Unlike stated in the LICENSE file, it is not necessary to include the copyright
|
|||||||
|
|
||||||
import * as Y from 'yjs' // eslint-disable-line
|
import * as Y from 'yjs' // eslint-disable-line
|
||||||
import * as bc from 'lib0/broadcastchannel.js'
|
import * as bc from 'lib0/broadcastchannel.js'
|
||||||
|
import * as time from 'lib0/time.js'
|
||||||
import * as encoding from 'lib0/encoding.js'
|
import * as encoding from 'lib0/encoding.js'
|
||||||
import * as decoding from 'lib0/decoding.js'
|
import * as decoding from 'lib0/decoding.js'
|
||||||
import * as syncProtocol from 'y-protocols/sync.js'
|
import * as syncProtocol from 'y-protocols/sync.js'
|
||||||
@ -17,13 +18,17 @@ import * as authProtocol from 'y-protocols/auth.js'
|
|||||||
import * as awarenessProtocol from 'y-protocols/awareness.js'
|
import * as awarenessProtocol from 'y-protocols/awareness.js'
|
||||||
import * as mutex from 'lib0/mutex.js'
|
import * as mutex from 'lib0/mutex.js'
|
||||||
import { Observable } from 'lib0/observable.js'
|
import { Observable } from 'lib0/observable.js'
|
||||||
|
import * as math from 'lib0/math.js'
|
||||||
|
|
||||||
const messageSync = 0
|
const messageSync = 0
|
||||||
const messageQueryAwareness = 3
|
const messageQueryAwareness = 3
|
||||||
const messageAwareness = 1
|
const messageAwareness = 1
|
||||||
const messageAuth = 2
|
const messageAuth = 2
|
||||||
|
|
||||||
const reconnectTimeout = 3000
|
const reconnectTimeoutBase = 1200
|
||||||
|
const maxReconnectTimeout = 2500
|
||||||
|
// @todo - this should depend on awareness.outdatedTime
|
||||||
|
const messageReconnectTimeout = 30000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {WebsocketProvider} provider
|
* @param {WebsocketProvider} provider
|
||||||
@ -73,6 +78,7 @@ const setupWS = provider => {
|
|||||||
provider.wsconnecting = true
|
provider.wsconnecting = true
|
||||||
provider.wsconnected = false
|
provider.wsconnected = false
|
||||||
websocket.onmessage = event => {
|
websocket.onmessage = event => {
|
||||||
|
provider.wsLastMessageReceived = time.getUnixTime()
|
||||||
const encoder = readMessage(provider, new Uint8Array(event.data))
|
const encoder = readMessage(provider, new Uint8Array(event.data))
|
||||||
if (encoding.length(encoder) > 1) {
|
if (encoding.length(encoder) > 1) {
|
||||||
websocket.send(encoding.toUint8Array(encoder))
|
websocket.send(encoding.toUint8Array(encoder))
|
||||||
@ -81,19 +87,27 @@ const setupWS = provider => {
|
|||||||
websocket.onclose = () => {
|
websocket.onclose = () => {
|
||||||
provider.ws = null
|
provider.ws = null
|
||||||
provider.wsconnecting = false
|
provider.wsconnecting = false
|
||||||
provider.wsconnected = false
|
|
||||||
if (provider.wsconnected) {
|
if (provider.wsconnected) {
|
||||||
|
provider.wsconnected = false
|
||||||
// update awareness (all users left)
|
// update awareness (all users left)
|
||||||
awarenessProtocol.removeAwarenessStates(provider.awareness, Array.from(provider.awareness.getStates().keys()), provider)
|
awarenessProtocol.removeAwarenessStates(provider.awareness, Array.from(provider.awareness.getStates().keys()), provider)
|
||||||
provider.emit('status', [{
|
provider.emit('status', [{
|
||||||
status: 'disconnected'
|
status: 'disconnected'
|
||||||
}])
|
}])
|
||||||
|
} else {
|
||||||
|
provider.wsUnsuccessfulReconnects++
|
||||||
}
|
}
|
||||||
setTimeout(setupWS, reconnectTimeout, provider)
|
// Start with no reconnect timeout and increase timeout by
|
||||||
|
// log10(wsUnsuccessfulReconnects).
|
||||||
|
// The idea is to increase reconnect timeout slowly and have no reconnect
|
||||||
|
// timeout at the beginning (log(1) = 0)
|
||||||
|
setTimeout(setupWS, math.min(Math.log10(provider.wsUnsuccessfulReconnects + 1) * reconnectTimeoutBase, maxReconnectTimeout), provider)
|
||||||
}
|
}
|
||||||
websocket.onopen = () => {
|
websocket.onopen = () => {
|
||||||
|
provider.wsLastMessageReceived = time.getUnixTime()
|
||||||
provider.wsconnecting = false
|
provider.wsconnecting = false
|
||||||
provider.wsconnected = true
|
provider.wsconnected = true
|
||||||
|
provider.wsUnsuccessfulReconnects = 0
|
||||||
provider.emit('status', [{
|
provider.emit('status', [{
|
||||||
status: 'connected'
|
status: 'connected'
|
||||||
}])
|
}])
|
||||||
@ -167,11 +181,13 @@ export class WebsocketProvider extends Observable {
|
|||||||
this.wsconnected = false
|
this.wsconnected = false
|
||||||
this.wsconnecting = false
|
this.wsconnecting = false
|
||||||
this.bcconnected = false
|
this.bcconnected = false
|
||||||
|
this.wsUnsuccessfulReconnects = 0
|
||||||
this.mux = mutex.createMutex()
|
this.mux = mutex.createMutex()
|
||||||
/**
|
/**
|
||||||
* @type {WebSocket?}
|
* @type {WebSocket?}
|
||||||
*/
|
*/
|
||||||
this.ws = null
|
this.ws = null
|
||||||
|
this.wsLastMessageReceived = 0
|
||||||
/**
|
/**
|
||||||
* Whether to connect to other peers or not
|
* Whether to connect to other peers or not
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@ -219,9 +235,17 @@ export class WebsocketProvider extends Observable {
|
|||||||
broadcastMessage(this, encoding.toUint8Array(encoder))
|
broadcastMessage(this, encoding.toUint8Array(encoder))
|
||||||
})
|
})
|
||||||
awareness.on('change', this._awarenessUpdateHandler)
|
awareness.on('change', this._awarenessUpdateHandler)
|
||||||
|
this._checkInterval = setInterval(() => {
|
||||||
|
if (this.wsconnected && messageReconnectTimeout < time.getUnixTime() - this.wsLastMessageReceived) {
|
||||||
|
// no message received in a long time - not even your own awareness
|
||||||
|
// updates (which are updated every 15 seconds)
|
||||||
|
/** @type {WebSocket} */ (this.ws).close()
|
||||||
|
}
|
||||||
|
})
|
||||||
this.connect()
|
this.connect()
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
|
clearInterval(this._checkInterval)
|
||||||
this.disconnect()
|
this.disconnect()
|
||||||
this.awareness.off('change', this._awarenessUpdateHandler)
|
this.awareness.off('change', this._awarenessUpdateHandler)
|
||||||
super.destroy()
|
super.destroy()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user