import { ConnectTableEntity } from "src/entities/ConnectTableEntity"; import { PollingEntity } from "src/entities/PollingEntity"; import ReconnectingWebSocket from "reconnecting-websocket"; import NormalWindowRequestEntity from "src/entities/NormalWindowRequestEntity"; import { PlanEntity } from "src/entities/PlanEntity"; import { SignalSourceEntity } from "src/entities/SignalSourceEntity"; import { StringKeyValueEntity } from "src/entities/StringKeyValueEntity"; import SubtitleEntity from "src/entities/SubtitleEntity"; import { Protocol } from "src/entities/WSProtocol"; import EventBus, { EventNamesDefine } from "./EventBus"; import { EdgeBlendingPoint } from "src/entities/EdgeBlendingEntities"; import { ExternalControlTableEntity } from "src/entities/ExternalControlTableEntity"; import { SerialPortConfigEntity } from "src/entities/SerialPortConfigEntity"; import TimingTaskEntity from "src/entities/TimingTaskEntity"; import JointActionEquipmentTableEntity from "src/entities/JointActionEquipmentTableEntity"; class _RpcInfo { send_timestamp: number; timeout_timestamp: number; callback: (is_fail: boolean, packet: Protocol.Commands, data: string) => void; constructor( timeout_timestamp: number, callback: ( is_fail: boolean, packet: Protocol.Commands, data: string ) => void ) { this.timeout_timestamp = timeout_timestamp; this.send_timestamp = new Date().getTime(); this.callback = callback; } public reject() { this.callback(true, new Protocol.Commands(), ""); } public reslove(is_fail: boolean, packet: Protocol.Commands, data: string) { this.callback(is_fail, packet, data); } } export default class ClientConnection { ws: ReconnectingWebSocket | null = null; url = ""; user_name = ""; password = ""; _is_login = false; _rpc_id_counter = 0; rpc_map = new Map(); public login_callback: | ((this: ClientConnection, logined: boolean) => void) | null = null; constructor( 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 ReconnectingWebSocket(url); this.initializeWs(); setInterval(() => { this.checkRpcTimeout(); }, 1000); } get is_connected() { return this.ws && this.ws.readyState == WebSocket.OPEN; } get is_login() { return this._is_login; } checkRpcTimeout() { const current_datetime = new Date().getTime(); this.rpc_map.forEach((v, k, m) => { if (current_datetime - v.send_timestamp > v.timeout_timestamp) { v.reject(); m.delete(k); } }); } 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: any) { this._is_login = false; EventBus.getInstance().emit(EventNamesDefine.WebSocketClose, this); } onError(ev: any) { this._is_login = false; EventBus.getInstance().emit(EventNamesDefine.WebSocketError, this); } onOpen(ev: any) { 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); this.rpc_map.get(packet.rpc_id)?.reject(); this.rpc_map.delete(packet.rpc_id); } 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.is_login) { EventBus.getInstance().emit( EventNamesDefine.WebSocketConnected, this ); } if ( this.login_callback && typeof this.login_callback == "function" ) { this.login_callback(this._is_login); } } } else if (this.rpc_map.has(packet.rpc_id)) { this.rpc_map.get(packet.rpc_id)?.reslove(false, packet, ev.data); this.rpc_map.delete(packet.rpc_id); } else { EventBus.getInstance().emit( packet.flag == Protocol.PacketEntity.FLAG_NOTIFY ? EventNamesDefine.NotifyMessage : packet.flag == Protocol.PacketEntity.FLAG_RESPONSE ? EventNamesDefine.ResponseMessage : EventNamesDefine.UnKnow, { packet: packet, data: ev.data, } ); } } } else { console.error("unknow command: " + packet.command, packet); } } } catch (e) { console.error(e); } } public async doRpc<_ResponseType>( request: Protocol.PacketEntity ): Promise<_ResponseType | null> { return new Promise((resolve, reject) => { const rpc_id = ++this._rpc_id_counter; if (this.rpc_map.has(rpc_id)) { this.rpc_map.get(rpc_id)?.reject(); this.rpc_map.delete(rpc_id); } request.rpc_id = rpc_id; this.rpc_map.set( rpc_id, new _RpcInfo( request.timeout, (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(); } } catch { reject(); } } } ) ); if (request) { request.timeout; } this.ws?.send(JSON.stringify(request)); }); } public async getSignalSources() { try { return await this.doRpc( new Protocol.GetSignalSourcesRequest() ); } catch (e) { console.error(e); } } public async addSignalSourceGroup(parent_uuid: string, name: string) { try { return await this.doRpc( new Protocol.AddSignalSourceGroupRequestEntity(0, parent_uuid, name) ); } catch (e) { console.error(e); } } public async editSignalSourceGroup( uuid: string, name: string, parent_uuid: string ) { try { return await this.doRpc( new Protocol.EditSignalSourceGroupRequestEntity( 0, uuid, name, parent_uuid ) ); } catch (e) { console.error(e); } } public async deleteSignalSourceGroup(uuid: string) { try { return await this.doRpc( new Protocol.DeleteSignalSourceGroupRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async addSignalSource(item: SignalSourceEntity) { try { return await this.doRpc( new Protocol.AddSignalSourceRequestEntity(0, item) ); } catch (e) { console.error(e); } } public async editSignalSource(item: SignalSourceEntity) { try { return await this.doRpc( new Protocol.EditSignalSourceRequestEntity(0, item) ); } catch (e) { console.error(e); } } public async deleteSignalSource(uuid: string) { try { return await this.doRpc( new Protocol.DeleteSignalSourceRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async getModes() { try { return await this.doRpc( new Protocol.GetModesRequestEntity() ); } catch (e) { console.error(e); } } public async addPlanGroup(group_uuid: string, name: string) { try { return await this.doRpc( new Protocol.AddPlanGroupRequestEntity(0, group_uuid, name) ); } catch (e) { console.error(e); } } public async editPlanGroup(uuid: string, name: string, parent_uuid: string) { try { return await this.doRpc( new Protocol.EditPlanGroupRequestEntity(0, uuid, name, parent_uuid) ); } catch (e) { console.error(e); } } public async deletePlanGroup(uuid: string) { try { return await this.doRpc( new Protocol.DeletePlanGroupRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async addPlan(entity?: PlanEntity) { try { return await this.doRpc( new Protocol.AddPlanRequestEntity(0, entity) ); } catch (e) { console.error(e); } } public async editPlan(entity?: PlanEntity) { try { return await this.doRpc( new Protocol.EditPlanRequestEntity(0, entity) ); } catch (e) { console.error(e); } } public async deletePlan(uuid: string) { try { return await this.doRpc( new Protocol.DeletePlanRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async deletePollingGroup(uuid: string) { try { return await this.doRpc( new Protocol.DeletePollingGroupRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async addPolling( group_uuid: string, name: string, datas: StringKeyValueEntity[] ) { try { return await this.doRpc( new Protocol.AddPollingRequestEntity(0, group_uuid, name, datas, "") ); } catch (e) { console.error(e); } } public async editPolling(entity: PollingEntity) { try { return await this.doRpc( new Protocol.EditPollingRequestEntity(0, entity) ); } catch (e) { console.error(e); } } public async deletePolling(uuid: string) { try { return await this.doRpc( new Protocol.DeletePollingRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async getCurrentRunningPlan() { try { return await this.doRpc( new Protocol.GetCurrentRunningPlanRequestEntity(0) ); } catch (e) { console.error(e); } } public runPlan(uuid: string) { this.ws?.send(JSON.stringify(new Protocol.RunPlanRequestEntity(uuid))); } public stopCurrentRunningPlan() { this.ws?.send( JSON.stringify(new Protocol.StopCurrentRunningPlanRequestEntity()) ); } public async getPlans() { try { return await this.doRpc( new Protocol.GetPlansRequestEntity() ); } catch (e) { console.error(e); } } public async addModeGroup(group_uuid: string, name: string) { try { return await this.doRpc( new Protocol.AddModeGroupRequestEntity(0, group_uuid, name) ); } catch (e) { console.error(e); } } public async editModeGroup(uuid: string, name: string, parent_uuid: string) { try { return await this.doRpc( new Protocol.EditModeGroupRequestEntity(0, uuid, name, parent_uuid) ); } catch (e) { console.error(e); } } public async updateModeWindowList(uuid: string) { try { return await this.doRpc( new Protocol.UpdateModeWindowListRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async deleteModeGroup(uuid: string) { try { return await this.doRpc( new Protocol.DeleteModeGroupRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public async addMode( group_uuid?: string, name?: string, index?: number, joint_action_equipments?: StringKeyValueEntity[] ) { try { return await this.doRpc( new Protocol.AddModeRequestEntity( 0, name, group_uuid, index, joint_action_equipments ) ); } catch (e) { console.error(e); } } public async editMode( uuid?: string, name?: string, index?: number, group_uuid?: string, joint_action_equipments?: StringKeyValueEntity[] ) { try { return await this.doRpc( new Protocol.EditModeRequestEntity( 0, name, uuid, index, group_uuid, joint_action_equipments ) ); } catch (e) { console.error(e); } } public async deleteMode(uuid: string) { try { return await this.doRpc( new Protocol.DeleteModeRequestEntity(0, uuid) ); } catch (e) { console.error(e); } } public callMode(uuid: string) { this.ws?.send(JSON.stringify(new Protocol.CallModeRequestEntity(uuid))); } public async getApplicationSettins() { try { return await this.doRpc( new Protocol.GetApplicationConfigRequestEntity() ); } catch (e) { console.error(e); } } public async getWindows() { try { return await this.doRpc( new Protocol.GetWindowsRequestEntity() ); } catch (e) { console.error(e); } } public async getDeviceAttribute() { try { return await this.doRpc( new Protocol.GetDeviceAttributeRequestEntity() ); } catch (e) { console.error(e); } } public setDeviceAttribute(attribute: number) { this.ws?.send( JSON.stringify(new Protocol.SetDeviceAttributeRequestEntity(attribute)) ); } 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 setWindowGeometry( window_id: number, x: number, y: number, width: number, height: number, limit: boolean = true ) { this.ws?.send( JSON.stringify( new Protocol.SetWindowGeometryRequestEntity( window_id, x, y, width, height, limit ) ) ); } public closeWindow(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.CloseWindowRequestEntity(window_id)) ); } public openWindow(data: Protocol.OpenWindowRequestEntity) { this.ws?.send(JSON.stringify(data)); } public replaceWindow(data: Protocol.ReplaceWindowRequestEntity) { this.ws?.send(JSON.stringify(data)); } public replaceWindow2( window_id: number, signal_source: string, polling?: boolean, ext_data?: string ) { this.replaceWindow( new Protocol.ReplaceWindowRequestEntity( window_id, signal_source, polling, ext_data ) ); } public openPolling(data: Protocol.OpenPollingRequestEntity) { this.ws?.send(JSON.stringify(data)); } public focusIn(window_id: number) { this.ws?.send( JSON.stringify( new NormalWindowRequestEntity(Protocol.Commands.kTopWindow, window_id) ) ); } public lowerWindow(window_id: number) { this.ws?.send( JSON.stringify( new NormalWindowRequestEntity(Protocol.Commands.kLowerWindow, window_id) ) ); } public setWallRowCol(wall_row: number, wall_col: number) { this.ws?.send( JSON.stringify( new Protocol.SetApplicationConfigRequestEntity( 0, "wall_row", wall_row.toString() ) ) ); this.ws?.send( JSON.stringify( new Protocol.SetApplicationConfigRequestEntity( 0, "wall_col", wall_col.toString() ) ) ); } public setSpecialVideoLayoutRotation(rotation: string) { this.ws?.send( JSON.stringify( new Protocol.SetApplicationConfigRequestEntity( 0, "special_video_layout_rotation", rotation ) ) ); } public setWebsocketPort(port: number) { this.ws?.send( JSON.stringify( new Protocol.SetApplicationConfigRequestEntity( 0, "websocket_port", port.toString() ) ) ); } public setHttpPort(port: number) { this.ws?.send( JSON.stringify( new Protocol.SetApplicationConfigRequestEntity( 0, "httpserver_port", port.toString() ) ) ); } public setPowerOnPlan(uuid: string) { this.ws?.send( JSON.stringify( new Protocol.SetApplicationConfigRequestEntity(0, "power_on_plan", uuid) ) ); } public windowFitGrid(window_id: number) { this.ws?.send( JSON.stringify( new NormalWindowRequestEntity( Protocol.Commands.kWindowFitGrid, window_id ) ) ); } public windowFullScreen(window_id: number, full_screen: boolean) { this.ws?.send( JSON.stringify(new Protocol.WindowFullScreen(window_id, full_screen)) ); } public async getSubtitle() { try { return await this.doRpc( new Protocol.GetSubtitleRequestEntity(0) ); } catch (e) { console.error(e); } } public async getRegisterInfo() { try { return await this.doRpc( new Protocol.GetRegisterInfoRequestEntity(0) ); } catch (e) { console.error(e); } } public async registerDevice( register_code: string, active_code: string, online: boolean, active_forever: boolean, secret_key?: string, hour?: number ) { try { return await this.doRpc( new Protocol.RegisterDeviceRequestEntity( register_code, active_code, online, active_forever, secret_key, hour, 0 ) ); } catch (e) { console.error(e); } } public async setSubtitle(subtitle: SubtitleEntity) { try { return await this.doRpc( new Protocol.SetSubtitleRequestEntity(0, subtitle) ); } catch (e) { console.error(e); } } public async setSystemNetwork( request: Protocol.SetSystemNetworkRequestEntity ) { return await this.doRpc(request); } public async setSystemGraphics( request: Protocol.SetSystemGraphicsRequestEntity ) { return await this.doRpc(request); } public async setSystemOther(request: Protocol.SetSystemOtherRequestEntity) { return await this.doRpc(request); } public async getSupportResolutions() { try { return await this.doRpc( new Protocol.GetSupportResolutionsRequestEntity(0) ); } catch (e) { console.error(e); } } public async getOutputBoardSetting() { try { return await this.doRpc( new Protocol.GetOutputBoardSettingRequestEntity(0) ); } catch (e) { console.error(e); } } public async setOutputBoardSetting( request: Protocol.SetOutputBoardSettingRequestEntity ) { try { return await this.doRpc( request ); } catch (e) { console.error(e); } } public async restoreOutputBoard() { try { return await this.doRpc( new Protocol.RestoreOutputBoardRequestEntity(0) ); } catch (e) { console.error(e); } } public async setWindowVolume(window_id: number, volume: number) { this.ws?.send( JSON.stringify( new Protocol.SetWindowVolumeRequestEntity(window_id, volume, 0) ) ); } public async unmuteWindow(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.UnMuteWindowRequestEntity(window_id, 0)) ); } public async muteWindow(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.MuteWindowRequestEntity(window_id, 0)) ); } public async playWindow(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.PlayWindowRequestEntity(window_id, 0)) ); } public async windowPlayNext(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.WindowPlayNextRequestEntity(window_id, 0)) ); } public async windowPlayPrev(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.WindowPlayPrevRequestEntity(window_id, 0)) ); } public async pauseWindow(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.PauseWindowRequestEntity(window_id, 0)) ); } public async startPolling(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.StartPollingRequestEntity(window_id)) ); } public async stopPolling(window_id: number) { this.ws?.send( JSON.stringify(new Protocol.StopPollingRequestEntity(window_id)) ); } public async setWindowPollingData( window_id: number, name: string, datas?: StringKeyValueEntity[] ) { return await this.doRpc( new Protocol.SetWindowPollingDataRequestEntity(window_id, name, datas) ); } public async getBuildInfo() { return await this.doRpc( new Protocol.GetBuildInfoRequestEntity(0) ); } public async getSystemTimes() { return await this.doRpc( new Protocol.GetSystemTimesRequestEntity(0) ); } public restoreDevice(delete_upload: boolean = false) { this.ws?.send( JSON.stringify(new Protocol.RestoreDeviceRequestEntity(delete_upload)) ); } public restartDevice(delay_ms?: number) { this.ws?.send( JSON.stringify(new Protocol.RestartDeviceRequestEntity(delay_ms)) ); } public async getUsbDevices() { try { return await this.doRpc( new Protocol.GetUsbDevicesRequestEntity(0) ); } catch (e) { console.error(e); } } public async getPollings() { try { return await this.doRpc( new Protocol.GetPollingsRequestEntity() ); } catch (e) { console.error(e); } } public async fileOperator( from_path: string, to_path: string, operator_type: string, force_operator: boolean = true ) { try { return await this.doRpc( new Protocol.FileOperatorRequestEntity( from_path, to_path, operator_type, force_operator ) ); } catch (e) { console.error(e); } } public async getEdgeBlendingInfo() { return await this.doRpc( new Protocol.GetEdgeBlendingInfoRequestEntity(0) ); } public async setEdgeBlendingInfo( enable_blending: boolean, enable_correct: boolean, width: number, height: number, col: number, row: number, point_count: number ) { return await this.doRpc( new Protocol.SetEdgeBlendingInfoRequestEntity( enable_blending, enable_correct, width, height, col, row, point_count, 0 ) ); } public async wakeUpDevice() { return await this.doRpc( new Protocol.SetDevicePowerRequestEntity( Protocol.SetDevicePowerRequestEntity.kPowerStatePowerOn ) ); } public async deviceStandByMode() { return await this.doRpc( new Protocol.SetDevicePowerRequestEntity( Protocol.SetDevicePowerRequestEntity.kPowerStateStandBy ) ); } public async getExternalControlDatas() { return await this.doRpc( new Protocol.RpcGetExternalControlDatasRequestEntity() ); } public async deleteExternalControlData(uuid: string) { return await this.doRpc( new Protocol.RpcDeleteExternalControlDataRequestEntity(uuid) ); } public async editExternalControlData(entity: ExternalControlTableEntity) { return await this.doRpc( new Protocol.RpcEditExternalControlDataRequestEntity(entity) ); } public async addExternalControlData(entity: ExternalControlTableEntity) { return await this.doRpc( new Protocol.RpcAddExternalControlDataRequestEntity(entity) ); } public async getExternalControlSerialPortConfig() { return await this.doRpc( new Protocol.RpcGetExternalControlSerialPortConfigRequestEntity() ); } public async setExternalControlSerialPortConfig( config: SerialPortConfigEntity ) { return await this.doRpc( new Protocol.RpcSetExternalControlSerialPortConfigRequestEntity(config) ); } public callExternalControlData(uuid: string) { this.ws?.send( JSON.stringify(new Protocol.CallExternalControlDataRequestEntity(uuid)) ); } public setEdgeBlendingPoint(point: EdgeBlendingPoint) { this.ws?.send( JSON.stringify(new Protocol.SetEdgeBlendingPointRequestEntity(point)) ); } public setServerLanguage(language: string) { this.ws?.send( JSON.stringify(new Protocol.SetLanguageRequestEntity(language)) ); } public async getConnectList() { return await this.doRpc( new Protocol.GetConnectionListRequestEntity() ); } public async setConnectItem(entity: ConnectTableEntity) { return await this.doRpc( new Protocol.SetConnectionItemRequestEntity(entity) ); } public async getTimingTasks() { try { return await this.doRpc( new Protocol.GetTimingTasksRequestEntity() ); } catch (e) { console.error(e); } } public async addTimingTask(task: TimingTaskEntity) { try { return await this.doRpc( new Protocol.AddTimingTaskRequestEntity(task) ); } catch (e) { console.error(e); } } public async editTimingTask(task: TimingTaskEntity) { try { return await this.doRpc( new Protocol.EditTimingTaskRequestEntity(task) ); } catch (e) { console.error(e); } } public async deleteTimingTask(uuid: string) { try { return await this.doRpc( new Protocol.DeleteTimingTaskRequestEntity(uuid) ); } catch (e) { console.error(e); } } public async getSystemNetworkInfo() { try { return await this.doRpc( new Protocol.GetSystemNetworkInfoRequestEntity() ); } catch (e) { console.error(e); } } public async setHdmiInDecodeType(index: number, type: string) { try { return await this.doRpc( new Protocol.SetHdmiInDecodeTypeRequestEntity(index, type) ); } catch (e) { console.error(e); } } public async getCityList(language?: string) { try { return await this.doRpc( new Protocol.GetCityListRequestEntity(language) ); } catch (e) { console.error(e); } } public async getPowerState() { try { return await this.doRpc( new Protocol.GetPowerStateRequestEntity() ); } catch (e) { console.error(e); } } public async getJointActionEquipments() { return await this.doRpc( new Protocol.GetJointActionEquipmentRequestEntity() ); } public async setJointActionEquipment( entity: JointActionEquipmentTableEntity ) { return await this.doRpc( new Protocol.SetJointActionEquipmentRequestEntity(entity) ); } public async deleteJointActionEquipment(uuid: string) { return await this.doRpc( new Protocol.DeleteJointActionEquipmentRequestEntity(uuid) ); } public destory() { this.ws?.close(); if (this.ws) { this.ws.onclose = null; this.ws.onerror = null; this.ws.onopen = null; this.ws.onmessage = null; } this.ws = null; } } export interface NotifyMessage { packet: Protocol.PacketEntity; data: string; }