forked from nsjcy/frontEnd/nsjcy

xuxj
2020-04-26 8b3fbce45058894a76aefbf11b3a199f60d487d6
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
var wxTunnel = require('./wxTunnel');
 
/**
 * 当前打开的socket通道,同一时间只能有一个socket通道打开
 */
var currentSocketTunnel = null;
 
// 信道状态枚举
var STATUS_CLOSED = SocketTunnel.STATUS_CLOSED = 'CLOSED';
var STATUS_CONNECTING = SocketTunnel.STATUS_CONNECTING = 'CONNECTING';
var STATUS_ACTIVE = SocketTunnel.STATUS_ACTIVE = 'ACTIVE';
 
// 错误类型枚举
var ERR_CONNECT_SOCKET = SocketTunnel.ERR_CONNECT_SOCKET = 1002;
var ERR_SOCKET_ERROR = SocketTunnel.ERR_SOCKET_ERROR = 3001;
 
function SocketTunnel(socketUrl) {
  if (currentSocketTunnel && currentSocketTunnel.status !== STATUS_CLOSED) {
    close(false)
  }
 
  currentSocketTunnel = this;
 
  // 等确认微信小程序全面支持 ES6 就不用那么麻烦了
  var me = this;
 
  //=========================================================================
  // 暴露实例状态以及方法
  //=========================================================================
  this.socketUrl = socketUrl;
  this.status = null;
 
  this.open = openConnect;
  this.on = registerEventHandler;
  this.close = close;
 
  this.isClosed = isClosed;
  this.isConnecting = isConnecting;
  this.isActive = isActive;
  this.send = sendPacket;
 
 
  //=========================================================================
  // socket状态处理,状态说明:
  //   closed       - 已关闭
  //   connecting   - 首次连接
  //   active       - 当前socket已经在工作
  //=========================================================================
  function isClosed() { return me.status === STATUS_CLOSED; }
  function isConnecting() { return me.status === STATUS_CONNECTING; }
  function isActive() { return me.status === STATUS_ACTIVE; }
 
  function setStatus(status) {
    var lastStatus = me.status;
    if (lastStatus !== status) {
      me.status = status;
    }
  }
 
  // 初始为关闭状态
  setStatus(STATUS_CLOSED);
 
 
  //=========================================================================
  // socket事件处理机制
  // socket事件包括:
  //   connect      - 连接已建立
  //   close        - 连接被关闭(包括主动关闭和被动关闭)
  //   error        - 发生错误
  //   message      - websocket服务器发送过来消息
  //=========================================================================
  var preservedEventTypes = 'connect,close,error,message'.split(',');
  var eventHandlers = [];
 
  /**
   * 注册消息处理函数
   * @param {string} messageType 支持类型("connect"|"close"|"error"|"message")
   */
  function registerEventHandler(eventType, eventHandler) {
    if (typeof eventHandler === 'function') {
      eventHandlers.push([eventType, eventHandler]);
    }
  }
 
  /**
   * 派发事件,通知所有处理函数进行处理
   */
  function dispatchEvent(eventType, eventPayload) {
    eventHandlers.forEach(function (handler) {
      var handleType = handler[0];
      var handleFn = handler[1];
 
      if (handleType === eventType) {
        handleFn(eventPayload);
      }
    });
  }
 
  //=========================================================================
  // 连接控制
  //=========================================================================
  var isOpening = false;
 
  /**
   * 进行 WebSocket 连接
   */
  function openConnect() {
    if (isOpening) return;
    isOpening = true;
    setStatus(STATUS_CONNECTING);
    openSocket(me.socketUrl);
  }
 
  /**
   * 打开 WebSocket 连接,打开后,注册微信的 Socket 处理方法
   */
  function openSocket(url) {
    wxTunnel.listen({
      onOpen: handleSocketOpen,
      onMessage: handleSocketMessage,
      onClose: handleSocketClose,
      onError: handleSocketError,
    });
 
    wx.connectSocket({ url: url });
  }
 
 
  //=========================================================================
  // 处理消息
  //=========================================================================
 
  // 连接还没成功建立的时候,需要发送的包会先存放到队列里
  var queuedPackets = [];
 
  /**
   * WebSocket 打开之后,更新状态,同时发送所有遗留的数据包
   */
  function handleSocketOpen() {
    /* istanbul ignore else */
    if (isConnecting()) {
      dispatchEvent('connect');
 
    }
 
    setStatus(STATUS_ACTIVE);
  }
 
  /**
   * 收到 WebSocket 数据包,交给处理函数
   */
  function handleSocketMessage(message) {
    dispatchEvent('message', message);
  }
 
  /**
   * 数据包推送到websocket
   */
  function sendPacket(packet) {
    wx.sendSocketMessage({
      data: packet,
      fail: handleSocketError,
    });
  }
 
  var isClosing = false;
  /**
   * 收到 WebSocket 断开的消息,处理断开逻辑
   */
  function handleSocketClose(res) {
    dispatchEvent('close', res);
 
    /* istanbul ignore if */
    if (isClosing) return;
 
    /* istanbul ignore else */
    if (isActive()) {
      close()
    }
  }
 
  function close(emitClose) {
    isClosing = true;
    closeSocket(emitClose);
    setStatus(STATUS_CLOSED);
    dispatchEvent('close');
    isClosing = false;
  }
 
  function closeSocket(emitClose) {
    if (isActive() && emitClose !== false) {
      wx.sendSocketMessage({
        data: JSON.stringify({
          "type": "Close", "data": "", "extra": ""
        }),complete:function(res){
          console.log(res)
        },
      })
    }
 
    wx.closeSocket({
      complete: function (res) {
        console.log('WebSocket连接关闭!' + res.errMsg)
      }
    })
  }
 
  //=========================================================================
  // 错误处理
  //=========================================================================
 
  /**
   * 错误处理
   */
  function handleSocketError(detail) {
    dispatchEvent('error', detail)
  }
 
}
 
module.exports = SocketTunnel;