|
@@ -2,6 +2,8 @@ import { isDevMode } from '@/utils/env'
|
|
|
import { message } from 'antd'
|
|
import { message } from 'antd'
|
|
|
import type { MessageType } from '@/types/typing'
|
|
import type { MessageType } from '@/types/typing'
|
|
|
import wsNotice from '@/components/RightContent/Book/components/wsNotice'
|
|
import wsNotice from '@/components/RightContent/Book/components/wsNotice'
|
|
|
|
|
+import { isNullOrUnDef } from './is'
|
|
|
|
|
+import { tryChangeWorkStatus } from '@/components/RightContent/Book'
|
|
|
|
|
|
|
|
enum ReadyState {
|
|
enum ReadyState {
|
|
|
Connecting = 0,
|
|
Connecting = 0,
|
|
@@ -11,6 +13,8 @@ enum ReadyState {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export enum CmdType {
|
|
export enum CmdType {
|
|
|
|
|
+ /** 心跳 */
|
|
|
|
|
+ HEART_BEAT = 0,
|
|
|
/** @name 通知、消息 */
|
|
/** @name 通知、消息 */
|
|
|
NoticeOrMessage = 13,
|
|
NoticeOrMessage = 13,
|
|
|
/** @name 在线员工列表 */
|
|
/** @name 在线员工列表 */
|
|
@@ -20,8 +24,8 @@ export enum CmdType {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
interface Options {
|
|
interface Options {
|
|
|
- // reconnectLimit?: number;
|
|
|
|
|
- // reconnectInterval?: number;
|
|
|
|
|
|
|
+ reconnectLimit?: number
|
|
|
|
|
+ reconnectInterval?: number // ♥跳间隔时长
|
|
|
onOpen?: (event: WebSocketEventMap['open']) => void
|
|
onOpen?: (event: WebSocketEventMap['open']) => void
|
|
|
onClose?: (event: WebSocketEventMap['close']) => void
|
|
onClose?: (event: WebSocketEventMap['close']) => void
|
|
|
onMessage?: (message: WebSocketEventMap['message']) => void
|
|
onMessage?: (message: WebSocketEventMap['message']) => void
|
|
@@ -29,16 +33,27 @@ interface Options {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class Ws {
|
|
class Ws {
|
|
|
|
|
+ private uid: string // 用户id
|
|
|
public uri: string // websocket 链接地址
|
|
public uri: string // websocket 链接地址
|
|
|
public opts?: Options // websocket 链接相关配置
|
|
public opts?: Options // websocket 链接相关配置
|
|
|
- private isLock: boolean // 防止多次重连
|
|
|
|
|
- public timeout?: number // ♥跳间隔时长
|
|
|
|
|
|
|
+ private isLock: boolean // 断开锁
|
|
|
|
|
+ private reconnectLimit: number // 重连限制锁
|
|
|
|
|
+ private timer: NodeJS.Timeout | undefined // 重连 延时函数
|
|
|
|
|
+ private sTimer: NodeJS.Timeout | undefined // ♥跳 延时函数
|
|
|
|
|
+ private sinTimer: NodeJS.Timeout | undefined // ♥跳
|
|
|
public wsIns: WebSocket | undefined // websocket实例
|
|
public wsIns: WebSocket | undefined // websocket实例
|
|
|
|
|
|
|
|
// 初始化socket,一般在应用启动时初始化一次就好了,或者需要更换wsUrl
|
|
// 初始化socket,一般在应用启动时初始化一次就好了,或者需要更换wsUrl
|
|
|
- public init(uri: string, opts?: Options) {
|
|
|
|
|
|
|
+ public init(uid: string, uri: string, opts?: Options) {
|
|
|
|
|
+ this.uid = uid
|
|
|
this.uri = uri
|
|
this.uri = uri
|
|
|
this.opts = opts
|
|
this.opts = opts
|
|
|
|
|
+ this.reconnectLimit = 0
|
|
|
|
|
+ if (isNullOrUnDef(this.uri)) {
|
|
|
|
|
+ throw new Error('websocket连接地址不能为空')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (!this.wsIns || this.wsIns?.readyState === ReadyState.Closed) {
|
|
if (!this.wsIns || this.wsIns?.readyState === ReadyState.Closed) {
|
|
|
this.connectWs()
|
|
this.connectWs()
|
|
|
}
|
|
}
|
|
@@ -62,16 +77,35 @@ class Ws {
|
|
|
try {
|
|
try {
|
|
|
this.wsIns = new WebSocket(this.uri)
|
|
this.wsIns = new WebSocket(this.uri)
|
|
|
this.wsIns.onmessage = msg => {
|
|
this.wsIns.onmessage = msg => {
|
|
|
|
|
+ this.heartCheck()
|
|
|
|
|
+ // 心跳检测事件, 什么事情都不用干
|
|
|
|
|
+ if (msg.data === 'pong') {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
this.opts?.onMessage?.(JSON.parse(msg.data))
|
|
this.opts?.onMessage?.(JSON.parse(msg.data))
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ this.wsIns.onopen = event => {
|
|
|
|
|
+ // this.heartCheck()
|
|
|
|
|
+ tryChangeWorkStatus(this.uid, window.location.pathname)
|
|
|
|
|
+ this.opts?.onOpen?.(event)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
this.wsIns.onclose = event => {
|
|
this.wsIns.onclose = event => {
|
|
|
|
|
+ this.reconnect()
|
|
|
this.opts?.onClose?.(event)
|
|
this.opts?.onClose?.(event)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
this.wsIns.onerror = err => {
|
|
this.wsIns.onerror = err => {
|
|
|
|
|
+ this.reconnect()
|
|
|
this.opts?.onError?.(err)
|
|
this.opts?.onError?.(err)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
|
|
|
|
|
+ window.addEventListener('beforeunload', () => {
|
|
|
|
|
+ this.wsIns?.close()
|
|
|
|
|
+ })
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- // 未来要做心跳机制
|
|
|
|
|
if (isDevMode()) {
|
|
if (isDevMode()) {
|
|
|
message.error(error.toString())
|
|
message.error(error.toString())
|
|
|
}
|
|
}
|
|
@@ -79,17 +113,51 @@ class Ws {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /** 发送消息 */
|
|
|
public sendMessage(map: MessageType) {
|
|
public sendMessage(map: MessageType) {
|
|
|
if (this.wsIns?.readyState === ReadyState.Open) {
|
|
if (this.wsIns?.readyState === ReadyState.Open) {
|
|
|
this.wsIns.send(JSON.stringify(map))
|
|
this.wsIns.send(JSON.stringify(map))
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /** 断线重连 */
|
|
|
public disconnect() {
|
|
public disconnect() {
|
|
|
if (this.wsIns?.readyState === ReadyState.Open) {
|
|
if (this.wsIns?.readyState === ReadyState.Open) {
|
|
|
|
|
+ this.isLock = true
|
|
|
this.wsIns.close()
|
|
this.wsIns.close()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /** ♥跳检测 */
|
|
|
|
|
+ private heartCheck() {
|
|
|
|
|
+ this.sTimer && clearTimeout(this.sTimer)
|
|
|
|
|
+ this.sinTimer && clearInterval(this.sinTimer)
|
|
|
|
|
+ this.sTimer = setTimeout(() => {
|
|
|
|
|
+ // 发送♥跳
|
|
|
|
|
+ this.sendMessage({ cmd: CmdType.HEART_BEAT, dstid: this.uid })
|
|
|
|
|
+ this.sinTimer = setTimeout(() => {
|
|
|
|
|
+ if (this.wsIns.readyState !== ReadyState.Open) {
|
|
|
|
|
+ this.wsIns.close()
|
|
|
|
|
+ }
|
|
|
|
|
+ }, this.opts.reconnectInterval)
|
|
|
|
|
+ }, this.opts.reconnectInterval)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 重连
|
|
|
|
|
+ private reconnect(): void {
|
|
|
|
|
+ if (
|
|
|
|
|
+ this.isLock ||
|
|
|
|
|
+ (this.opts?.reconnectLimit && this.reconnectLimit > this.opts?.reconnectLimit)
|
|
|
|
|
+ ) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.reconnectLimit += 1
|
|
|
|
|
+ this.timer && clearTimeout(this.timer)
|
|
|
|
|
+ this.timer = setTimeout(() => {
|
|
|
|
|
+ this.connectWs()
|
|
|
|
|
+ this.isLock = false
|
|
|
|
|
+ }, 4000)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
export function onMessage(msg: MessageType) {
|
|
export function onMessage(msg: MessageType) {
|
|
|
// 这里执行所有的message监听事件
|
|
// 这里执行所有的message监听事件
|