magic-chat-im 2.9.2 → 2.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/es/common.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * 对外暴露事件名
3
+ */
4
+ export declare const enum EVT_TYPE {
5
+ OPEN = "open",
6
+ ACK = "ack",
7
+ MESSAGE = "message",
8
+ ERROR = "error",
9
+ CLOSE = "close",
10
+ RECONNECT = "reconnect",
11
+ CONNECT = "connect"
12
+ }
13
+ /**
14
+ * 内部事件名
15
+ */
16
+ export declare const enum IM_TYPE {
17
+ OPEN = "im_open",
18
+ MESSAGE = "im_message",
19
+ ERROR = "im_error",
20
+ CLOSE = "im_close"
21
+ }
22
+ /**
23
+ * WS事件名
24
+ */
25
+ export declare const enum WS_TYPE {
26
+ OPEN = "open",
27
+ MESSAGE = "message",
28
+ ERROR = "error",
29
+ CLOSE = "close"
30
+ }
31
+ /**
32
+ * 下行消息类型
33
+ */
34
+ export declare const enum RECEIVED_MSG_TYPE {
35
+ SERVER_ACK = "SERVER_ACK",
36
+ MESSAGE = "MESSAGE"
37
+ }
38
+ /**
39
+ * 上行消息类型
40
+ */
41
+ export declare const enum SEND_MSG_TYPE {
42
+ HB = "hb",
43
+ CLIENT_ACK = "CLIENT_ACK",
44
+ MESSAGE = "MESSAGE"
45
+ }
46
+ /**
47
+ * ws status
48
+ */
49
+ export declare const enum WS_STATUS {
50
+ OFFLINE = "offline",
51
+ ONLINE = "online"
52
+ }
53
+ /**
54
+ * 参考 ws.readyState
55
+ * CONNECTING:值为0,表示正在连接。
56
+ * OPEN:值为1,表示连接成功,可以通信了。
57
+ * CLOSING:值为2,表示连接正在关闭。
58
+ * CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
59
+ */
60
+ export declare const enum WS_READYSTATE {
61
+ CONNECTING = 0,// 正在连接
62
+ OPEN = 1,// 连接成功
63
+ CLOSING = 2,// 连接正在关闭
64
+ CLOSED = 3
65
+ }
66
+ export declare const enum EXCEPTION_ERROR {
67
+ GET_TOKEN_EXCEPTION = "GET_TOKEN_EXCEPTION",
68
+ WS_NOT_SUPPORT = "WS_NOT_SUPPORT",
69
+ PARAMS_MISS = "PARAMS_MISS",
70
+ RECONNECT_ERROR = "RECONNECT_ERROR",
71
+ SOCKET_CONNECT_ERROR = "SOCKET_CONNECT_ERROR",
72
+ CONNECTION_CLOSED_CLEANLY = "CONNECTION_CLOSED_CLEANLY",
73
+ SOCKET_IM_CLOSE = "SOCKET_IM_CLOSE",
74
+ NEED_RECONNECT_MANUAL = "NEED_RECONNECT_MANUAL",// 重连次数过大,提醒用户需要刷新页面
75
+ NETWORK_OFFLINE = "NETWORK_OFFLINE"
76
+ }
77
+ export declare const enum RECONNECT_RESON {
78
+ TAB_ACTIVATED = "TAB_ACTIVATED",// tab 激活
79
+ NETWORK_RESTORED = "NETWORK_RESTORED",// 网络恢复
80
+ SOCKET_CONNECT_ERROR = "SOCKET_CONNECT_ERROR",// socket连接失败
81
+ GET_TOKEN_EXCEPTION = "GET_TOKEN_EXCEPTION",
82
+ HEARTBEAT_TIMEOUT = "HEARTBEAT_TIMEOUT",
83
+ ONERROR = "ONERROR",
84
+ ONCLOSE = "ONCLOSE",
85
+ POSTMESSAGE = "POSTMESSAGE"
86
+ }
package/es/common.js ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * 对外暴露事件名
3
+ */
4
+ export var EVT_TYPE = {
5
+ OPEN: "open",
6
+ ACK: "ack",
7
+ MESSAGE: "message",
8
+ ERROR: "error",
9
+ CLOSE: "close",
10
+ RECONNECT: "reconnect",
11
+ CONNECT: "connect"
12
+ };
13
+
14
+ /**
15
+ * 内部事件名
16
+ */
17
+ export var IM_TYPE = {
18
+ OPEN: "im_open",
19
+ MESSAGE: "im_message",
20
+ ERROR: "im_error",
21
+ CLOSE: "im_close"
22
+ };
23
+
24
+ /**
25
+ * WS事件名
26
+ */
27
+ export var WS_TYPE = {
28
+ OPEN: "open",
29
+ MESSAGE: "message",
30
+ ERROR: "error",
31
+ CLOSE: "close"
32
+ };
33
+ /**
34
+ * 下行消息类型
35
+ */
36
+ export var RECEIVED_MSG_TYPE = {
37
+ SERVER_ACK: "SERVER_ACK",
38
+ MESSAGE: "MESSAGE"
39
+ };
40
+
41
+ /**
42
+ * 上行消息类型
43
+ */
44
+ export var SEND_MSG_TYPE = {
45
+ HB: "hb",
46
+ CLIENT_ACK: "CLIENT_ACK",
47
+ MESSAGE: "MESSAGE"
48
+ };
49
+
50
+ /**
51
+ * ws status
52
+ */
53
+ export var WS_STATUS = {
54
+ OFFLINE: "offline",
55
+ ONLINE: "online"
56
+ };
57
+
58
+ /**
59
+ * 参考 ws.readyState
60
+ * CONNECTING:值为0,表示正在连接。
61
+ * OPEN:值为1,表示连接成功,可以通信了。
62
+ * CLOSING:值为2,表示连接正在关闭。
63
+ * CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
64
+ */
65
+
66
+ export var WS_READYSTATE = {
67
+ CONNECTING: 0,
68
+ OPEN: 1,
69
+ CLOSING: 2,
70
+ CLOSED: 3
71
+ }; // 连接已经关闭
72
+ export var EXCEPTION_ERROR = {
73
+ GET_TOKEN_EXCEPTION: "GET_TOKEN_EXCEPTION",
74
+ WS_NOT_SUPPORT: "WS_NOT_SUPPORT",
75
+ PARAMS_MISS: "PARAMS_MISS",
76
+ RECONNECT_ERROR: "RECONNECT_ERROR",
77
+ SOCKET_CONNECT_ERROR: "SOCKET_CONNECT_ERROR",
78
+ CONNECTION_CLOSED_CLEANLY: "CONNECTION_CLOSED_CLEANLY",
79
+ SOCKET_IM_CLOSE: "SOCKET_IM_CLOSE",
80
+ NEED_RECONNECT_MANUAL: "NEED_RECONNECT_MANUAL",
81
+ NETWORK_OFFLINE: "NETWORK_OFFLINE"
82
+ }; // 网络离线
83
+ export var RECONNECT_RESON = {
84
+ TAB_ACTIVATED: "TAB_ACTIVATED",
85
+ NETWORK_RESTORED: "NETWORK_RESTORED",
86
+ SOCKET_CONNECT_ERROR: "SOCKET_CONNECT_ERROR",
87
+ GET_TOKEN_EXCEPTION: "GET_TOKEN_EXCEPTION",
88
+ HEARTBEAT_TIMEOUT: "HEARTBEAT_TIMEOUT",
89
+ ONERROR: "ONERROR",
90
+ ONCLOSE: "ONCLOSE",
91
+ POSTMESSAGE: "POSTMESSAGE"
92
+ };
@@ -0,0 +1,83 @@
1
+ import { RECONNECT_RESON } from './common';
2
+ import type { IMInstance } from './im.interface';
3
+ import type { ErrorEventData, CloseEventData, ReconnectEventData } from './types';
4
+ export declare class ConnectionManager {
5
+ private im;
6
+ private _boundHandleOnline;
7
+ private _boundHandleOffline;
8
+ private _boundHandleVisibilityChange;
9
+ private _listenersAttached;
10
+ private _hiddenToVisibleTimeThreshold;
11
+ private _manualReconnectTimer;
12
+ private _connectionTimer;
13
+ constructor(im: IMInstance, hiddenToVisibleTimeThreshold: number);
14
+ /**
15
+ * 浏览器 tab 切换的变化处理
16
+ * 移动端webview 从hidden到visible状态变化处理
17
+ */
18
+ private _handleVisibilityChange;
19
+ private _handleOnline;
20
+ private _handleOffline;
21
+ /**
22
+ * 添加事件监听器(确保只添加一次)
23
+ */
24
+ attachEventListeners(): void;
25
+ /**
26
+ * 移除事件监听器
27
+ */
28
+ detachEventListeners(): void;
29
+ /**
30
+ * IM建连
31
+ */
32
+ connect(): void;
33
+ private _connect;
34
+ private _bindEvt;
35
+ /**
36
+ * 重新建立im连接
37
+ *
38
+ * @param code 重连原因
39
+ */
40
+ reconnect(code: RECONNECT_RESON, error?: string | Event): void;
41
+ /**
42
+ * 关闭IM连接,用户主动关闭连接
43
+ */
44
+ close(): void;
45
+ /**
46
+ * 手动重连(用于达到最大重连次数后)
47
+ */
48
+ manualReconnect(): void;
49
+ /**
50
+ * 清理所有定时器
51
+ */
52
+ cleanup(): void;
53
+ /**
54
+ * 参考 ws.readyState
55
+ * CONNECTING:值为0,表示正在连接。
56
+ * OPEN:值为1,表示连接成功,可以通信了。
57
+ * CLOSING:值为2,表示连接正在关闭。
58
+ * CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
59
+ */
60
+ readyState(): number;
61
+ /**
62
+ * error回调
63
+ */
64
+ errorEvent(msg: ErrorEventData): void;
65
+ /**
66
+ * 关闭回调
67
+ */
68
+ closeEvent(msg: CloseEventData): void;
69
+ /**
70
+ * 重连回调
71
+ */
72
+ reconnectEvent(msg: ReconnectEventData): void;
73
+ /**
74
+ * 设置用户关闭状态(用于测试)
75
+ * @param {boolean} closed - 是否为用户关闭
76
+ */
77
+ setUserClosed(closed: boolean): void;
78
+ /**
79
+ * 探测环境是否支持WebSocket
80
+ * 不支持WebSocket就降级long polling
81
+ */
82
+ private _detect;
83
+ }
@@ -0,0 +1,434 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5
+ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
6
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
7
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
9
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
10
+ import { RECONNECT_RESON, WS_READYSTATE, EXCEPTION_ERROR, EVT_TYPE } from "./common";
11
+ import { logger } from "./logger";
12
+ import Socket from "./socket";
13
+ import { errorHandler } from "./error-handler";
14
+ export var ConnectionManager = /*#__PURE__*/function () {
15
+ function ConnectionManager(im, hiddenToVisibleTimeThreshold) {
16
+ _classCallCheck(this, ConnectionManager);
17
+ _defineProperty(this, "im", void 0);
18
+ _defineProperty(this, "_boundHandleOnline", void 0);
19
+ _defineProperty(this, "_boundHandleOffline", void 0);
20
+ _defineProperty(this, "_boundHandleVisibilityChange", void 0);
21
+ _defineProperty(this, "_listenersAttached", false);
22
+ _defineProperty(this, "_hiddenToVisibleTimeThreshold", void 0);
23
+ _defineProperty(this, "_manualReconnectTimer", null);
24
+ _defineProperty(this, "_connectionTimer", null);
25
+ this.im = im;
26
+ this._hiddenToVisibleTimeThreshold = hiddenToVisibleTimeThreshold;
27
+
28
+ // 初始化绑定函数
29
+ this._boundHandleOnline = this._handleOnline.bind(this);
30
+ this._boundHandleOffline = this._handleOffline.bind(this);
31
+ this._boundHandleVisibilityChange = this._handleVisibilityChange.bind(this);
32
+ }
33
+
34
+ /**
35
+ * 浏览器 tab 切换的变化处理
36
+ * 移动端webview 从hidden到visible状态变化处理
37
+ */
38
+ _createClass(ConnectionManager, [{
39
+ key: "_handleVisibilityChange",
40
+ value: function _handleVisibilityChange() {
41
+ var hiddenTime;
42
+ var visibleTime;
43
+
44
+ // status 现在是 getter,会自动从 ws.readyState 计算,无需手动调用 updateStatus()
45
+
46
+ if (document.visibilityState === 'hidden') {
47
+ hiddenTime = Date.now();
48
+ logger.info('[ConnectionManager] App went to background');
49
+ // 可以选择在进入后台时发送一个ping来检测连接
50
+ if (this.im.readyState() === WS_READYSTATE.OPEN) {
51
+ this.im.ping();
52
+ }
53
+ } else {
54
+ visibleTime = Date.now();
55
+ // 应用回到前台时,检查连接状态
56
+ var state = this.im.readyState();
57
+ logger.info('[ConnectionManager] App came to foreground');
58
+
59
+ // 只在启用网络恢复重连时处理可见性变化
60
+ if (this.im.options.supportNetworkRestoredReconnect) {
61
+ // 页面再次可见-页面隐藏时间超过阈值,重连
62
+ if (visibleTime - hiddenTime > this._hiddenToVisibleTimeThreshold) {
63
+ logger.info('[ConnectionManager] Tab activated and connection lost 30s. Attempting to reconnect...');
64
+ this.im.reconnect(RECONNECT_RESON.TAB_ACTIVATED);
65
+ } else if (state === WS_READYSTATE.OPEN) {
66
+ // 连接正常,发送 ping 验证
67
+ logger.info('[ConnectionManager] Tab activated. Connection is healthy. Sending ping...');
68
+ this.im.ping();
69
+ } else if (state !== WS_READYSTATE.OPEN) {
70
+ // 未连接状态,强制重连
71
+ logger.info('[ConnectionManager] Tab activated and connection lost. Forcing reconnect...');
72
+ this.im.reconnect(RECONNECT_RESON.TAB_ACTIVATED);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }, {
78
+ key: "_handleOnline",
79
+ value: function _handleOnline() {
80
+ // 只在启用网络恢复重连时处理网络在线事件
81
+ if (this.im.options.supportNetworkRestoredReconnect && navigator.onLine) {
82
+ var state = this.im.readyState();
83
+
84
+ // 只在未连接状态才尝试重连
85
+ if (state !== WS_READYSTATE.OPEN && state !== WS_READYSTATE.CONNECTING) {
86
+ logger.info('[ConnectionManager] Network is back online. Attempting to reconnect...');
87
+ this.im.reconnect(RECONNECT_RESON.NETWORK_RESTORED);
88
+ } else {
89
+ logger.debug('[ConnectionManager] Network restored but connection is already established.');
90
+ }
91
+ }
92
+ }
93
+ }, {
94
+ key: "_handleOffline",
95
+ value: function _handleOffline() {
96
+ var msg = {
97
+ code: EXCEPTION_ERROR.NETWORK_OFFLINE,
98
+ err: 'Network is offline.'
99
+ };
100
+ this.im.errorEvent(msg);
101
+ // 网络错误,系统关闭连接
102
+ this.im.close();
103
+ this.im.setUserClosed(false);
104
+ }
105
+
106
+ /**
107
+ * 添加事件监听器(确保只添加一次)
108
+ */
109
+ }, {
110
+ key: "attachEventListeners",
111
+ value: function attachEventListeners() {
112
+ if (this._listenersAttached) {
113
+ return; // 已经添加过了,直接返回
114
+ }
115
+
116
+ // 监听网络状态变化
117
+ window.addEventListener('online', this._boundHandleOnline);
118
+ window.addEventListener('offline', this._boundHandleOffline);
119
+ // 添加对 tab 切换的支持
120
+ document.addEventListener('visibilitychange', this._boundHandleVisibilityChange);
121
+ this._listenersAttached = true;
122
+ logger.debug('[ConnectionManager] Event listeners attached');
123
+ }
124
+
125
+ /**
126
+ * 移除事件监听器
127
+ */
128
+ }, {
129
+ key: "detachEventListeners",
130
+ value: function detachEventListeners() {
131
+ if (!this._listenersAttached) {
132
+ return; // 没有添加过,直接返回
133
+ }
134
+ window.removeEventListener('online', this._boundHandleOnline);
135
+ window.removeEventListener('offline', this._boundHandleOffline);
136
+ document.removeEventListener('visibilitychange', this._boundHandleVisibilityChange);
137
+ this._listenersAttached = false;
138
+ logger.debug('[ConnectionManager] Event listeners detached');
139
+ }
140
+
141
+ /**
142
+ * IM建连
143
+ */
144
+ }, {
145
+ key: "connect",
146
+ value: function connect() {
147
+ var _this = this;
148
+ var options = this.im.options;
149
+ var token = options.token,
150
+ url = options.url,
151
+ appKey = options.appKey,
152
+ getToken = options.getToken,
153
+ _options$connectionTi = options.connectionTimeout,
154
+ connectionTimeout = _options$connectionTi === void 0 ? 15000 : _options$connectionTi;
155
+ if (!this._detect()) {
156
+ var msg = {
157
+ code: EXCEPTION_ERROR.WS_NOT_SUPPORT,
158
+ err: '浏览器环境不支持WS'
159
+ };
160
+ this.im.errorEvent(msg);
161
+ return;
162
+ }
163
+ if (!url || !appKey) {
164
+ var _msg = {
165
+ code: EXCEPTION_ERROR.PARAMS_MISS,
166
+ err: 'need url | appkey'
167
+ };
168
+ this.im.errorEvent(_msg);
169
+ return;
170
+ }
171
+
172
+ // 设置连接超时定时器 - 只在启用网络恢复重连时启用超时重连
173
+ if (this.im.options.supportNetworkRestoredReconnect) {
174
+ this._connectionTimer = window.setTimeout(function () {
175
+ logger.error("[ConnectionManager] Connection timeout after ".concat(connectionTimeout, "ms"));
176
+ var msg = {
177
+ code: EXCEPTION_ERROR.SOCKET_CONNECT_ERROR,
178
+ err: "Connection timeout after ".concat(connectionTimeout, "ms"),
179
+ context: {
180
+ url: options.url,
181
+ appKey: options.appKey
182
+ }
183
+ };
184
+ _this.im.errorEvent(msg);
185
+ _this.im.reconnect(RECONNECT_RESON.SOCKET_CONNECT_ERROR);
186
+ }, connectionTimeout);
187
+ }
188
+ if (token) {
189
+ this._connect(token);
190
+ } else {
191
+ getToken().then(function (resToken) {
192
+ // 清除连接超时定时器
193
+ if (_this._connectionTimer) {
194
+ clearTimeout(_this._connectionTimer);
195
+ _this._connectionTimer = null;
196
+ }
197
+ _this._connect(resToken);
198
+ }).catch(function (err) {
199
+ // 清除连接超时定时器
200
+ if (_this._connectionTimer) {
201
+ clearTimeout(_this._connectionTimer);
202
+ _this._connectionTimer = null;
203
+ }
204
+ var msg = {
205
+ code: EXCEPTION_ERROR.GET_TOKEN_EXCEPTION,
206
+ err: err,
207
+ context: {
208
+ url: _this.im.options.url,
209
+ appKey: _this.im.options.appKey
210
+ }
211
+ };
212
+ _this.im.errorEvent(msg);
213
+ _this.im.reconnect(RECONNECT_RESON.GET_TOKEN_EXCEPTION);
214
+ });
215
+ }
216
+ }
217
+ }, {
218
+ key: "_connect",
219
+ value: function _connect(token) {
220
+ var options = this.im.options;
221
+ var url = options.url,
222
+ appKey = options.appKey;
223
+ try {
224
+ var im = new Socket({
225
+ token: token,
226
+ url: url,
227
+ appKey: appKey
228
+ });
229
+ this._bindEvt(im);
230
+ Object.assign(this.im, {
231
+ im: im
232
+ });
233
+ // 清除连接超时定时器
234
+ if (this._connectionTimer) {
235
+ clearTimeout(this._connectionTimer);
236
+ this._connectionTimer = null;
237
+ }
238
+ } catch (error) {
239
+ // 清除连接超时定时器
240
+ if (this._connectionTimer) {
241
+ clearTimeout(this._connectionTimer);
242
+ this._connectionTimer = null;
243
+ }
244
+ var msg = {
245
+ code: EXCEPTION_ERROR.SOCKET_CONNECT_ERROR,
246
+ err: error,
247
+ context: {
248
+ url: this.im.options.url,
249
+ appKey: this.im.options.appKey,
250
+ token: token.substring(0, 10) + '...' // 避免记录完整token
251
+ }
252
+ };
253
+ this.im.errorEvent(msg);
254
+ this.im.reconnect(RECONNECT_RESON.SOCKET_CONNECT_ERROR);
255
+ }
256
+ }
257
+ }, {
258
+ key: "_bindEvt",
259
+ value: function _bindEvt(im) {
260
+ // 使用新的事件处理器来绑定事件
261
+ // 由于_eventHandler是IM类的私有属性,我们需要通过IM实例来调用
262
+ this.im._eventHandler.bindEvents(im);
263
+ }
264
+
265
+ /**
266
+ * 重新建立im连接
267
+ *
268
+ * @param code 重连原因
269
+ */
270
+ }, {
271
+ key: "reconnect",
272
+ value: function reconnect(code, error) {
273
+ var _this$im$_reconnect, _this$im$_reconnect2;
274
+ // 如果是用户主动关闭,不要重连
275
+ if (this.im._userClosed) {
276
+ logger.debug('[ConnectionManager] Connection was closed by user, skipping reconnect');
277
+ return;
278
+ }
279
+ if (!navigator.onLine) {
280
+ logger.debug('[ConnectionManager] Network is offline, skipping reconnect');
281
+ return; // 没网就中断重连
282
+ }
283
+
284
+ // 使用心跳管理器停止心跳
285
+ this.im._heartbeatManager.stop();
286
+ // 重置重连计数器
287
+ (_this$im$_reconnect = this.im._reconnect) === null || _this$im$_reconnect === void 0 || _this$im$_reconnect.reset();
288
+ // 失败重连
289
+ (_this$im$_reconnect2 = this.im._reconnect) === null || _this$im$_reconnect2 === void 0 || _this$im$_reconnect2.fail(code, error);
290
+ }
291
+
292
+ /**
293
+ * 关闭IM连接,用户主动关闭连接
294
+ */
295
+ }, {
296
+ key: "close",
297
+ value: function close() {
298
+ var _this$im$im;
299
+ // 更新断开连接统计信息
300
+ this.im._monitoringManager.updateConnectionCloseStats();
301
+ if (this.im._userClosed) {
302
+ logger.info('[ConnectionManager] User initiated close');
303
+ } else {
304
+ logger.info('[ConnectionManager] System initiated close (non-user)');
305
+ }
306
+
307
+ // 使用心跳管理器停止心跳
308
+ this.im._heartbeatManager.stop();
309
+
310
+ // 清理队列
311
+ this.im._messageQueueManager.clear();
312
+
313
+ // 解绑WebSocket事件
314
+ if (this.im.im) {
315
+ this.im._eventHandler.unbindEvents(this.im.im);
316
+ }
317
+
318
+ // 关闭 WebSocket
319
+ (_this$im$im = this.im.im) === null || _this$im$im === void 0 || _this$im$im.close();
320
+ }
321
+
322
+ /**
323
+ * 手动重连(用于达到最大重连次数后)
324
+ */
325
+ }, {
326
+ key: "manualReconnect",
327
+ value: function manualReconnect() {
328
+ var _this$im$_reconnect3,
329
+ _this2 = this;
330
+ logger.info('[ConnectionManager] Manual reconnect triggered manualReconnect');
331
+ (_this$im$_reconnect3 = this.im._reconnect) === null || _this$im$_reconnect3 === void 0 || _this$im$_reconnect3.reset();
332
+ // 主动关闭连接
333
+ this.close();
334
+ this.im.setUserClosed(true);
335
+
336
+ // 延迟一小段时间后重连
337
+ this._manualReconnectTimer = window.setTimeout(function () {
338
+ _this2._manualReconnectTimer = null;
339
+ _this2.im._userClosed = false; // 重置标记
340
+ _this2.connect();
341
+ }, 1000);
342
+ }
343
+
344
+ /**
345
+ * 清理所有定时器
346
+ */
347
+ }, {
348
+ key: "cleanup",
349
+ value: function cleanup() {
350
+ if (this._manualReconnectTimer) {
351
+ clearTimeout(this._manualReconnectTimer);
352
+ this._manualReconnectTimer = null;
353
+ }
354
+ if (this._connectionTimer) {
355
+ clearTimeout(this._connectionTimer);
356
+ this._connectionTimer = null;
357
+ }
358
+ }
359
+
360
+ /**
361
+ * 参考 ws.readyState
362
+ * CONNECTING:值为0,表示正在连接。
363
+ * OPEN:值为1,表示连接成功,可以通信了。
364
+ * CLOSING:值为2,表示连接正在关闭。
365
+ * CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
366
+ */
367
+ }, {
368
+ key: "readyState",
369
+ value: function readyState() {
370
+ var _this$im$im2 = this.im.im,
371
+ im = _this$im$im2 === void 0 ? {} : _this$im$im2;
372
+ return typeof im.readyState === 'number' ? im.readyState : WS_READYSTATE.CLOSED;
373
+ }
374
+
375
+ /**
376
+ * error回调
377
+ */
378
+ }, {
379
+ key: "errorEvent",
380
+ value: function errorEvent(msg) {
381
+ var errorCallback = this.im.options.errorCallback;
382
+ this.im.emit(EVT_TYPE.ERROR, msg);
383
+
384
+ // 使用统一的错误处理中心记录错误
385
+ errorHandler.reportException(msg.code, msg.err, _objectSpread({
386
+ eventType: EVT_TYPE.ERROR
387
+ }, msg));
388
+ errorCallback === null || errorCallback === void 0 || errorCallback(msg);
389
+ }
390
+
391
+ /**
392
+ * 关闭回调
393
+ */
394
+ }, {
395
+ key: "closeEvent",
396
+ value: function closeEvent(msg) {
397
+ var closeCallback = this.im.options.closeCallback;
398
+ this.im.emit(EVT_TYPE.CLOSE, msg);
399
+ closeCallback === null || closeCallback === void 0 || closeCallback(msg);
400
+ }
401
+
402
+ /**
403
+ * 重连回调
404
+ */
405
+ }, {
406
+ key: "reconnectEvent",
407
+ value: function reconnectEvent(msg) {
408
+ var reconnectCallback = this.im.options.reconnectCallback;
409
+ reconnectCallback === null || reconnectCallback === void 0 || reconnectCallback(msg);
410
+ this.im.emit(EVT_TYPE.RECONNECT, msg);
411
+ }
412
+
413
+ /**
414
+ * 设置用户关闭状态(用于测试)
415
+ * @param {boolean} closed - 是否为用户关闭
416
+ */
417
+ }, {
418
+ key: "setUserClosed",
419
+ value: function setUserClosed(closed) {
420
+ this.im._userClosed = closed;
421
+ }
422
+
423
+ /**
424
+ * 探测环境是否支持WebSocket
425
+ * 不支持WebSocket就降级long polling
426
+ */
427
+ }, {
428
+ key: "_detect",
429
+ value: function _detect() {
430
+ return !!(window.WebSocket && window.WebSocket.prototype.send);
431
+ }
432
+ }]);
433
+ return ConnectionManager;
434
+ }();