EverSocket.js 7.3 KB
// //////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2016-present
//  All Rights Reserved.
//
//  Author: AlexWang
//  Date: 2016-08-27 21:40:49
//  Last Modified by:   AlexWang
//  Last Modified time: 2016-12-05 12:02:48
//  QQ Email: 1669499355@qq.com
//  Description: 底层Socket管理器,保持一直在线及异常重连.
//
// //////////////////////////////////////////////////////////////////////////////

import Emiter from 'Emiter';
import Loger from 'Loger';
let loger = Loger.getLoger('EverSocket');
const MCU_MAX_RECONNECTION = 4;//最多重连次数
class EverSocket extends Emiter {
    constructor() {
        super();
        this._connected = false;
        this._lastActiveTime = 0;//最后一次收到消息的时间
        this._enableEverSocket = false;
        this.reConnectionCounter = 0;//重连次数

    }

    begin(ip, port) {
        this._clearHistory();
        loger.log('开始WebSocket应用.');
        this._enableEverSocket = true;
        this.wsURL = 'ws://' + ip + ':' + port;
        this._newConnection();
    }

    end() {
        loger.log('停止WebSocket应用.');
        this._clear();
    }
    switchSocketIp(ip,port) {
        if(port){
            this.wsURL = 'ws://' + ip + ':' + port;
        }else {
            this.wsURL = 'ws://' + ip;
        }
    }
    get connected() {
        return this._connected;
    }

    send(data) {
        if (this._connected) {
            if (data) {
                loger.log('SEND MESSAGE-->byteLength->', data.byteLength);
            } else {
                loger.log('SEND MESSAGE---->');
            }
            this.websocket.send(data);
        } else {
            loger.warn('WebSocket未建立连接.消息忽略');
        }
    }

    _setConnected(isConn = true) {
        this._connected = isConn;
        if (this._connected) {
            this._emit(EverSocket.OPEN);
        } else {
            this._emit(EverSocket.CLOSED);
        }
    }

    _newConnection() {
        this.websocket = new WebSocket(this.wsURL);
        this.websocket.binaryType = 'arraybuffer';
        this.websocket.onopen = this._onOpen.bind(this);
        this.websocket.onclose = this._onClose.bind(this);
        this.websocket.onerror = this._onError.bind(this);
        this.websocket.onmessage = this._onMessage.bind(this);
    }

    _reConnection() {
        this._clear();
        window.clearTimeout(this.reConnectionTimeout);
        this.reConnectionCounter++;
        if (this.reConnectionCounter > MCU_MAX_RECONNECTION) {
            loger.warn('MCU断线重连->已经达到最大重连次数!');
            this._emit(EverSocket.ERROR, EverSocket.ERR_SOCKET_RECONNECT_FAILED);
            this.reConnectionCounter=0;
        }

        this.reConnectionTimeout = window.setTimeout(() => {
            loger.log('MCU断线重连->', this.reConnectionCounter);
            window.clearTimeout(this.reConnectionTimeout);
            this._newConnection();
        }, EverSocket.RECONN_INTERVAL);
    }

