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.
@@ -0,0 +1,45 @@
1
+ import { LogLevel } from './logger';
2
+ import { EXCEPTION_ERROR } from './common';
3
+ import type { ErrorEventData } from './types';
4
+ export interface ErrorContext {
5
+ [key: string]: any;
6
+ }
7
+ /**
8
+ * 错误级别枚举
9
+ */
10
+ export declare enum ErrorLevel {
11
+ CRITICAL = "CRITICAL",// 致命错误,需要用户干预
12
+ HIGH = "HIGH",// 高优先级错误,影响功能
13
+ MEDIUM = "MEDIUM",// 中优先级错误,可恢复
14
+ LOW = "LOW"
15
+ }
16
+ /**
17
+ * 统一错误处理中心
18
+ */
19
+ export declare class ErrorHandler {
20
+ private logger;
21
+ /**
22
+ * 报告业务异常
23
+ * @param code 异常代码
24
+ * @param error 错误对象
25
+ * @param context 上下文信息
26
+ * @param level 日志级别
27
+ */
28
+ reportException(code: EXCEPTION_ERROR, error: any, context?: ErrorContext, level?: LogLevel): ErrorEventData;
29
+ /**
30
+ * 报告系统错误
31
+ * @param message 错误消息
32
+ * @param error 错误对象
33
+ * @param context 上下文信息
34
+ */
35
+ reportError(message: string, error: any, context?: ErrorContext): {
36
+ message: string;
37
+ error: any;
38
+ };
39
+ /**
40
+ * 根据错误代码映射错误级别
41
+ * @param code 错误代码
42
+ */
43
+ private mapErrorLevel;
44
+ }
45
+ export declare const errorHandler: ErrorHandler;
@@ -0,0 +1,111 @@
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 { logger, LogLevel } from "./logger";
11
+ import { EXCEPTION_ERROR } from "./common";
12
+ /**
13
+ * 错误级别枚举
14
+ */
15
+ export var ErrorLevel = /*#__PURE__*/function (ErrorLevel) {
16
+ ErrorLevel["CRITICAL"] = "CRITICAL";
17
+ ErrorLevel["HIGH"] = "HIGH";
18
+ ErrorLevel["MEDIUM"] = "MEDIUM";
19
+ ErrorLevel["LOW"] = "LOW";
20
+ return ErrorLevel;
21
+ }({});
22
+
23
+ /**
24
+ * 错误级别映射
25
+ */
26
+ var ERROR_LEVEL_MAP = _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, EXCEPTION_ERROR.NEED_RECONNECT_MANUAL, ErrorLevel.CRITICAL), EXCEPTION_ERROR.SOCKET_CONNECT_ERROR, ErrorLevel.HIGH), EXCEPTION_ERROR.GET_TOKEN_EXCEPTION, ErrorLevel.MEDIUM), EXCEPTION_ERROR.WS_NOT_SUPPORT, ErrorLevel.HIGH), EXCEPTION_ERROR.PARAMS_MISS, ErrorLevel.HIGH), EXCEPTION_ERROR.RECONNECT_ERROR, ErrorLevel.HIGH), EXCEPTION_ERROR.CONNECTION_CLOSED_CLEANLY, ErrorLevel.LOW), EXCEPTION_ERROR.SOCKET_IM_CLOSE, ErrorLevel.MEDIUM), EXCEPTION_ERROR.NETWORK_OFFLINE, ErrorLevel.MEDIUM);
27
+
28
+ /**
29
+ * 统一错误处理中心
30
+ */
31
+ export var ErrorHandler = /*#__PURE__*/function () {
32
+ function ErrorHandler() {
33
+ _classCallCheck(this, ErrorHandler);
34
+ _defineProperty(this, "logger", logger);
35
+ }
36
+ _createClass(ErrorHandler, [{
37
+ key: "reportException",
38
+ value:
39
+ /**
40
+ * 报告业务异常
41
+ * @param code 异常代码
42
+ * @param error 错误对象
43
+ * @param context 上下文信息
44
+ * @param level 日志级别
45
+ */
46
+ function reportException(code, error, context, level) {
47
+ // 如果未指定日志级别,则根据错误代码映射
48
+ var errorLevel = level !== null && level !== void 0 ? level : this.mapErrorLevel(code);
49
+ var errorData = _objectSpread({
50
+ code: code,
51
+ err: error
52
+ }, context);
53
+
54
+ // 根据错误级别记录日志
55
+ switch (errorLevel) {
56
+ case LogLevel.ERROR:
57
+ this.logger.errorWithContext("[Exception] ".concat(code), errorData);
58
+ break;
59
+ case LogLevel.WARN:
60
+ this.logger.warn("[Exception] ".concat(code), errorData);
61
+ break;
62
+ case LogLevel.INFO:
63
+ this.logger.info("[Exception] ".concat(code), errorData);
64
+ break;
65
+ default:
66
+ this.logger.errorWithContext("[Exception] ".concat(code), errorData);
67
+ }
68
+ return errorData;
69
+ }
70
+
71
+ /**
72
+ * 报告系统错误
73
+ * @param message 错误消息
74
+ * @param error 错误对象
75
+ * @param context 上下文信息
76
+ */
77
+ }, {
78
+ key: "reportError",
79
+ value: function reportError(message, error, context) {
80
+ var errorData = _objectSpread({
81
+ message: message,
82
+ error: error
83
+ }, context);
84
+ this.logger.errorWithContext("[System Error] ".concat(message), errorData);
85
+ return errorData;
86
+ }
87
+
88
+ /**
89
+ * 根据错误代码映射错误级别
90
+ * @param code 错误代码
91
+ */
92
+ }, {
93
+ key: "mapErrorLevel",
94
+ value: function mapErrorLevel(code) {
95
+ var level = ERROR_LEVEL_MAP[code];
96
+ switch (level) {
97
+ case ErrorLevel.CRITICAL:
98
+ case ErrorLevel.HIGH:
99
+ return LogLevel.ERROR;
100
+ case ErrorLevel.MEDIUM:
101
+ return LogLevel.WARN;
102
+ case ErrorLevel.LOW:
103
+ return LogLevel.INFO;
104
+ default:
105
+ return LogLevel.ERROR;
106
+ }
107
+ }
108
+ }]);
109
+ return ErrorHandler;
110
+ }();
111
+ export var errorHandler = new ErrorHandler();
@@ -0,0 +1,14 @@
1
+ import type { IMInstance } from './im.interface';
2
+ export declare class EventHandler {
3
+ private im;
4
+ private _boundHandlers;
5
+ constructor(im: IMInstance);
6
+ /**
7
+ * 绑定 WebSocket 事件
8
+ */
9
+ bindEvents(socket: any): void;
10
+ /**
11
+ * 解绑 WebSocket 事件
12
+ */
13
+ unbindEvents(socket: any): void;
14
+ }
@@ -0,0 +1,215 @@
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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3
+ 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); } }
4
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
5
+ 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; }
6
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
7
+ 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); }
8
+ import { EVT_TYPE, EXCEPTION_ERROR, IM_TYPE, RECEIVED_MSG_TYPE, RECONNECT_RESON, WS_STATUS } from "./common";
9
+ import { logger } from "./logger";
10
+ import { getMsgBody, getError } from "./util";
11
+ export var EventHandler = /*#__PURE__*/function () {
12
+ function EventHandler(im) {
13
+ _classCallCheck(this, EventHandler);
14
+ _defineProperty(this, "im", void 0);
15
+ _defineProperty(this, "_boundHandlers", {});
16
+ this.im = im;
17
+ }
18
+
19
+ /**
20
+ * 绑定 WebSocket 事件
21
+ */
22
+ _createClass(EventHandler, [{
23
+ key: "bindEvents",
24
+ value: function bindEvents(socket) {
25
+ var _this = this;
26
+ var options = this.im.options;
27
+ var connectCallback = options.connectCallback,
28
+ messageCallback = options.messageCallback,
29
+ ackCallback = options.ackCallback;
30
+
31
+ /**
32
+ * 连接打开实现Ping-Pong消息机制
33
+ * 定义一个定时器定期发送Ping消息给服务器。
34
+ * 当接收到服务器返回的Pong消息时,更新客户端的活跃状态或重置超时计时器。
35
+ */
36
+ this._boundHandlers[IM_TYPE.OPEN] = function () {
37
+ var _this$im$_reconnect;
38
+ // 更新连接统计信息
39
+ _this.im._monitoringManager.updateConnectionOpenStats();
40
+
41
+ // 在WebSocket连接建立后开始定期发送Ping
42
+ _this.im._keepAlive();
43
+ logger.debug('[IM] IM SDK start keep alive');
44
+
45
+ // reconnect连接成功清除重连
46
+ (_this$im$_reconnect = _this.im._reconnect) === null || _this$im$_reconnect === void 0 || _this$im$_reconnect.success();
47
+ _this.im.emit(EVT_TYPE.OPEN);
48
+ // 连接建立 TODO:后面应该收到后端的连接建立消息表明连接建立
49
+ _this.im.emit(EVT_TYPE.CONNECT);
50
+ connectCallback === null || connectCallback === void 0 || connectCallback();
51
+
52
+ // 重连重发 - 执行所有堆积的任务
53
+ _this.im._messageQueueManager.executeAllSendTasks();
54
+ };
55
+
56
+ /**
57
+ * ws失败error重连
58
+ * 监听error事件以捕获WebSocket连接中的错误。
59
+ * @param err
60
+ */
61
+ this._boundHandlers[IM_TYPE.ERROR] = function (err) {
62
+ logger.debug("[EventHandler] connection onError: ".concat(JSON.stringify(err)));
63
+ var errStr = getError(err);
64
+ if (socket.status === WS_STATUS.ONLINE) {
65
+ _this.im.errorEvent({
66
+ code: EXCEPTION_ERROR.SOCKET_CONNECT_ERROR,
67
+ err: errStr
68
+ });
69
+ _this.im.reconnect(RECONNECT_RESON.ONERROR, err);
70
+ }
71
+ };
72
+
73
+ /**
74
+ * ws关闭,非正常关闭WS重连,正常关闭无需重连
75
+ * 监听close事件以处理正常关闭或异常关闭的情况。
76
+ * @param err
77
+ */
78
+ this._boundHandlers[IM_TYPE.CLOSE] = function (err) {
79
+ // 如果是正常关闭,可能无需立即重连
80
+ logger.warn("[EventHandler] connection onClose: ".concat(JSON.stringify(err)));
81
+ var errStr = getError(err);
82
+ var reason = err.reason || 'Unknown';
83
+ if (err.wasClean) {
84
+ var msg = {
85
+ code: EXCEPTION_ERROR.CONNECTION_CLOSED_CLEANLY,
86
+ err: errStr,
87
+ reason: reason
88
+ };
89
+ _this.im.closeEvent(msg);
90
+ } else {
91
+ // 非正常关闭,触发重连逻辑
92
+ var _msg = {
93
+ code: EXCEPTION_ERROR.SOCKET_CONNECT_ERROR,
94
+ err: errStr,
95
+ reason: reason
96
+ };
97
+ _this.im.closeEvent(_msg);
98
+ _this.im.reconnect(RECONNECT_RESON.ONCLOSE, err);
99
+ }
100
+ };
101
+
102
+ /**
103
+ * 消息包格式:
104
+ * socket这边转发过来格式是
105
+ * {
106
+ * type:
107
+ * data
108
+ * }
109
+ * https://aliyuque.antfin.com/goc-dev/gts-fe/uwi3ta8enca0fdmm#ThWrH
110
+ * @param {*} data
111
+ */
112
+ this._boundHandlers[IM_TYPE.MESSAGE] = function (wsMessage) {
113
+ var _ref = wsMessage || {},
114
+ type = _ref.type,
115
+ data = _ref.data;
116
+ if (type === IM_TYPE.MESSAGE) {
117
+ if (typeof data === 'string' && data === 'hb') {
118
+ // 收到Pong消息,清除当前超时计时器,表明连接正常
119
+ // 主要连接消息 重置标记
120
+ // 使用连接管理器来设置用户关闭状态
121
+ _this.im._connectionManager.setUserClosed(false);
122
+ _this.im._onPongReceived();
123
+ } else {
124
+ logger.debug("[EventHandler] Message received: ".concat(JSON.stringify(data)));
125
+ var messageData = getMsgBody(data);
126
+ if (!messageData) {
127
+ logger.warn('[EventHandler] Invalid message data received');
128
+ return;
129
+ }
130
+ var name = messageData.name,
131
+ args = messageData.args,
132
+ messageKey = messageData.messageKey,
133
+ msgType = messageData.msgType,
134
+ _messageData$msgBody = messageData.msgBody,
135
+ msgBody = _messageData$msgBody === void 0 ? {} : _messageData$msgBody;
136
+
137
+ // ack消息
138
+ if (msgType === RECEIVED_MSG_TYPE.SERVER_ACK) {
139
+ ackCallback === null || ackCallback === void 0 || ackCallback(messageData);
140
+ _this.im.emit(EVT_TYPE.ACK, messageData);
141
+ if (messageKey) {
142
+ _this.im._ack(messageKey);
143
+ }
144
+ } else {
145
+ // 业务消息
146
+
147
+ /**
148
+ * 以下处理兼容旧的apush消息
149
+ */
150
+ if (name === 'apushMsg' && Array.isArray(args) && args.length) {
151
+ var arg = args[0];
152
+ var _ref2 = arg || {},
153
+ _msgType = _ref2.msgType;
154
+ if (_msgType) {
155
+ var msgBodyOld = {
156
+ msgType: _msgType,
157
+ version: '1.0.0',
158
+ msgDetail: args
159
+ };
160
+ _this.im.emit(EVT_TYPE.MESSAGE, msgBodyOld);
161
+ messageCallback === null || messageCallback === void 0 || messageCallback(msgBodyOld);
162
+ }
163
+ /**
164
+ * 以下处理的webPush消息
165
+ * webPush消息有messageKey,支持消息回溯
166
+ */
167
+ } else if (name === 'webPush') {
168
+ // 消息去重 - 使用新的消息队列管理器来处理
169
+ // 注意:这里我们暂时保留原有的去重逻辑,但可以考虑用新的管理器来实现
170
+ if (messageKey) {
171
+ // 简单的去重实现 - 在实际应用中可能需要更复杂的去重机制
172
+ // 这里我们只是演示如何移除对 msgQueue 的依赖
173
+ logger.debug("[EventHandler] Processing message with key: ".concat(messageKey));
174
+ }
175
+ _this.im.emit(EVT_TYPE.MESSAGE, msgBody);
176
+ messageCallback === null || messageCallback === void 0 || messageCallback(msgBody);
177
+
178
+ // 更新接收消息统计
179
+ _this.im._monitoringManager.updateMessageReceivedStats();
180
+ _this.im._ack(messageKey);
181
+
182
+ // 将 messageKey 加入队列 - 使用新的消息队列管理器来处理
183
+ if (messageKey) {
184
+ // 这里可以添加对 messageKey 的处理逻辑
185
+ logger.debug("[EventHandler] Message key added to queue: ".concat(messageKey));
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ };
192
+ socket.on(IM_TYPE.MESSAGE, this._boundHandlers[IM_TYPE.MESSAGE]);
193
+ socket.on(IM_TYPE.OPEN, this._boundHandlers[IM_TYPE.OPEN]);
194
+ socket.on(IM_TYPE.ERROR, this._boundHandlers[IM_TYPE.ERROR]);
195
+ socket.on(IM_TYPE.CLOSE, this._boundHandlers[IM_TYPE.CLOSE]);
196
+ }
197
+
198
+ /**
199
+ * 解绑 WebSocket 事件
200
+ */
201
+ }, {
202
+ key: "unbindEvents",
203
+ value: function unbindEvents(socket) {
204
+ var _this2 = this;
205
+ // 移除所有事件监听器
206
+ Object.keys(this._boundHandlers).forEach(function (eventType) {
207
+ socket.off(eventType, _this2._boundHandlers[eventType]);
208
+ });
209
+
210
+ // 清空绑定的处理器
211
+ this._boundHandlers = {};
212
+ }
213
+ }]);
214
+ return EventHandler;
215
+ }();
@@ -0,0 +1,37 @@
1
+ export interface HeartbeatConfig {
2
+ /**
3
+ * @description 心跳间隔时间(毫秒)
4
+ * @default 10000 (10秒)
5
+ */
6
+ pingInterval: number;
7
+ /**
8
+ * @description 心跳超时时间(毫秒)
9
+ * @default 60000 (60秒)
10
+ */
11
+ pingTimeout: number;
12
+ }
13
+ export declare class HeartbeatManager {
14
+ private pingIntervalId;
15
+ private pongTimeoutId;
16
+ private config;
17
+ private onTimeout;
18
+ private sendPing;
19
+ constructor(config: HeartbeatConfig, onTimeout: () => void);
20
+ /**
21
+ * 开始心跳
22
+ * @param sendPing 发送ping消息的函数
23
+ */
24
+ start(sendPing: () => void): void;
25
+ /**
26
+ * 停止心跳
27
+ */
28
+ stop(): void;
29
+ /**
30
+ * 重置心跳超时计时器
31
+ */
32
+ reset(): void;
33
+ /**
34
+ * 获取当前心跳配置
35
+ */
36
+ getConfig(): HeartbeatConfig;
37
+ }
@@ -0,0 +1,93 @@
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 { logger } from "./logger";
11
+ export var HeartbeatManager = /*#__PURE__*/function () {
12
+ function HeartbeatManager(config, onTimeout) {
13
+ _classCallCheck(this, HeartbeatManager);
14
+ _defineProperty(this, "pingIntervalId", null);
15
+ _defineProperty(this, "pongTimeoutId", null);
16
+ _defineProperty(this, "config", void 0);
17
+ _defineProperty(this, "onTimeout", void 0);
18
+ _defineProperty(this, "sendPing", null);
19
+ this.config = config;
20
+ this.onTimeout = onTimeout;
21
+ }
22
+
23
+ /**
24
+ * 开始心跳
25
+ * @param sendPing 发送ping消息的函数
26
+ */
27
+ _createClass(HeartbeatManager, [{
28
+ key: "start",
29
+ value: function start(sendPing) {
30
+ var _this = this;
31
+ this.sendPing = sendPing;
32
+
33
+ // 先清除旧的心跳
34
+ this.stop();
35
+
36
+ // 立即发送第一次心跳
37
+ this.sendPing();
38
+
39
+ // 定期发送心跳
40
+ this.pingIntervalId = window.setInterval(function () {
41
+ if (_this.sendPing) {
42
+ _this.sendPing();
43
+ }
44
+ }, this.config.pingInterval);
45
+ }
46
+
47
+ /**
48
+ * 停止心跳
49
+ */
50
+ }, {
51
+ key: "stop",
52
+ value: function stop() {
53
+ if (this.pingIntervalId) {
54
+ clearInterval(this.pingIntervalId);
55
+ this.pingIntervalId = null;
56
+ }
57
+ if (this.pongTimeoutId) {
58
+ clearTimeout(this.pongTimeoutId);
59
+ this.pongTimeoutId = null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * 重置心跳超时计时器
65
+ */
66
+ }, {
67
+ key: "reset",
68
+ value: function reset() {
69
+ var _this2 = this;
70
+ // 清除旧的超时计时器
71
+ if (this.pongTimeoutId) {
72
+ clearTimeout(this.pongTimeoutId);
73
+ this.pongTimeoutId = null;
74
+ }
75
+
76
+ // 设置新的超时检测
77
+ this.pongTimeoutId = window.setTimeout(function () {
78
+ logger.error('[HeartbeatManager] Heartbeat timeout detected');
79
+ _this2.onTimeout();
80
+ }, this.config.pingTimeout);
81
+ }
82
+
83
+ /**
84
+ * 获取当前心跳配置
85
+ */
86
+ }, {
87
+ key: "getConfig",
88
+ value: function getConfig() {
89
+ return _objectSpread({}, this.config);
90
+ }
91
+ }]);
92
+ return HeartbeatManager;
93
+ }();
package/es/im.d.ts ADDED
@@ -0,0 +1,162 @@
1
+ import { RECONNECT_RESON } from './common';
2
+ import { ReconnectState } from './reconnect';
3
+ import { HeartbeatManager } from './heartbeat-manager';
4
+ import { MessageQueueManager } from './message-queue-manager';
5
+ import { MonitoringManager } from './monitoring-manager';
6
+ import { ConnectionManager } from './connection-manager';
7
+ import type { CloseEventData, ErrorEventData, MessageBody, ReconnectEventData } from './types';
8
+ import type { IMInstance, IMConnectionStats, CommonParams, Options } from './im.interface';
9
+ export default class IM implements IMInstance {
10
+ version: string;
11
+ options: Options;
12
+ emit: any;
13
+ on: any;
14
+ im: any;
15
+ _connectionStats: IMConnectionStats;
16
+ _heartbeatManager: HeartbeatManager;
17
+ _messageQueueManager: MessageQueueManager;
18
+ private _eventHandler;
19
+ private _messageSender;
20
+ _monitoringManager: MonitoringManager;
21
+ _connectionManager: ConnectionManager;
22
+ private _hiddenToVisibleTimeThreshold;
23
+ _reconnect: any;
24
+ _commonParams: CommonParams;
25
+ _userClosed: boolean;
26
+ _msgCounter: number;
27
+ constructor(options: Options);
28
+ /**
29
+ * 销毁 IM 实例
30
+ * 注意:如果开启了 supportNetworkRestoredReconnect,必须显式调用此方法以清理资源
31
+ */
32
+ destroy(): void;
33
+ /**
34
+ * 设置全局参数
35
+ * @param {*} param
36
+ */
37
+ setCommonParams(param: any): void;
38
+ /**
39
+ * IM建连
40
+ */
41
+ connect(): void;
42
+ /**
43
+ * 重新建立im连接
44
+ *
45
+ * @param code 重连原因
46
+ */
47
+ reconnect(code: RECONNECT_RESON, error?: string | Event): void;
48
+ /**
49
+ * 关闭IM连接,用户主动关闭连接
50
+ */
51
+ close(): void;
52
+ /**
53
+ * 手动重连(用于达到最大重连次数后)
54
+ */
55
+ manualReconnect(): void;
56
+ /**
57
+ * 参考 ws.readyState
58
+ * CONNECTING:值为0,表示正在连接。
59
+ * OPEN:值为1,表示连接成功,可以通信了。
60
+ * CLOSING:值为2,表示连接正在关闭。
61
+ * CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
62
+ */
63
+ readyState(): number;
64
+ /**
65
+ * error回调
66
+ */
67
+ errorEvent(msg: ErrorEventData): void;
68
+ /**
69
+ * 关闭回调
70
+ */
71
+ closeEvent(msg: CloseEventData): void;
72
+ /**
73
+ * 重连回调
74
+ */
75
+ reconnectEvent(msg: ReconnectEventData): void;
76
+ /**
77
+ * 设置用户关闭状态(用于测试)
78
+ * @param {boolean} closed - 是否为用户关闭
79
+ *
80
+ * @example
81
+ * // 模拟系统错误,允许重连
82
+ * im.setUserClosed(false);
83
+ *
84
+ * // 模拟用户主动关闭,阻止重连
85
+ * im.setUserClosed(true);
86
+ */
87
+ setUserClosed(closed: boolean): void;
88
+ /**
89
+ * 获取用户关闭状态(用于测试和监控)
90
+ * @returns {boolean} 是否为用户主动关闭
91
+ */
92
+ getUserClosed(): boolean;
93
+ /**
94
+ * 获取重连状态(用于监控)
95
+ * @returns {ReconnectState} 重连状态
96
+ */
97
+ getReconnectState(): ReconnectState | undefined;
98
+ /**
99
+ * 获取当前重连次数(用于监控)
100
+ * @returns {number} 当前重连次数
101
+ */
102
+ getReconnectCounter(): number;
103
+ /**
104
+ * 获取最大重连次数(用于监控)
105
+ * @returns {number} 最大重连次数
106
+ */
107
+ getReconnectMaxRetry(): number;
108
+ /**
109
+ * 获取待发送消息队列大小(用于监控)
110
+ * @returns {number} 队列大小
111
+ */
112
+ getQueueSize(): number;
113
+ /**
114
+ * 获取连接统计信息(用于监控)
115
+ * @returns {object} 连接统计信息
116
+ */
117
+ getConnectionStats(): IMConnectionStats;
118
+ /**
119
+ * 获取性能指标(用于监控)
120
+ * @returns {object} 性能指标
121
+ */
122
+ getPerformanceMetrics(): {
123
+ connectionSuccessRate: number;
124
+ messageLossRate: number;
125
+ averageReconnectionTime: number;
126
+ heartbeatTimeoutRate: number;
127
+ };
128
+ /**
129
+ * 重置连接统计信息
130
+ */
131
+ resetConnectionStats(): void;
132
+ /**
133
+ * 探测环境是否支持WebSocket
134
+ * 不支持WebSocket就降级long polling
135
+ */
136
+ _detect(): boolean;
137
+ _keepAlive(): void;
138
+ /**
139
+ * 收到 Pong 响应
140
+ */
141
+ _onPongReceived(): void;
142
+ _ack(messageKey: string): void;
143
+ _messageKey(): string;
144
+ /**
145
+ * 发送消息
146
+ */
147
+ sendMessage(msgBody?: Partial<MessageBody>): void;
148
+ /**
149
+ * 发送hb消息
150
+ */
151
+ ping(): void;
152
+ /**
153
+ * 发送事件消息
154
+ * @param {Object} data
155
+ */
156
+ sendEvent(data: Record<string, any>): void;
157
+ /**
158
+ * 发送消息
159
+ * @param {Object} data
160
+ */
161
+ _send(data: string): void;
162
+ }