
class Ws {
    constructor(ws, data, ...args) { // [{url, data, method...},,,,]
        this._ws = ws;
        this._data = data;
        // 待发送的消息列
        this._msgs = []

        this.socket = this.doLink();
        this.doOpen();
        // 订阅/发布模型
        this._events = {};
        // 是否保持连接
        this._isLink = true;
        // 订阅列表(交易所专用)
        this.subs = []
        // 循环检查
        setInterval(() => {
            if (this._isLink) {
                if (this.socket.readyState == 2 || this.socket.readyState == 3) {
                    this.resetLink()
                }
            }
        }, 3000)
    }
    // 重连
    resetLink() {
        this.socket = this.doLink(() => {
            this.Notify({
                Event: 'resetLink'
            });
            this.resetSub()
        });
        this.doOpen();
    }
    // 连接
    doLink(call) {
        let ws = uni.connectSocket({
            url: this._ws,
            // 可选参数 设置默认值
            header: {
                'content-type': 'application/json'
            },
            method: 'GET',
            success: () => {
                call && call()
            }
        })
        return ws;
    }
    doOpen() {
        this.socket.onOpen((ev) => {
            this.onOpen(ev)
        })
        this.socket.onMessage((ev) => {
            this.onMessage(ev)
        })
        this.socket.onClose((ev) => {
            this.onClose(ev)
        })
        this.socket.onError((ev) => {
            this.onError(ev)
        })

    }
    // 打开
    onOpen() {
        // 打开时重发未发出的消息
        let list = Object.assign([], this._msgs)
        list.forEach((item) => {
            if (this.send(item)) {
                let idx = this._msgs.indexOf(item)
                if (idx != -1) {
                    this._msgs.splice(idx, 1)
                }
            }
        })
    }
    // 手动关闭
    doClose() {
        this._isLink = false
        this._events = {}
        this._msgs = []
        this.socket.close({
            success: () => {
                console.log('socket close success')
            }
        })
    }
    // 添加监听
    on(name, handler) {
        this.subscribe(name, handler);
    }
    // 取消监听
    off(name, handler) {
        this.unsubscribe(name, handler);
    }
    // 关闭事件
    onClose() {
        // 是否重新连接
        if (this._isLink) {
            setTimeout(() => {
                this.resetLink()
            }, 3000)
        }
    }
    // 错误
    onError(evt) {
        this.Notify({
            Event: 'error',
            Data: evt
        });

    }
    // 接受数据
    onMessage(evt) {
        try {

            // 解析推送的数据
            const data = JSON.parse(evt.data);

            // 通知订阅者
            this.Notify({
                Event: 'message',
                Data: data
            });

        } catch (err) {
            console.error(' >> Data parsing error:', err);
            // 通知订阅者
            this.Notify({
                Event: 'error',
                Data: err
            });
        }
    }
    // 订阅事件的方法
    subscribe(name, handler) {
        if (this._events.hasOwnProperty(name)) {
            this._events[name].push(handler); // 追加事件
        } else {
            this._events[name] = [handler]; // 添加事件
        }
    }
    // 取消订阅事件
    unsubscribe(name, handler) {
        let start = this._events[name].findIndex(item => item === handler);
        // 删除该事件
        this._events[name].splice(start, 1);
    }
    // 发布后通知订阅者
    Notify(entry) {
        // 检查是否有订阅者 返回队列
        const cbQueue = this._events[entry.Event];
        if (cbQueue && cbQueue.length) {
            for (let callback of cbQueue) {
                if (callback instanceof Function) callback(entry.Data);
            }
        }
    }
    // 发送消息
    send(data) {
        this.changeSubs(data)
        if (this.socket.readyState == 1) {
            this.socket.send({ data: JSON.stringify(data) })
            return true
        } else {
            // 保存到待发送信息
            if (!this._msgs.includes(data)) {
                this._msgs.push(data)
            };
            return false
        }

    }
    // 修改订阅列表（交易所用）
    changeSubs(data) {
        if (data.cmd == 'sub') {
            if (!this.subs.includes(data.msg)) {
                this.subs.push(data.msg)
            }
        } else if (data.cmd == 'unsub') {
            let idx = this.subs.indexOf(data.msg)
            if (idx != -1) {
                this.subs.splice(idx, 1)
            }
        }
    }
    // 重新订阅（交易所用）
    resetSub() {
        let list = Object.assign([], this.subs)
        list.forEach((item) => {
            this.send({
                cmd: 'sub',
                msg: item
            })
        })
    }
}
export default Ws