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 +86 -0
- package/es/common.js +92 -0
- package/es/connection-manager.d.ts +83 -0
- package/es/connection-manager.js +434 -0
- package/es/error-handler.d.ts +45 -0
- package/es/error-handler.js +111 -0
- package/es/event-handler.d.ts +14 -0
- package/es/event-handler.js +215 -0
- package/es/heartbeat-manager.d.ts +37 -0
- package/es/heartbeat-manager.js +93 -0
- package/es/im.d.ts +162 -0
- package/es/im.interface.d.ts +234 -0
- package/es/im.interface.js +1 -0
- package/es/im.js +444 -0
- package/es/index.d.ts +7 -0
- package/es/index.js +8 -0
- package/es/logger.d.ts +98 -0
- package/es/logger.js +238 -0
- package/es/message-queue-manager.d.ts +45 -0
- package/es/message-queue-manager.js +128 -0
- package/es/message-sender.d.ts +26 -0
- package/es/message-sender.js +113 -0
- package/es/monitoring-manager.d.ts +48 -0
- package/es/monitoring-manager.js +161 -0
- package/es/reconnect.d.ts +19 -0
- package/es/reconnect.js +279 -0
- package/es/socket.d.ts +29 -0
- package/es/socket.js +163 -0
- package/es/types.d.ts +82 -0
- package/es/types.js +1 -0
- package/es/util.d.ts +11 -0
- package/es/util.js +44 -0
- package/package.json +1 -1
|
@@ -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
|
+
}
|