1/* 2 * Copyright (C) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15import { Utils, MessageParam } from "./Util" 16import { Constants, TypeConstants } from "./Constants"; 17 18export class WebSocketManager { 19 static instance: WebSocketManager | null | undefined = null; 20 url: string = 'ws://localhost:18080';//8080后期需要修改 21 private websocket: WebSocket | null | undefined = null; 22 private ready: boolean = false; 23 private distributeMap: Map<number, Function> = new Map<number, Function>(); 24 private sessionId: number | null | undefined; 25 private session: bigint | null | undefined; 26 private heartbeatInterval: number | null | undefined; 27 28 constructor() { 29 if (WebSocketManager.instance) { 30 return WebSocketManager.instance; 31 } 32 WebSocketManager.instance = this; 33 //连接websocket 34 this.connectWebSocket(); 35 } 36 //连接WebSocket 37 connectWebSocket(): void { 38 this.websocket = new WebSocket(this.url); 39 this.websocket.binaryType = "arraybuffer"; 40 this.websocket.onopen = () => { 41 // 设置心跳定时器 42 this.sendHeartbeat(); 43 // 连接后登录 44 this.login(); 45 }; 46 47 //接受webSocket的消息 48 this.websocket.onmessage = (event) => { 49 // 先解码 50 let decode: MessageParam = Utils.decode(event.data); 51 if (decode.type === TypeConstants.HEARTBEAT_TYPE) { 52 return; 53 } 54 this.onmessage(decode!); 55 }; 56 57 this.websocket.onerror = (error) => { 58 console.error('error:', error); 59 }; 60 61 this.websocket.onclose = (event) => { 62 this.initLoginInfor(); 63 this.clearHeartbeat(); 64 this.reconnect(event); 65 }; 66 } 67 68 /** 69 * 接收webSocket返回的buffer数据 70 * 分别处理登录、其他业务的数据 71 * 其他业务数据分发 72 */ 73 onmessage(decode: MessageParam): void { 74 // 解码event 调decode 75 if (decode.type === TypeConstants.LOGIN_TYPE) {// 登录 76 if (decode.cmd === Constants.LOGIN_CMD) { 77 this.ready = true; 78 this.sessionId = decode.session_id; 79 this.session = decode.session; 80 } 81 } else {// type其他 82 for (let [key, callback] of this.distributeMap.entries()) { 83 if (key === decode.type) { 84 callback(decode.cmd, decode.data); 85 } 86 }; 87 } 88 } 89 90 // 登录 91 login(): void { 92 this.websocket!.send(Utils.encode(Constants.LOGIN_PARAM)); 93 } 94 95 // 模块调 96 static getInstance(): WebSocketManager | null | undefined { 97 if (!WebSocketManager.instance) { 98 new WebSocketManager(); 99 } 100 return WebSocketManager.instance 101 } 102 103 // WebSocket是否登录成功 104 isReady(): boolean { 105 return this.ready 106 } 107 108 /** 109 * 消息监听器 110 * listener是不同模块传来接收数据的函数 111 * 模块调用 112 */ 113 registerMessageListener(type: number, callback: Function): void { 114 if (!this.distributeMap.has(type)) { 115 this.distributeMap.set(type, callback); 116 } 117 } 118 119 /** 120 * 传递数据信息至webSocket 121 * 模块调 122 */ 123 sendMessage(type: number, cmd?: number, data?: Uint8Array): void { 124 // 检查WebSocket是否登录成功 125 if (!this.ready) {// 改判断条件 ready 126 return; 127 } 128 let message: MessageParam = { 129 type: type, 130 cmd: cmd, 131 session_id: this.sessionId!, 132 session: this.session!, 133 data_lenght: data ? data.byteLength : undefined, 134 data: data 135 } 136 let encode = Utils.encode(message); 137 this.websocket!.send(encode!); 138 } 139 140 /** 141 * 传递数据信息至webSocket 142 * 模块调 143 */ 144 reconnect(event: unknown) { 145 //@ts-ignore 146 if (event.wasClean) {// 正常关闭 147 return 148 } 149 // 未连接成功打开定时器 150 setTimeout(() => { 151 this.connectWebSocket(); 152 }, Constants.INTERVAL_TIME) 153 } 154 155 // 定时检查心跳 156 sendHeartbeat() { 157 this.heartbeatInterval = window.setInterval(() => { 158 this.sendMessage(TypeConstants.HEARTBEAT_TYPE) 159 }, Constants.INTERVAL_TIME) 160 } 161 162 /** 163 * 重连时初始化登录信息 164 * 在异常关闭时调用 165 */ 166 initLoginInfor() { 167 this.ready = false; 168 this.sessionId = null; 169 this.session = null; 170 } 171 172 // 连接关闭时,清除心跳 173 clearHeartbeat() { 174 if (this.heartbeatInterval) { 175 clearInterval(this.heartbeatInterval); 176 this.heartbeatInterval = null; 177 } 178 } 179} 180