From 4572c2060dfc43df7c5201d830e6d80d8f9ce1fb Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 24 Jan 2024 16:07:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ws=20=E5=8E=9F=E7=94=9F=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=97=A0=E6=B3=95=E5=B8=A6hearde?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/ws-websocket.ts | 164 ++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 src/plugins/ws-websocket.ts diff --git a/src/plugins/ws-websocket.ts b/src/plugins/ws-websocket.ts new file mode 100644 index 00000000..6c5b34a7 --- /dev/null +++ b/src/plugins/ws-websocket.ts @@ -0,0 +1,164 @@ +import { sessionGet } from "@/utils/cache-session-utils"; + +/**连接参数类型 */ +export type TypeParams = { + /**WebSocket服务器将响应的URL */ + url?: string; + /**onopen事件的回调函数 */ + onopen?: Function; + /**message事件的回调函数 */ + onmessage: Function; + /**error事件的回调函数 */ + onerror: Function; + /**close事件的回调函数 */ + onclose?: Function; + /**心跳周期 若为0则不启用 */ + heartTimer?: number; + /**重连等待 若为0则不启用 */ + reconnectTimer?: number; +}; + +/** + * WebSocket 使用方法 + * + * import WS from '@/plugins/ws-websocket.ts'; + * const options = { + * url: 'ws://127.0.0.1:8080', + * onmessage: (res) => { + * // 接收数据后回调 + * }, + * // 保活周期 10s + * timer: 10000, + * // 断线重连 + * reconnect: true, + * }; + * const ws = new WS(options); + * + * 手动关闭 + * ws.close(); + */ +export class WS { + /**ws 实例 */ + private ws: WebSocket | null = null; + /**ws 连接参数 */ + private params: TypeParams | null = null; + /**心跳调度器 */ + private heartInterval: number = 0; + /**重连定时器 */ + private reconnectTimeout: number = 0; + + /** + * 构造函数 + * @param {object} params 构造函数参数 + */ + constructor(params: TypeParams) { + if (!window.WebSocket) { + // 检测浏览器支持 + console.error('抱歉! 浏览器不支持websocket'); + return; + } + this.params = params; + this.create(params); + } + + /** + * 创建链接 + * @param {object} params 连接参数 + */ + public create(params: TypeParams) { + try { + if (!params.url) { + // 兼容旧前端可改配置文件 + const baseUrl = import.meta.env.PROD + ? sessionGet('wsUrl') || import.meta.env.VITE_API_BASE_URL + : import.meta.env.VITE_API_BASE_URL; + params.url = `ws://${baseUrl}/ws`; + } + + const ws = new WebSocket(params.url); + // 用于指定连接成功后的回调函数。 + ws.onopen = ev => { + if (params.heartTimer && params.heartTimer > 0) { + this.heartCheck(params.heartTimer); + } + if (typeof params.onopen === 'function') { + params.onopen(ev); + } + }; + // 用于指定当从服务器接受到信息时的回调函数。 + ws.onmessage = ev => { + if (typeof params.onmessage === 'function') { + params.onmessage(ev); + } + }; + // 用于指定连接关闭后的回调函数。 + ws.onclose = ev => { + if (typeof params.onclose === 'function') { + params.onclose(ev); + } + }; + // 用于指定连接失败后的回调函数。 + ws.onerror = ev => { + console.error('websocket 连接异常', ev); + + if (typeof params.onerror === 'function') { + params.onerror(ev); + } + if (params.reconnectTimer && params.reconnectTimer > 0) { + this.reconnect(params.reconnectTimer); + } + }; + this.ws = ws; + } catch (error) { + if (typeof params.onerror === 'function') { + params.onerror(error); + } + if (params.reconnectTimer && params.reconnectTimer > 0) { + this.reconnect(params.reconnectTimer); + } + } + } + + // 发送消息 + send(data: Record) { + if (!this.ws) { + console.warn('websocket 不可用'); + return; + } + console.log(' readyState', this.ws.readyState); + + this.ws.send(JSON.stringify(data)); + } + + // 手动关闭socket + close() { + this.heartInterval && clearInterval(this.heartInterval); + this.reconnectTimeout && clearTimeout(this.reconnectTimeout); + if (!this.ws) { + console.warn('websocket 不可用'); + return; + } + this.ws.close(WebSocket.CLOSED); + } + + // 周期性发送ping 保活 + heartCheck(heartTimer: number) { + this.heartInterval = window.setInterval(() => { + this.send({ + type: 'ping', + }); + }, heartTimer); + } + + // 断线重连 + reconnect(reconnectTimer: number) { + if (this.reconnectTimeout > 0) return; + clearTimeout(this.reconnectTimeout); + this.reconnectTimeout = window.setTimeout(() => { + if (this.params) { + this.create(this.params); + this.reconnectTimeout = 0; + } + }, reconnectTimer); + } +}