import { Protocol } from "src/entities/WSProtocol"; import EventBus, { EventNamesDefine } from "./EventBus"; export default class ClientConnection { ws: WebSocket | null = null; url = ""; user_name = ""; password = ""; _is_login = false; _rpc_id_counter = 0; rpc_map = new Map< number, (is_fail: boolean, packet: Protocol.Commands, data: string) => void >(); public login_callback: | ((this: ClientConnection, logined: boolean) => void) | null = null; constructor( url: string, user_name?: string | null, password?: string | null ) { this.reconnectTo(url, user_name, password); } get is_connected() { return this.ws && this.ws.readyState == WebSocket.OPEN; } get is_login() { return this._is_login; } public reconnectTo( url: string, user_name?: string | null, password?: string | null ) { this.url = url; this.user_name = user_name ?? ""; this.password = password ?? ""; if (this.ws) { this.ws.close(); } this.ws = new WebSocket(url); this.initializeWs(); } initializeWs() { if (this.ws) { this.ws.onclose = (ev) => { this.onClose(ev); }; this.ws.onerror = (ev) => { this.onError(ev); }; this.ws.onopen = (ev) => { this.onOpen(ev); }; this.ws.onmessage = (ev) => { this.onMessage(ev); }; } } login() { if (this.is_connected) { const request = new Protocol.LoginRequest(this.user_name, this.password); this.ws?.send(JSON.stringify(request)); } } onClose(ev: CloseEvent) { this._is_login = false; console.log("onClose"); } onError(ev: Event) { this._is_login = false; setTimeout(() => { this.reconnectTo(this.url, this.user_name, this.password); }, 5000); } onOpen(ev: Event) { this._is_login = false; this.login(); } onMessage(ev: MessageEvent) { try { const packet = JSON.parse(ev.data) as Protocol.PacketEntity; if (packet) { if (packet.has_exception) { console.error(ev.data); } if (Protocol.Commands.AllCommands.has(packet.command)) { if ( packet.flag == Protocol.PacketEntity.FLAG_RESPONSE || packet.flag == Protocol.PacketEntity.FLAG_NOTIFY ) { if (packet.command == Protocol.Commands.kLogin) { const login_response = JSON.parse( ev.data ) as Protocol.LoginResponse; if (login_response) { this._is_login = !login_response.has_exception && login_response.success; if ( this.login_callback && typeof this.login_callback == "function" ) { this.login_callback(this._is_login); } } } if (this.rpc_map.has(packet.rpc_id)) { const f = this.rpc_map.get(packet.rpc_id); if (f && typeof f == "function") { f(false, packet, ev.data); this.rpc_map.delete(packet.rpc_id); } } else { EventBus.getInstance().emit(EventNamesDefine.ResponseMessage, { packet: packet, data: ev.data, }); } } } else { console.error("unknow command: " + packet.command, packet); } } } catch (e) { console.error(e); } } public async doRpc<_RequestType extends Protocol.PacketEntity, _ResponseType>( RequestType: new () => _RequestType ): Promise<_ResponseType | null> { return new Promise((resolve, reject) => { const rpc_id = ++this._rpc_id_counter; if (this.rpc_map.has(rpc_id)) { const f = this.rpc_map.get(rpc_id); if (f && typeof f == "function") { f(true, new Protocol.Commands(), ""); this.rpc_map.delete(rpc_id); } } let request: _RequestType = new RequestType(); request.rpc_id = rpc_id; this.ws?.send(JSON.stringify(request)); this.rpc_map.set( rpc_id, (is_fail: boolean, packet: Protocol.Commands, data: string) => { if (is_fail) { reject(); } else { try { const response = JSON.parse(data) as _ResponseType; if (response) { resolve(response); } else { reject(); console.log("reject"); } } catch { reject(); console.log("reject"); } } } ); }); } public async getSignalSources() { try { return await this.doRpc< Protocol.GetSignalSourcesRequest, Protocol.GetSignalSourcesResponse >(Protocol.GetSignalSourcesRequest); } catch (e) { console.error(e); } } public async getApplicationSettins() { try { return await this.doRpc< Protocol.GetApplicationConfigRequestEntity, Protocol.GetApplicationConfigResponseEntity >(Protocol.GetApplicationConfigRequestEntity); } catch (e) { console.error(e); } } public async getWindows() { try { return await this.doRpc< Protocol.GetWindowsRequestEntity, Protocol.GetWindowsResponseEntity >(Protocol.GetWindowsRequestEntity); } catch (e) { console.error(e); } } public moveWindow(window_id: number, x: number, y: number) { this.ws?.send( JSON.stringify(new Protocol.MoveWindowRequestEntity(window_id, x, y)) ); } public resizeWindow(window_id: number, width: number, height: number) { this.ws?.send( JSON.stringify( new Protocol.ResizeWindowRequestEntity(window_id, width, height) ) ); } public closeWindow(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.CloseWindowRequestEntity(window_id)) ); } }