    _clear() {
        loger.log('WebSocket,Timers销毁');
        window.clearInterval(this.pingTimer);
        window.clearInterval(this.pongTimer);
        window.clearInterval(this.reConnectionTimeout);
        this._setConnected(false);//先设置状态
        this._enableEverSocket = false;
        if (this.websocket == null) {
            loger.log('WebSocket,Timers已经销毁');
            return;
        }
        this.websocket.onopen = undefined;
        this.websocket.onclose = undefined;
        this.websocket.onerror = undefined;
        this.websocket.onmessage = undefined;
        try {
            this.websocket.close();
        } catch (e) {
            loger.log('ignore errors');
        }
        this.websocket = undefined;

    }
    _clearHistory(){
        loger.log('WebSocket->清除记录');
        window.clearInterval(this.pingTimer);
        window.clearInterval(this.pongTimer);
        window.clearInterval(this.reConnectionTimeout);
        //this._setConnected(false);//先设置状态
        this._connected = false;
        this._enableEverSocket = false;
        if (this.websocket == null) {
            loger.log('WebSocket->已经销毁');
            return;
        }
        this.websocket.onopen = undefined;
        this.websocket.onclose = undefined;
        this.websocket.onerror = undefined;
        this.websocket.onmessage = undefined;
        try {
            this.websocket.close();
        } catch (e) {
            loger.log('ignore errors');
        }
        this.websocket = undefined;
    }
    _onOpen() {
        loger.log('WebSocket建立成功', this.wsURL);
        this.reConnectionCounter = 0;

        //启动心跳,检查socket链接状态
        this.pingTimer = window.setInterval(this._sendPingHandler.bind(this), EverSocket.PING_INTERVAL);
        this.pongTimer = window.setInterval(this._checkPongHandler.bind(this), EverSocket.PONG_INTERVAL);

        this._setConnected();
    }

    _onClose(closeEvent) {
        loger.log(`WebSocket连接断开 CODE:${closeEvent.code} REASON:${closeEvent.reason} CLEAN: ${closeEvent.wasClean}`, this.wsURL);
        this._reConnection();
    }

    _onError() {
        loger.log('WebSocket错误出现');
        this._connected = false;
        this._reConnection();
    }

    _onMessage(messageEvent) {
        this._lastActiveTime = Date.now();
        const bufferData = messageEvent.data;
        loger.log('RECEIVE MESSAGE-->byteLength->',bufferData.byteLength);
        if (bufferData.byteLength > 0) {
            this._emit(EverSocket.MESSAGE, bufferData);
        }
    }

    _sendPingHandler() {
        if (this._connected) {
            this.websocket.send(new ArrayBuffer);
        } else {
            this._reConnection();
        }
    }

    _checkPongHandler() {
        let pongTime = Date.now();
        if (this._lastActiveTime &&
            this._lastActiveTime >= pongTime - EverSocket.PONG_INTERVAL &&
            this._lastActiveTime <= pongTime
        ) {

        } else {
            loger.warn('---服务器PINGPONG超时-----');
            this._reConnection();
        }
    }
}


/*//修改之前的
 EverSocket.prototype.PONG_INTERVAL = EverSocket.PONG_INTERVAL = 5000;
 EverSocket.prototype.PING_INTERVAL = EverSocket.PING_INTERVAL = 3000;
 EverSocket.prototype.RECONN_INTERVAL = EverSocket.RECONN_INTERVAL = 2000;*/


//20170223-mcu服务端修改了心跳的逻辑,如果客户端30秒没有请求,就会按离开的处理
//目前客户端发送心跳请求的空数据,服务端不会每次都回,暂定为10秒心跳一次
EverSocket.prototype.PONG_INTERVAL = EverSocket.PONG_INTERVAL = 21000;//
EverSocket.prototype.PING_INTERVAL = EverSocket.PING_INTERVAL = 10000;//心跳间隔
EverSocket.prototype.RECONN_INTERVAL = EverSocket.RECONN_INTERVAL = 5000;//重连的间隔


EverSocket.prototype.ERR_SOCKET_RECONNECT_FAILED =EverSocket.ERR_SOCKET_RECONNECT_FAILED=20001;//MCU自动重连失败,已经达到最大重连次数

EverSocket.prototype.CONNECTING = EverSocket.CONNECTING = 0;
EverSocket.prototype.OPEN = EverSocket.OPEN = 1;
EverSocket.prototype.CLOSING = EverSocket.CLOSING = 2;
EverSocket.prototype.CLOSED = EverSocket.CLOSED = 3;
EverSocket.prototype.MESSAGE = EverSocket.MESSAGE = 4;
EverSocket.prototype.ERROR = EverSocket.ERROR = 5;
export default new EverSocket();