Socket.js 4.2 KB
// //////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2016-present
//  All Rights Reserved.
//
//  Author: AlexWang
//  Date: 2016-08-27 21:40:49
//  Last Modified by:   AlexWang
//  Last Modified time: 2017-05-20 12:38:31
//  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---->', data);
      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() {
    loger.log('WebSocket,Timers销毁');
    window.clearInterval(this.pingTimer);
    window.clearInterval(this.pongTimer);
    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;
    this._enableEverSocket = false;
    this._setConnected(false);
  }

  _onOpen() {
    loger.log('WebSocket建立成功', this.wsURL);
    //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;
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();