mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
add comments to reconnector.
This commit is contained in:
parent
7a7041625a
commit
e2db39fe69
@ -74,7 +74,7 @@ export class NekoConnection extends EventEmitter<NekoConnectionEvents> {
|
|||||||
|
|
||||||
this._onCloseHandle = this.close.bind(this)
|
this._onCloseHandle = this.close.bind(this)
|
||||||
|
|
||||||
// bind events to all reconnecters
|
// bind events to all reconnectors
|
||||||
Object.values(this._reconnector).forEach((r) => {
|
Object.values(this._reconnector).forEach((r) => {
|
||||||
r.on('connect', this._onConnectHandle)
|
r.on('connect', this._onConnectHandle)
|
||||||
r.on('disconnect', this._onDisconnectHandle)
|
r.on('disconnect', this._onDisconnectHandle)
|
||||||
@ -179,7 +179,7 @@ export class NekoConnection extends EventEmitter<NekoConnectionEvents> {
|
|||||||
|
|
||||||
Vue.set(this._state, 'status', 'connecting')
|
Vue.set(this._state, 'status', 'connecting')
|
||||||
|
|
||||||
// open all reconnecters
|
// open all reconnectors with deferred connection
|
||||||
Object.values(this._reconnector).forEach((r) => r.open(true))
|
Object.values(this._reconnector).forEach((r) => r.open(true))
|
||||||
|
|
||||||
this._reconnector.websocket.connect()
|
this._reconnector.websocket.connect()
|
||||||
@ -189,6 +189,7 @@ export class NekoConnection extends EventEmitter<NekoConnectionEvents> {
|
|||||||
if (this._open) {
|
if (this._open) {
|
||||||
this._open = false
|
this._open = false
|
||||||
|
|
||||||
|
// set state to disconnected
|
||||||
Vue.set(this._state.websocket, 'connected', false)
|
Vue.set(this._state.websocket, 'connected', false)
|
||||||
Vue.set(this._state.webrtc, 'connected', false)
|
Vue.set(this._state.webrtc, 'connected', false)
|
||||||
Vue.set(this._state, 'status', 'disconnected')
|
Vue.set(this._state, 'status', 'disconnected')
|
||||||
@ -196,7 +197,7 @@ export class NekoConnection extends EventEmitter<NekoConnectionEvents> {
|
|||||||
this.emit('close', error)
|
this.emit('close', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// close all reconnecters
|
// close all reconnectors
|
||||||
Object.values(this._reconnector).forEach((r) => r.close())
|
Object.values(this._reconnector).forEach((r) => r.close())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,16 +207,17 @@ export class NekoConnection extends EventEmitter<NekoConnectionEvents> {
|
|||||||
// TODO: Use server side congestion control.
|
// TODO: Use server side congestion control.
|
||||||
this.webrtc.off('stats', this._webrtcCongestionControlHandle)
|
this.webrtc.off('stats', this._webrtcCongestionControlHandle)
|
||||||
|
|
||||||
// unbind events from all reconnecters
|
// unbind events from all reconnectors
|
||||||
Object.values(this._reconnector).forEach((r) => {
|
Object.values(this._reconnector).forEach((r) => {
|
||||||
r.off('connect', this._onConnectHandle)
|
r.off('connect', this._onConnectHandle)
|
||||||
r.off('disconnect', this._onDisconnectHandle)
|
r.off('disconnect', this._onDisconnectHandle)
|
||||||
r.off('close', this._onCloseHandle)
|
r.off('close', this._onCloseHandle)
|
||||||
})
|
})
|
||||||
|
|
||||||
// destroy all reconnecters
|
// destroy all reconnectors
|
||||||
Object.values(this._reconnector).forEach((r) => r.destroy())
|
Object.values(this._reconnector).forEach((r) => r.destroy())
|
||||||
|
|
||||||
|
// set state to disconnected
|
||||||
Vue.set(this._state.websocket, 'connected', false)
|
Vue.set(this._state.websocket, 'connected', false)
|
||||||
Vue.set(this._state.webrtc, 'connected', false)
|
Vue.set(this._state.webrtc, 'connected', false)
|
||||||
Vue.set(this._state, 'status', 'disconnected')
|
Vue.set(this._state, 'status', 'disconnected')
|
||||||
|
@ -23,6 +23,25 @@ export abstract class ReconnectorAbstract extends EventEmitter<ReconnectorAbstra
|
|||||||
public abstract destroy(): void
|
public abstract destroy(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Reconnector handles reconnection logic according to supplied config for an abstract class. It can reconnect anything that:
|
||||||
|
- can be connected to
|
||||||
|
- can send event once it is connected to
|
||||||
|
- can be disconnected from
|
||||||
|
- can send event once it is disconnected from
|
||||||
|
- can provide information at any moment if it is connected to or not
|
||||||
|
|
||||||
|
Reconnector creates one additional abstract layer for a user. User can open and close a connection. If the connection is open,
|
||||||
|
when connection will be disconnected, reconnector will attempt to connect to it again. Once connection is closed, no further
|
||||||
|
events will be emitted and connection will be disconnected.
|
||||||
|
- When using deferred connection in opening function, reconnector does not try to connect when opening a connection. This is
|
||||||
|
the initial state, when reconnector is not connected but no reconnect attempts are in progress, since there has not been
|
||||||
|
any disconnect even. It is up to user to call initial connect attempt.
|
||||||
|
- Events 'open' and 'close' will be fired exactly once, no matter how many times open() and close() funxtions were called.
|
||||||
|
- Events 'connecŧ' and 'disconnect' can fire throughout open connection at any time.
|
||||||
|
|
||||||
|
*/
|
||||||
export interface ReconnectorEvents {
|
export interface ReconnectorEvents {
|
||||||
open: () => void
|
open: () => void
|
||||||
connect: () => void
|
connect: () => void
|
||||||
@ -48,6 +67,7 @@ export class Reconnector extends EventEmitter<ReconnectorEvents> {
|
|||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
// setup default config values
|
||||||
this._config = {
|
this._config = {
|
||||||
max_reconnects: 10,
|
max_reconnects: 10,
|
||||||
timeout_ms: 1500,
|
timeout_ms: 1500,
|
||||||
@ -55,6 +75,10 @@ export class Reconnector extends EventEmitter<ReconnectorEvents> {
|
|||||||
...config,
|
...config,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register connect and disconnect handlers with current class
|
||||||
|
// as 'this' context, store them to a variable so that they
|
||||||
|
// can be later unregistered
|
||||||
|
|
||||||
this._onConnectHandle = this.onConnect.bind(this)
|
this._onConnectHandle = this.onConnect.bind(this)
|
||||||
this._conn.on('connect', this._onConnectHandle)
|
this._conn.on('connect', this._onConnectHandle)
|
||||||
|
|
||||||
@ -62,27 +86,33 @@ export class Reconnector extends EventEmitter<ReconnectorEvents> {
|
|||||||
this._conn.on('disconnect', this._onDisconnectHandle)
|
this._conn.on('disconnect', this._onDisconnectHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
private onConnect() {
|
private clearTimeout() {
|
||||||
if (this._timeout) {
|
if (this._timeout) {
|
||||||
window.clearTimeout(this._timeout)
|
window.clearTimeout(this._timeout)
|
||||||
this._timeout = undefined
|
this._timeout = undefined
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onConnect() {
|
||||||
|
this.clearTimeout()
|
||||||
|
|
||||||
|
// only if connection is open, fire connect event
|
||||||
if (this._open) {
|
if (this._open) {
|
||||||
this._last_connected = new Date()
|
this._last_connected = new Date()
|
||||||
this._total_reconnects = 0
|
this._total_reconnects = 0
|
||||||
this.emit('connect')
|
this.emit('connect')
|
||||||
} else {
|
} else {
|
||||||
|
// in this case we are connected but this connection
|
||||||
|
// has been closed, so we simply disconnect again
|
||||||
this._conn.disconnect()
|
this._conn.disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onDisconnect() {
|
private onDisconnect() {
|
||||||
if (this._timeout) {
|
this.clearTimeout()
|
||||||
window.clearTimeout(this._timeout)
|
|
||||||
this._timeout = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// only if connection is open, fire disconnect event
|
||||||
|
// and start reconnecteing logic
|
||||||
if (this._open) {
|
if (this._open) {
|
||||||
this.emit('disconnect')
|
this.emit('disconnect')
|
||||||
this.reconnect()
|
this.reconnect()
|
||||||
@ -110,18 +140,21 @@ export class Reconnector extends EventEmitter<ReconnectorEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public set config(conf: ReconnectorConfig) {
|
public set config(conf: ReconnectorConfig) {
|
||||||
this._config = { ...conf }
|
this._config = { ...this._config, ...conf }
|
||||||
|
|
||||||
if (this._config.max_reconnects <= this._total_reconnects) {
|
if (this._config.max_reconnects <= this._total_reconnects) {
|
||||||
this.close(new Error('reconnection config changed'))
|
this.close(new Error('reconnection config changed'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allows future reconnect attempts and connects if not set
|
||||||
|
// deferred connection to true
|
||||||
public open(deferredConnection = false): void {
|
public open(deferredConnection = false): void {
|
||||||
if (this._timeout) {
|
this.clearTimeout()
|
||||||
window.clearTimeout(this._timeout)
|
|
||||||
this._timeout = undefined
|
// assuming open event can fire multiple times, we need to
|
||||||
}
|
// ensure, that open event get fired only once along with
|
||||||
|
// resetting total reconnects counter
|
||||||
|
|
||||||
if (!this._open) {
|
if (!this._open) {
|
||||||
this._open = true
|
this._open = true
|
||||||
@ -134,50 +167,53 @@ export class Reconnector extends EventEmitter<ReconnectorEvents> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disconnects and forbids future reconnect attempts
|
||||||
public close(error?: Error): void {
|
public close(error?: Error): void {
|
||||||
if (this._timeout) {
|
this.clearTimeout()
|
||||||
window.clearTimeout(this._timeout)
|
|
||||||
this._timeout = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// assuming close event can fire multiple times, the same
|
||||||
|
// precautions need to be taken as in open event, so that
|
||||||
|
// close event fires only once
|
||||||
|
|
||||||
if (this._open) {
|
if (this._open) {
|
||||||
this._open = false
|
this._open = false
|
||||||
this._last_connected = undefined
|
this._last_connected = undefined
|
||||||
this.emit('close', error)
|
this.emit('close', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if connected, tries to disconnect even if it has been
|
||||||
|
// called multiple times by user
|
||||||
|
|
||||||
if (this._conn.connected) {
|
if (this._conn.connected) {
|
||||||
this._conn.disconnect()
|
this._conn.disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tries to connect and calls on disconnected if it could not
|
||||||
|
// connect within specified timeout according to config
|
||||||
public connect(): void {
|
public connect(): void {
|
||||||
if (this._timeout) {
|
this.clearTimeout()
|
||||||
window.clearTimeout(this._timeout)
|
|
||||||
this._timeout = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
this._conn.connect()
|
this._conn.connect()
|
||||||
this._timeout = window.setTimeout(this.onDisconnect.bind(this), this._config.timeout_ms)
|
this._timeout = window.setTimeout(this.onDisconnect.bind(this), this._config.timeout_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tries to connect with specified backoff time if
|
||||||
|
// maximum reconnect theshold was not exceeded, otherwise
|
||||||
|
// closes the connection with an error message
|
||||||
public reconnect(): void {
|
public reconnect(): void {
|
||||||
if (this._timeout) {
|
this.clearTimeout()
|
||||||
window.clearTimeout(this._timeout)
|
|
||||||
this._timeout = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
this._total_reconnects++
|
if (this._config.max_reconnects > ++this._total_reconnects || this._config.max_reconnects == -1) {
|
||||||
|
|
||||||
if (this._config.max_reconnects > this._total_reconnects || this._config.max_reconnects == -1) {
|
|
||||||
this._timeout = window.setTimeout(this.connect.bind(this), this._config.backoff_ms)
|
this._timeout = window.setTimeout(this.connect.bind(this), this._config.backoff_ms)
|
||||||
} else {
|
} else {
|
||||||
this.close(new Error('reconnection failed'))
|
this.close(new Error('reconnection failed'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closes connection and unregisters all events
|
||||||
public destroy() {
|
public destroy() {
|
||||||
this.close()
|
this.close(new Error('connection destroyed'))
|
||||||
|
|
||||||
this._conn.off('connect', this._onConnectHandle)
|
this._conn.off('connect', this._onConnectHandle)
|
||||||
this._conn.off('disconnect', this._onDisconnectHandle)
|
this._conn.off('disconnect', this._onDisconnectHandle)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as webrtcTypes from './webrtc'
|
import * as webrtcTypes from './webrtc'
|
||||||
import * as reconnecterTypes from './reconnector'
|
import * as reconnectorTypes from './reconnector'
|
||||||
|
|
||||||
export default interface State {
|
export default interface State {
|
||||||
authenticated: boolean
|
authenticated: boolean
|
||||||
@ -39,7 +39,7 @@ export interface WebRTC {
|
|||||||
videos: string[]
|
videos: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReconnectorConfig extends reconnecterTypes.ReconnectorConfig {}
|
export interface ReconnectorConfig extends reconnectorTypes.ReconnectorConfig {}
|
||||||
|
|
||||||
export interface WebRTCStats extends webrtcTypes.WebRTCStats {}
|
export interface WebRTCStats extends webrtcTypes.WebRTCStats {}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user