From 3d1b92ae1c10f53b31a66a11834575a3fa0f879f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Sat, 19 Jun 2021 19:36:59 +0200 Subject: [PATCH] add new reconnection logic. --- src/component/internal/connection.ts | 104 +++++++++++++++++++++------ src/component/main.vue | 8 +-- 2 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/component/internal/connection.ts b/src/component/internal/connection.ts index 951119cb..fbbd0e5c 100644 --- a/src/component/internal/connection.ts +++ b/src/component/internal/connection.ts @@ -1,5 +1,6 @@ import Vue from 'vue' import EventEmitter from 'eventemitter3' +import { Logger } from '../utils/logger' import * as EVENT from '../types/events' import { NekoWebSocket } from './websocket' @@ -14,6 +15,8 @@ export class NekoConnection extends EventEmitter { private _url: string private _token: string private _state: Connection + private _log: Logger + private _shouldReconnect = false public websocket = new NekoWebSocket() public webrtc = new NekoWebRTC() @@ -23,52 +26,48 @@ export class NekoConnection extends EventEmitter { this._url = '' this._token = '' + this._log = new Logger('connection') this._state = state // initial state Vue.set(this._state, 'type', 'webrtc') - let webSocketStatus = 'disconnected' - let webRTCStatus = 'disconnected' - // websocket this.websocket.on('connecting', () => { - webSocketStatus = 'connecting' if (this._state.status !== 'connecting') { Vue.set(this._state, 'status', 'connecting') } }) this.websocket.on('connected', () => { - webSocketStatus = 'connected' - if (webSocketStatus == 'connected' && webRTCStatus == 'connected') { + if (this.websocket.connected && this.webrtc.connected) { Vue.set(this._state, 'status', 'connected') } }) this.websocket.on('disconnected', () => { - webSocketStatus = 'disconnected' if (this._state.status !== 'disconnected') { Vue.set(this._state, 'status', 'disconnected') } + + this._websocketReconnect() }) // webrtc this.webrtc.on('connecting', () => { - webRTCStatus = 'connecting' if (this._state.status !== 'connecting') { Vue.set(this._state, 'status', 'connecting') } }) this.webrtc.on('connected', () => { - webRTCStatus = 'connected' - if (webSocketStatus == 'connected' && webRTCStatus == 'connected') { + if (this.websocket.connected && this.webrtc.connected) { Vue.set(this._state, 'status', 'connected') } }) this.webrtc.on('disconnected', () => { - webRTCStatus = 'disconnected' if (this._state.status !== 'disconnected') { Vue.set(this._state, 'status', 'disconnected') } + + this._webrtcReconnect() }) let webrtcCongestion: number = 0 @@ -123,22 +122,87 @@ export class NekoConnection extends EventEmitter { this.websocket.send(EVENT.SIGNAL_VIDEO, { video: video }) } - public async connect(): Promise { + public async connect(video?: string): Promise { + this._shouldReconnect = true + + await this._websocketConnect() + + if (video && !this._state.webrtc.videos.includes(video)) { + throw new Error('video id not found') + } + + this._webrtcConnect(video) + } + + public disconnect() { + this._shouldReconnect = false + + this.webrtc.disconnect() + this.websocket.disconnect() + + Vue.set(this._state, 'status', 'disconnected') + this.emit('disconnect') + } + + async _websocketConnect() { let url = this._url if (this._token) { url += '?token=' + encodeURIComponent(this._token) } await this.websocket.connect(url) - - // TODO: connect to WebRTC - //this.websocket.send(EVENT.SIGNAL_REQUEST, { video: video }) } - public disconnect() { - this.webrtc.disconnect() - this.websocket.disconnect() - Vue.set(this._state, 'status', 'disconnected') - this.emit('disconnect') + _websocketIsReconnecting = false + _websocketReconnect() { + if (this._websocketIsReconnecting) { + return + } + + setTimeout(async () => { + while (this._shouldReconnect) { + try { + await this._websocketConnect() + this._webrtcReconnect() + break + } catch (e) { + this._log.debug(`websocket reconnection`, e) + } + } + + this._websocketIsReconnecting = false + }, 0) + } + + _webrtcConnect(video?: string) { + if (video && !this._state.webrtc.videos.includes(video)) { + throw new Error('video id not found') + } + + this.websocket.send(EVENT.SIGNAL_REQUEST, { video: video }) + } + + _webrtcReconnTimer?: number + _webrtcReconnect() { + if (this._webrtcReconnTimer) { + return + } + + const lastVideo = this._state.webrtc.video ?? undefined + + const reconnFunc = async () => { + if (!this._shouldReconnect || !this.websocket.connected || this.webrtc.connected) { + clearInterval(this._webrtcReconnTimer) + this._webrtcReconnTimer = undefined + return + } + + try { + this._webrtcConnect(lastVideo) + } catch (e) {} + } + + this._webrtcReconnTimer = window.setInterval(reconnFunc, 1000) + reconnFunc() } } diff --git a/src/component/main.vue b/src/component/main.vue index bb1860b5..08067c5f 100644 --- a/src/component/main.vue +++ b/src/component/main.vue @@ -256,13 +256,7 @@ throw new Error('client is already connected') } - await this.connection.connect() - - if (video && !this.state.connection.webrtc.videos.includes(video)) { - throw new Error('video id not found') - } - - this.connection.websocket.send(EVENT.SIGNAL_REQUEST, { video: video }) + await this.connection.connect(video) } public disconnect() {