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