diff --git a/src/component/internal/connection.ts b/src/component/internal/connection.ts index 4d724d97..e45ad100 100644 --- a/src/component/internal/connection.ts +++ b/src/component/internal/connection.ts @@ -1,11 +1,10 @@ import Vue from 'vue' import EventEmitter from 'eventemitter3' -import { Logger } from '../utils/logger' import * as EVENT from '../types/events' import { NekoWebSocket } from './websocket' -import { NekoWebRTC, WebRTCStats } from './webrtc' -import { Connection } from '../types/state' +import { NekoWebRTC } from './webrtc' +import { Connection, WebRTCStats } from '../types/state' import { Reconnecter, ReconnecterAbstract } from '../utils/reconnecter' const WEBRTC_RECONN_MAX_LOSS = 25 @@ -16,14 +15,13 @@ export interface NekoConnectionEvents { } class WebsocketReconnecter extends ReconnecterAbstract { - private _conn: NekoConnection + private _state: Connection private _websocket: NekoWebSocket - constructor(conn: NekoConnection, websocket: NekoWebSocket) { + constructor(state: Connection, websocket: NekoWebSocket) { super() - // TODO: Antipattern. - this._conn = conn + this._state = state // TODO: Unmount. this._websocket = websocket @@ -32,8 +30,10 @@ class WebsocketReconnecter extends ReconnecterAbstract { } public async connect() { - let url = this._conn.getUrl() - const token = this._conn.getToken() + let url = this._state.url + url = url.replace(/^http/, 'ws').replace(/\/+$/, '') + '/api/ws' + + const token = this._state.token if (token) { url += '?token=' + encodeURIComponent(token) } @@ -47,15 +47,14 @@ class WebsocketReconnecter extends ReconnecterAbstract { } class WebrtcReconnecter extends ReconnecterAbstract { - private _conn: NekoConnection + private _state: Connection private _websocket: NekoWebSocket private _webrtc: NekoWebRTC - constructor(conn: NekoConnection, websocket: NekoWebSocket, webrtc: NekoWebRTC) { + constructor(state: Connection, websocket: NekoWebSocket, webrtc: NekoWebRTC) { super() - // TODO: Antipattern. - this._conn = conn + this._state = state this._websocket = websocket // TODO: Unmount. @@ -65,7 +64,7 @@ class WebrtcReconnecter extends ReconnecterAbstract { } public async connect() { - this._websocket.send(EVENT.SIGNAL_REQUEST, { video: this._conn.getVideo() }) + this._websocket.send(EVENT.SIGNAL_REQUEST, { video: this._state.webrtc.video }) } public async disconnect() { @@ -74,31 +73,23 @@ class WebrtcReconnecter extends ReconnecterAbstract { } export class NekoConnection extends EventEmitter { - private _url = '' - private _token = '' - private _video = '' - - private _log = new Logger('connection') private _state: Connection public websocket = new NekoWebSocket() - public _websocket_reconn = new Reconnecter(new WebsocketReconnecter(this, this.websocket), { - max_reconnects: 15, - timeout_ms: 5000, - backoff_ms: 1500, - }) + public _websocket_reconn: Reconnecter public webrtc = new NekoWebRTC() - public _webrtc_reconn = new Reconnecter(new WebrtcReconnecter(this, this.websocket, this.webrtc), { - max_reconnects: 15, - timeout_ms: 10000, - backoff_ms: 1500, - }) + public _webrtc_reconn: Reconnecter constructor(state: Connection) { super() this._state = state + this._websocket_reconn = new Reconnecter(new WebsocketReconnecter(state, this.websocket), state.websocket.config) + this._webrtc_reconn = new Reconnecter( + new WebrtcReconnecter(state, this.websocket, this.webrtc), + state.webrtc.config, + ) // initial state Vue.set(this._state, 'type', 'screencast') @@ -187,40 +178,22 @@ export class NekoConnection extends EventEmitter { return this._websocket_reconn.isOpen && this._webrtc_reconn.isOpen } - public setUrl(url: string) { - this._url = url.replace(/^http/, 'ws').replace(/\/+$/, '') + '/api/ws' - } - - public getUrl(): string { - return this._url - } - - public setToken(token: string) { - this._token = token - } - - public getToken(): string { - return this._token - } - public setVideo(video: string) { if (!this._state.webrtc.videos.includes(video)) { throw new Error('video id not found') } - if (this.websocket.connected) { - this.websocket.send(EVENT.SIGNAL_VIDEO, { video }) - } - - this._video = video - } - - public getVideo() { - return this._video + this.websocket.send(EVENT.SIGNAL_VIDEO, { video }) } public async connect(video?: string): Promise { - if (video) this._video = video + if (video) { + if (!this._state.webrtc.videos.includes(video)) { + throw new Error('video id not found') + } + + Vue.set(this._state.webrtc, 'video', video) + } this._webrtc_reconn.open(true) this._websocket_reconn.open() diff --git a/src/component/main.vue b/src/component/main.vue index ca1dd121..1147564f 100644 --- a/src/component/main.vue +++ b/src/component/main.vue @@ -110,8 +110,22 @@ public state = { authenticated: false, connection: { + url: location.href, + token: undefined, status: 'disconnected', + websocket: { + config: { + maxReconnects: 15, + timeoutMs: 5000, + backoffMs: 1500, + }, + }, webrtc: { + config: { + maxReconnects: 15, + timeoutMs: 10000, + backoffMs: 1500, + }, stats: null, video: null, videos: [], @@ -184,7 +198,7 @@ const httpURL = url.replace(/^ws/, 'http').replace(/\/$|\/ws\/?$/, '') this.api.setUrl(httpURL) - this.connection.setUrl(httpURL) + Vue.set(this.state.connection, 'url', httpURL) if (this.connected) { this.connection.disconnect() @@ -208,7 +222,7 @@ if (token) { this.api.setToken(token) - this.connection.setToken(token) + Vue.set(this.state.connection, 'token', token) } await this.api.session.whoami() @@ -227,7 +241,7 @@ const res = await this.api.session.login({ username, password }) if (res.data.token) { this.api.setToken(res.data.token) - this.connection.setToken(res.data.token) + Vue.set(this.state.connection, 'token', res.data.token) if (this.autologin) { localStorage.setItem('neko_session', res.data.token) @@ -250,7 +264,7 @@ await this.api.session.logout() } finally { this.api.setToken('') - this.connection.setToken('') + Vue.delete(this.state.connection, 'token') if (this.autologin) { localStorage.removeItem('neko_session') diff --git a/src/component/types/state.ts b/src/component/types/state.ts index 76f52ebf..fd8d6be6 100644 --- a/src/component/types/state.ts +++ b/src/component/types/state.ts @@ -1,3 +1,6 @@ +import * as webrtcTypes from './webrtc' +import * as reconnecterTypes from './reconnecter' + export default interface State { authenticated: boolean connection: Connection @@ -13,27 +16,30 @@ export default interface State { ///////////////////////////// export interface Connection { + url: string + token?: string status: 'disconnected' | 'connecting' | 'connected' + websocket: WebSocket webrtc: WebRTC screencast: boolean type: 'webrtc' | 'screencast' | 'none' } +export interface WebSocket { + config: ReconnecterConfig +} + export interface WebRTC { + config: ReconnecterConfig stats: WebRTCStats | null video: string | null videos: string[] auto: boolean } -export interface WebRTCStats { - bitrate: number - packetLoss: number - fps: number - width: number - height: number - muted?: boolean -} +export interface ReconnecterConfig extends reconnecterTypes.ReconnecterConfig {} + +export interface WebRTCStats extends webrtcTypes.WebRTCStats {} ///////////////////////////// // Video