1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { getByValue } from '@/enum/socketMessage.js';
import { encodeMessage, decodeMessage } from './socketMessage.js';
import { $socket_base_url } from '@/api/index.js';
class FYWebSocket extends WebSocket {
  constructor() {
    super($socket_base_url);
    return this;
  }
  /**
   * heartBeatConfig 心跳连接参数
   *    time: 心跳时间间隔
   *    timeout: 心跳超时间隔
   *    reconnect: 断线重连时间间隔
   * reconnectFunc 断线重连函数
   * messageManager 消息管理器
   */
  init(reconnectFunc, messageManager) {
    this.onopen = this.openHandler; // 连接成功后的回调函数
    this.onclose = this.closeHandler; // 连接关闭后的回调 函数
    this.onmessage = this.messageHandler; // 收到服务器数据后的回调函数
    this.onerror = this.errorHandler; // 连接发生错误的回调方法
    this.heartBeatConfig = {
      time: 30 * 1000,
      timeout: 2 * 1000,
      reconnect: 30 * 1000
    }; // 心跳连接配置参数
    this.isReconnect = typeof reconnectFunc === 'function'; // 记录是否断线重连
    this.reconnectFunc = reconnectFunc; // 断线重连函数
    this.messageManager = messageManager; // 消息处理管理器
    this.reconnectTimer = null; // 记录断线重连的时间器
    this.startHeartBeatTimer = null; // 记录心跳时间器
    this.webSocketState = false; // 记录socket连接状态 true为已连接
  }
  // 获取消息
  getMessage({ data }) {
    return decodeMessage(data);
  }
  // 发送消息
  sendMessage(type, data) {
    return this.send(encodeMessage(type, data));
  }
  // 连接成功后的回调函数
  openHandler() {
    console.log('====onopen websocket连接成功====');
    // socket状态设置为连接,做为后面的断线重连的拦截器
    this.webSocketState = true;
    // 判断是否启动心跳机制
    if (this.heartBeatConfig && this.heartBeatConfig.time) {
      this.startHeartBeat(this.heartBeatConfig.time);
    }
  }
  // 收到服务器数据后的回调函数
  messageHandler(res) {
    const webSocketMsg = this.getMessage(res);
    if (!(webSocketMsg && webSocketMsg != null && webSocketMsg != {})) {
      return;
    }
    const type = webSocketMsg.type;
    const data = webSocketMsg.data;
    let typeObj = getByValue(type);
    if (type == 0) {
      // 将连接状态更新为在线
      this.webSocketState = true;
      console.log('====onmessage websocket心跳检测====', data);
    } else {
      // 发送事件
      this.messageManager.emit(typeObj.name, data);
      console.log(`====onmessage websocket${typeObj.label}====`, data);
    }
  }
  // 连接关闭后的回调 函数
  closeHandler() {
    console.log('====onclose websocket关闭连接====');
    // 设置socket状态为断线
    this.webSocketState = false;
    // 在断开连接时 清除心跳时间器和 断开重连时间器
    this.startHeartBeatTimer && clearTimeout(this.startHeartBeatTimer);
    this.reconnectTimer && clearTimeout(this.reconnectTimer);
    this.reconnectWebSocket();
  }
  errorHandler() {
    console.log('====onerror websocket连接出错====');
    // 设置socket状态为断线
    this.webSocketState = false;
    // 重新连接
    this.reconnectWebSocket();
  }
 
  // 心跳初始化方法 time:心跳间隔
  startHeartBeat(time) {
    this.startHeartBeatTimer = setTimeout(() => {
      // 客户端每隔一段时间向服务端发送一个心跳消息
      this.sendMessage('0', Date.now());
      this.waitingServer();
    }, time);
  }
  //在客户端发送消息之后,延时等待服务器响应,通过webSocketState判断是否连线成功
  waitingServer() {
    this.webSocketState = false;
    setTimeout(() => {
      // 连线成功状态下 继续心跳检测
      if (this.webSocketState) {
        this.startHeartBeat(this.heartBeatConfig.time);
        return;
      }
      console.log('websocket 心跳无响应, 已经和服务端断线');
      // 重新连接时,记得要先关闭当前连接
      try {
        this.close();
      } catch (error) {
        console.log('websocket 当前连接已经关闭');
      }
      // // 重新连接
      // this.reconnectWebSocket()
    }, this.heartBeatConfig.timeout);
  }
 
  // 重新连接
  reconnectWebSocket() {
    // 判断是否是重新连接状态(即被动状态断线),如果是主动断线的不需要重新连接
    if (!this.isReconnect) {
      return;
    }
    // 根据传入的断线重连时间间隔 延时连接
    this.reconnectTimer = setTimeout(() => {
      // 触发重新连接函数
      console.log('====onerror websocket尝试重连====');
      this.reconnectFunc();
    }, this.heartBeatConfig.reconnect);
  }
}
export { FYWebSocket };