diff --git a/src/component/internal/connection.ts b/src/component/internal/connection.ts index 5fd276ac..ff04331b 100644 --- a/src/component/internal/connection.ts +++ b/src/component/internal/connection.ts @@ -14,72 +14,69 @@ const WEBRTC_RECONN_MAX_LOSS = 25 const WEBRTC_RECONN_FAILED_ATTEMPTS = 5 export interface NekoConnectionEvents { - disconnect: (error?: Error) => void + close: (error?: Error) => void } export class NekoConnection extends EventEmitter { private _state: Connection public websocket = new NekoWebSocket() - public _websocket_reconn: Reconnector - public webrtc = new NekoWebRTC() - public _webrtc_reconn: Reconnector + + private _reconnector: { + websocket: Reconnector + webrtc: Reconnector + } constructor(state: Connection) { super() this._state = state - this._websocket_reconn = new Reconnector(new WebsocketReconnector(state, this.websocket), state.websocket.config) - this._webrtc_reconn = new Reconnector( - new WebrtcReconnector(state, this.websocket, this.webrtc), - state.webrtc.config, - ) + this._reconnector = { + websocket: new Reconnector(new WebsocketReconnector(state, this.websocket), state.websocket.config), + webrtc: new Reconnector(new WebrtcReconnector(state, this.websocket, this.webrtc), state.webrtc.config), + } // websocket - this._websocket_reconn.on('connect', () => { + this._reconnector.websocket.on('connect', () => { if (this.websocket.connected && this.webrtc.connected) { Vue.set(this._state, 'status', 'connected') } if (!this.webrtc.connected) { - this._webrtc_reconn.connect() + this._reconnector.webrtc.connect() } }) - this._websocket_reconn.on('disconnect', () => { + this._reconnector.websocket.on('disconnect', () => { if (this._state.status === 'connected' && this.activated) { Vue.set(this._state, 'status', 'connecting') } }) - this._websocket_reconn.on('close', (error) => { - this.disconnect(error) - }) + this._reconnector.websocket.on('close', this.close.bind(this)) // webrtc - this._webrtc_reconn.on('connect', () => { + this._reconnector.webrtc.on('connect', () => { if (this.websocket.connected && this.webrtc.connected) { Vue.set(this._state, 'status', 'connected') } Vue.set(this._state, 'type', 'webrtc') }) - this._webrtc_reconn.on('disconnect', () => { + this._reconnector.webrtc.on('disconnect', () => { if (this._state.status === 'connected' && this.activated) { Vue.set(this._state, 'status', 'connecting') } Vue.set(this._state, 'type', 'fallback') }) - this._webrtc_reconn.on('close', (error) => { - this.disconnect(error) - }) + this._reconnector.webrtc.on('close', this.close.bind(this)) let webrtcCongestion: number = 0 this.webrtc.on('stats', (stats: WebRTCStats) => { Vue.set(this._state.webrtc, 'stats', stats) // if automatic quality adjusting is turned off - if (!this._state.webrtc.auto || !this._webrtc_reconn.isOpen) return + if (!this._state.webrtc.auto || !this._reconnector.webrtc.isOpen) return // if there are no or just one quality, no switching can be done if (this._state.webrtc.videos.length <= 1) return @@ -118,14 +115,15 @@ export class NekoConnection extends EventEmitter { return } - // try to reconnect - this._webrtc_reconn.reconnect() + // try to reconnect webrtc + this._reconnector.webrtc.reconnect() } }) } public get activated() { - return this._websocket_reconn.isOpen && this._webrtc_reconn.isOpen + // check if every reconnecter is open + return Object.values(this._reconnector).every((r) => r.isOpen) } public setVideo(video: string) { @@ -136,7 +134,7 @@ export class NekoConnection extends EventEmitter { this.websocket.send(EVENT.SIGNAL_VIDEO, { video }) } - public connect(video?: string) { + public open(video?: string) { if (video) { if (!this._state.webrtc.videos.includes(video)) { throw new Error('video id not found') @@ -148,23 +146,27 @@ export class NekoConnection extends EventEmitter { Vue.set(this._state, 'type', 'fallback') Vue.set(this._state, 'status', 'connecting') - this._webrtc_reconn.open(true) - this._websocket_reconn.open() + // open all reconnecters + Object.values(this._reconnector).forEach((r) => r.open(true)) + + this._reconnector.websocket.connect() } - public disconnect(error?: Error) { - this._websocket_reconn.close() - this._webrtc_reconn.close() + public close(error?: Error) { + if (this.activated) { + Vue.set(this._state, 'type', 'none') + Vue.set(this._state, 'status', 'disconnected') - Vue.set(this._state, 'type', 'none') - Vue.set(this._state, 'status', 'disconnected') + this.emit('close', error) + } - this.emit('disconnect', error) + // close all reconnecters + Object.values(this._reconnector).forEach((r) => r.close()) } public destroy() { - this._websocket_reconn.destroy() - this._webrtc_reconn.destroy() + // destroy all reconnecters + Object.values(this._reconnector).forEach((r) => r.destroy()) Vue.set(this._state, 'type', 'none') Vue.set(this._state, 'status', 'disconnected') diff --git a/src/component/internal/messages.ts b/src/component/internal/messages.ts index 48c59c2c..f67198b5 100644 --- a/src/component/internal/messages.ts +++ b/src/component/internal/messages.ts @@ -12,7 +12,7 @@ export interface NekoEvents { ['connection.status']: (status: 'connected' | 'connecting' | 'disconnected') => void ['connection.webrtc.sdp']: (type: 'local' | 'remote', data: string) => void ['connection.webrtc.sdp.candidate']: (type: 'local' | 'remote', data: RTCIceCandidateInit) => void - ['connection.disconnect']: (message: string) => void + ['connection.closed']: (error?: Error) => void // drag and drop events ['upload.drop.started']: () => void @@ -106,8 +106,7 @@ export class NekoMessages extends EventEmitter { protected [EVENT.SYSTEM_DISCONNECT]({ message }: message.SystemDisconnect) { this._log.debug('EVENT.SYSTEM_DISCONNECT') - this._connection.disconnect() - this.emit('connection.disconnect', message) + this._connection.close(new Error(message)) } ///////////////////////////// diff --git a/src/component/main.vue b/src/component/main.vue index fee0d6c5..a0f8109a 100644 --- a/src/component/main.vue +++ b/src/component/main.vue @@ -198,9 +198,9 @@ this.api.setUrl(httpURL) Vue.set(this.state.connection, 'url', httpURL) - if (this.connected) { - this.connection.disconnect() - } + try { + this.disconnect() + } catch (e) {} if (this.state.authenticated) { Vue.set(this.state, 'authenticated', false) @@ -254,9 +254,9 @@ throw new Error('client not authenticated') } - if (this.connected) { - this.connection.disconnect() - } + try { + this.disconnect() + } catch (e) {} try { await this.api.session.logout() @@ -281,7 +281,7 @@ throw new Error('client is already connected') } - this.connection.connect(video) + this.connection.open(video) } public disconnect() { @@ -289,7 +289,7 @@ throw new Error('client is not connected') } - this.connection.disconnect() + this.connection.close() } public play() { @@ -383,7 +383,8 @@ // video events VideoRegister(this._video, this.state.video) - this.connection.on('disconnect', () => { + this.connection.on('close', (error) => { + this.events.emit('connection.closed', error) this.clear() })