EverSocket.js 4.9 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');

class EverSocket extends Emiter {
  constructor() {
    super();
    this._connected = false;
    this._lastActiveTime = 0;//最后一次收到消息的时间
    this._enableEverSocket = false;
  }

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

  end() {
    loger.log('停止WebSocket应用.');
    this._clear();
  }

  get connected() {
    return this._connected;
  }

  send(data) {
    if (this._connected) {
      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();
    this.reConnectionTimeout = window.setTimeout(() => {
      loger.log('WebSocket重新建立.');
      window.clearTimeout(this.reConnectionTimeout);
      this._newConnection();
    }, EverSocket.RECONN_INTERVAL);
  }

  _clear() {
    //this._emit(EverSocket.CLOSED);
    loger.log('WebSocket,Timers销毁');
    window.clearInterval(this.pingTimer);
    window.clearInterval(this.pongTimer);
    if(this.websocket==null){
      loger.log('WebSocket,Timers已经销毁');
      return;
    }
    this._enableEverSocket = false;
    this._setConnected(false);
    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);

    //启动心跳,检查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) {
    loger.log('<----RECEIVE MESSAGE');
    this._lastActiveTime = Date.now();
    const bufferData = messageEvent.data;
    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 = 3000;//重连的间隔

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;

export default new EverSocket();