WebSocket 的简单用法

// 与服务器定义的返回字段信息
enum SocketEvents {
    taken_offline = "taken_offline"
}

export { SocketEvents }

interface SocketEvent {
    event: SocketEvents,
    message: string,
    data: any
}

type SocketEventListener = (event: SocketEvent) => void

type removeEventListen = () => void

/**
 *  创建一个websocket的构造函数! 结合发布订阅模式
 */
class SocketManager {
    private socket!: WebSocket
    private socketListeners = new Set<SocketEventListener>()
    private isConnect = false
    private isTimeout = false
    private keepAliveTimeInterval!: NodeJS.Timeout
    private checkTimeoutTimer!: NodeJS.Timeout
    private reTryTimes = 0 // 重连次数

    public async start() {
        // 设置需要建立联系的地址
        let cashierWssAddress = ""
        if (process.env.NODE_ENV === "development") {
            cashierWssAddress = "https://xxxx.xxxx.xx".replace('https', "wss")
        } else {
            cashierWssAddress = '生成环境地址'.replace('https', "wss")
        }

        this.socket = new WebSocket(cashierWssAddress)
        this.socket.onopen = this.onOpen.bind(this)
        this.socket.onmessage = this.onMessage.bind(this)
        this.socket.onerror = this.onError.bind(this)
        this.socket.onclose = this.onClose.bind(this)
    }

    public stop() {
        if (this.socket) {
            this.socket.close()
        }
        clearInterval(this.checkTimeoutTimer)
        clearInterval(this.keepAliveTimeInterval)
    }

    public addEventListener(fn: SocketEventListener): removeEventListen {
        this.socketListeners.add(fn)

        return () => {
            this.socketListeners.delete(fn)
        }
    }

    public removeEventListener(fn: SocketEventListener) {
        this.socketListeners.delete(fn)
    }

    private onOpen(event: Event) {
        console.log('socket 建立连接')
        this.isConnect = true
        this.reTryTimes = 0
        this.keepAlive()
    }

    private onMessage(event: MessageEvent) {
        const data = JSON.parse(event.data)
        console.log('socket 收到消息', data)
        this.dispathEvent(data)

        if (this.checkTimeoutTimer) {
            clearTimeout(this.checkTimeoutTimer)
        }
        this.isTimeout = false
        this.checkTimeoutTimer = setTimeout(() => {
            if (this.isConnect) {
                this.isTimeout = true
                console.log('socket 连接超时')
            }
        }, 40 * 1000)
    }

    private onError(event: Event) {
        if (this.reTryTimes < 5) {
            console.log("连接失败")
        } else {
            console.log('socket 通信错误', event)
            this.isConnect = false
            // openMessage(MessageType.error, "socket连接失败,将无法使用系统")
            setTimeout(() => {
                // System.logout().then(() => {
                //     window.location.href = PASSPORT_DOMAIN + '/#/login?oa=new_ls'
                // })
            }, 3 * 1000)
        }
    }

    private onClose(ev: CloseEvent) {
        console.log('socket 连接关闭')
        this.isConnect = false
        if (this.reTryTimes < 5) {
            this.reTryTimes++
            // openMessage(MessageType.info, "socket 断开连接,尝试第" + this.reTryTimes + "次重连")
            setTimeout(() => {
                this.start()
            }, 3 * 1000)
        }
    }

    private keepAlive() {
        clearInterval(this.keepAliveTimeInterval) // 防止重复调用
        this.keepAliveTimeInterval = setInterval(() => {
            if (!this.isConnect) {
                return clearInterval(this.keepAliveTimeInterval)
            }
            if (this.isTimeout) {
                return this.start()
            }

            if (this.socket) {
                this.socket.send('❤️')
            } else {
                clearInterval(this.keepAliveTimeInterval)
            }
        }, 10 * 1000)
    }

    private dispathEvent(event: SocketEvent) {
        this.socketListeners.forEach(fn => fn(event))
    }
}

const socketManager = new SocketManager()

socketManager.addEventListener((socketEvent) => {

    switch (socketEvent.event) {
        case SocketEvents.taken_offline:
            // reactHistory.push("/noSeat")
            break
    }
})


export {
    socketManager
}

posted @ 2020-09-05 10:07  yaogengzhu  阅读(424)  评论(0编辑  收藏  举报