tgo-widget-miniprogram 1.0.0 → 1.1.1
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/miniprogram_dist/core/chatStore.js +1494 -591
- package/miniprogram_dist/services/wukongim.js +1118 -170
- package/miniprogram_dist/utils/jsonRender.js +18538 -109
- package/miniprogram_dist/utils/markdown.js +1214 -21
- package/package.json +7 -8
|
@@ -1,183 +1,1131 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var WKIM = require('easyjssdk').WKIM
|
|
6
|
-
var WKIMEvent = require('easyjssdk').WKIMEvent
|
|
7
|
-
var adapter = require('../adapters/request')
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
3
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
4
|
+
};
|
|
8
5
|
|
|
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
|
-
|
|
6
|
+
// node_modules/easyjssdk/dist/cjs/index.js
|
|
7
|
+
var require_cjs = __commonJS({
|
|
8
|
+
"node_modules/easyjssdk/dist/cjs/index.js"(exports2) {
|
|
9
|
+
"use strict";
|
|
10
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11
|
+
exports2.WKIMDeviceFlag = exports2.WKIMEvent = exports2.WKIMChannelType = exports2.WKIM = exports2.DeviceFlag = exports2.ReasonCode = exports2.Event = exports2.ChannelType = exports2.currentPlatform = exports2.PlatformType = void 0;
|
|
12
|
+
var WS_CONNECTING = 0;
|
|
13
|
+
var WS_OPEN = 1;
|
|
14
|
+
var WS_CLOSING = 2;
|
|
15
|
+
var WS_CLOSED = 3;
|
|
16
|
+
var PlatformType;
|
|
17
|
+
(function(PlatformType2) {
|
|
18
|
+
PlatformType2["Browser"] = "browser";
|
|
19
|
+
PlatformType2["NodeJS"] = "nodejs";
|
|
20
|
+
PlatformType2["WeChat"] = "wechat";
|
|
21
|
+
PlatformType2["Alipay"] = "alipay";
|
|
22
|
+
PlatformType2["UniApp"] = "uniapp";
|
|
23
|
+
})(PlatformType || (exports2.PlatformType = PlatformType = {}));
|
|
24
|
+
var WeChatWebSocketAdapter = class {
|
|
25
|
+
constructor(url) {
|
|
26
|
+
this.socketTask = null;
|
|
27
|
+
this._readyState = WS_CONNECTING;
|
|
28
|
+
this.onopen = null;
|
|
29
|
+
this.onmessage = null;
|
|
30
|
+
this.onerror = null;
|
|
31
|
+
this.onclose = null;
|
|
32
|
+
if (typeof wx === "undefined") {
|
|
33
|
+
throw new Error("WeChat Mini Program environment not detected");
|
|
34
|
+
}
|
|
35
|
+
this.socketTask = wx.connectSocket({
|
|
36
|
+
url,
|
|
37
|
+
success: () => {
|
|
38
|
+
console.log("WeChat WebSocket connecting...");
|
|
39
|
+
},
|
|
40
|
+
fail: (err) => {
|
|
41
|
+
console.error("WeChat WebSocket connection failed:", err);
|
|
42
|
+
this._readyState = WS_CLOSED;
|
|
43
|
+
if (this.onerror) {
|
|
44
|
+
this.onerror({ message: err.errMsg || "Connection failed" });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
this.socketTask.onOpen((res) => {
|
|
49
|
+
this._readyState = WS_OPEN;
|
|
50
|
+
if (this.onopen) {
|
|
51
|
+
this.onopen(res);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.socketTask.onMessage((res) => {
|
|
55
|
+
if (this.onmessage) {
|
|
56
|
+
const data = res.data instanceof ArrayBuffer ? new TextDecoder().decode(res.data) : res.data;
|
|
57
|
+
this.onmessage({ data });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
this.socketTask.onError((res) => {
|
|
61
|
+
console.error("WeChat WebSocket error:", res);
|
|
62
|
+
if (this.onerror) {
|
|
63
|
+
this.onerror({ message: res.errMsg || "WebSocket error" });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
this.socketTask.onClose((res) => {
|
|
67
|
+
this._readyState = WS_CLOSED;
|
|
68
|
+
if (this.onclose) {
|
|
69
|
+
this.onclose({ code: res.code || 1e3, reason: res.reason || "" });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
get readyState() {
|
|
74
|
+
return this._readyState;
|
|
75
|
+
}
|
|
76
|
+
send(data) {
|
|
77
|
+
if (this._readyState !== WS_OPEN || !this.socketTask) {
|
|
78
|
+
throw new Error("WebSocket is not open");
|
|
79
|
+
}
|
|
80
|
+
this.socketTask.send({
|
|
81
|
+
data,
|
|
82
|
+
fail: (err) => {
|
|
83
|
+
console.error("WeChat WebSocket send failed:", err);
|
|
84
|
+
if (this.onerror) {
|
|
85
|
+
this.onerror({ message: "Send failed" });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
close(code, reason) {
|
|
91
|
+
if (this._readyState === WS_CLOSED || this._readyState === WS_CLOSING) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this._readyState = WS_CLOSING;
|
|
95
|
+
if (this.socketTask) {
|
|
96
|
+
this.socketTask.close({
|
|
97
|
+
code: code || 1e3,
|
|
98
|
+
reason: reason || "",
|
|
99
|
+
fail: (err) => {
|
|
100
|
+
console.error("WeChat WebSocket close failed:", err);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var AlipayWebSocketAdapter = class {
|
|
107
|
+
constructor(url) {
|
|
108
|
+
this._readyState = WS_CONNECTING;
|
|
109
|
+
this.boundOnOpen = null;
|
|
110
|
+
this.boundOnMessage = null;
|
|
111
|
+
this.boundOnError = null;
|
|
112
|
+
this.boundOnClose = null;
|
|
113
|
+
this.onopen = null;
|
|
114
|
+
this.onmessage = null;
|
|
115
|
+
this.onerror = null;
|
|
116
|
+
this.onclose = null;
|
|
117
|
+
if (typeof my === "undefined") {
|
|
118
|
+
throw new Error("Alipay Mini Program environment not detected");
|
|
119
|
+
}
|
|
120
|
+
this.boundOnOpen = (res) => {
|
|
121
|
+
this._readyState = WS_OPEN;
|
|
122
|
+
if (this.onopen) {
|
|
123
|
+
this.onopen(res);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
this.boundOnMessage = (res) => {
|
|
127
|
+
if (this.onmessage) {
|
|
128
|
+
const data = res.data instanceof ArrayBuffer ? new TextDecoder().decode(res.data) : res.data;
|
|
129
|
+
this.onmessage({ data });
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
this.boundOnError = (res) => {
|
|
133
|
+
console.error("Alipay WebSocket error:", res);
|
|
134
|
+
if (this.onerror) {
|
|
135
|
+
this.onerror({ message: res.errorMessage || "WebSocket error" });
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
this.boundOnClose = (res) => {
|
|
139
|
+
this._readyState = WS_CLOSED;
|
|
140
|
+
this.cleanup();
|
|
141
|
+
if (this.onclose) {
|
|
142
|
+
this.onclose({ code: res.code || 1e3, reason: res.reason || "" });
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
my.onSocketOpen(this.boundOnOpen);
|
|
146
|
+
my.onSocketMessage(this.boundOnMessage);
|
|
147
|
+
my.onSocketError(this.boundOnError);
|
|
148
|
+
my.onSocketClose(this.boundOnClose);
|
|
149
|
+
my.connectSocket({
|
|
150
|
+
url,
|
|
151
|
+
success: () => {
|
|
152
|
+
console.log("Alipay WebSocket connecting...");
|
|
153
|
+
},
|
|
154
|
+
fail: (err) => {
|
|
155
|
+
console.error("Alipay WebSocket connection failed:", err);
|
|
156
|
+
this._readyState = WS_CLOSED;
|
|
157
|
+
this.cleanup();
|
|
158
|
+
if (this.onerror) {
|
|
159
|
+
this.onerror({ message: err.errorMessage || "Connection failed" });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
get readyState() {
|
|
165
|
+
return this._readyState;
|
|
166
|
+
}
|
|
167
|
+
send(data) {
|
|
168
|
+
if (typeof my === "undefined") {
|
|
169
|
+
throw new Error("Alipay Mini Program environment not detected");
|
|
170
|
+
}
|
|
171
|
+
if (this._readyState !== WS_OPEN) {
|
|
172
|
+
throw new Error("WebSocket is not open");
|
|
173
|
+
}
|
|
174
|
+
my.sendSocketMessage({
|
|
175
|
+
data,
|
|
176
|
+
fail: (err) => {
|
|
177
|
+
console.error("Alipay WebSocket send failed:", err);
|
|
178
|
+
if (this.onerror) {
|
|
179
|
+
this.onerror({ message: "Send failed" });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
close(code, reason) {
|
|
185
|
+
if (typeof my === "undefined") {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (this._readyState === WS_CLOSED || this._readyState === WS_CLOSING) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
this._readyState = WS_CLOSING;
|
|
192
|
+
my.closeSocket({
|
|
193
|
+
code: code || 1e3,
|
|
194
|
+
reason: reason || "",
|
|
195
|
+
fail: (err) => {
|
|
196
|
+
console.error("Alipay WebSocket close failed:", err);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
cleanup() {
|
|
201
|
+
if (typeof my !== "undefined") {
|
|
202
|
+
my.offSocketOpen(this.boundOnOpen);
|
|
203
|
+
my.offSocketMessage(this.boundOnMessage);
|
|
204
|
+
my.offSocketError(this.boundOnError);
|
|
205
|
+
my.offSocketClose(this.boundOnClose);
|
|
206
|
+
this.boundOnOpen = null;
|
|
207
|
+
this.boundOnMessage = null;
|
|
208
|
+
this.boundOnError = null;
|
|
209
|
+
this.boundOnClose = null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
var UniAppWebSocketAdapter = class {
|
|
214
|
+
constructor(url) {
|
|
215
|
+
this.socketTask = null;
|
|
216
|
+
this._readyState = WS_CONNECTING;
|
|
217
|
+
this.onopen = null;
|
|
218
|
+
this.onmessage = null;
|
|
219
|
+
this.onerror = null;
|
|
220
|
+
this.onclose = null;
|
|
221
|
+
if (typeof uni === "undefined") {
|
|
222
|
+
throw new Error("UniApp environment not detected");
|
|
223
|
+
}
|
|
224
|
+
this.socketTask = uni.connectSocket({
|
|
225
|
+
url,
|
|
226
|
+
success: () => {
|
|
227
|
+
console.log("UniApp WebSocket connecting...");
|
|
228
|
+
},
|
|
229
|
+
fail: (err) => {
|
|
230
|
+
console.error("UniApp WebSocket connection failed:", err);
|
|
231
|
+
this._readyState = WS_CLOSED;
|
|
232
|
+
if (this.onerror) {
|
|
233
|
+
this.onerror({ message: err.errMsg || "Connection failed" });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
this.socketTask.onOpen((res) => {
|
|
238
|
+
this._readyState = WS_OPEN;
|
|
239
|
+
if (this.onopen) {
|
|
240
|
+
this.onopen(res);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
this.socketTask.onMessage((res) => {
|
|
244
|
+
if (this.onmessage) {
|
|
245
|
+
const data = res.data instanceof ArrayBuffer ? new TextDecoder().decode(res.data) : res.data;
|
|
246
|
+
this.onmessage({ data });
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
this.socketTask.onError((res) => {
|
|
250
|
+
console.error("UniApp WebSocket error:", res);
|
|
251
|
+
if (this.onerror) {
|
|
252
|
+
this.onerror({ message: res.errMsg || "WebSocket error" });
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
this.socketTask.onClose((res) => {
|
|
256
|
+
this._readyState = WS_CLOSED;
|
|
257
|
+
if (this.onclose) {
|
|
258
|
+
this.onclose({ code: res.code || 1e3, reason: res.reason || "" });
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
get readyState() {
|
|
263
|
+
return this._readyState;
|
|
264
|
+
}
|
|
265
|
+
send(data) {
|
|
266
|
+
if (this._readyState !== WS_OPEN || !this.socketTask) {
|
|
267
|
+
throw new Error("WebSocket is not open");
|
|
268
|
+
}
|
|
269
|
+
this.socketTask.send({
|
|
270
|
+
data,
|
|
271
|
+
fail: (err) => {
|
|
272
|
+
console.error("UniApp WebSocket send failed:", err);
|
|
273
|
+
if (this.onerror) {
|
|
274
|
+
this.onerror({ message: "Send failed" });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
close(code, reason) {
|
|
280
|
+
if (this._readyState === WS_CLOSED || this._readyState === WS_CLOSING) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
this._readyState = WS_CLOSING;
|
|
284
|
+
if (this.socketTask) {
|
|
285
|
+
this.socketTask.close({
|
|
286
|
+
code: code || 1e3,
|
|
287
|
+
reason: reason || "",
|
|
288
|
+
fail: (err) => {
|
|
289
|
+
console.error("UniApp WebSocket close failed:", err);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
function detectPlatform() {
|
|
296
|
+
if (typeof uni !== "undefined" && typeof uni.connectSocket === "function") {
|
|
297
|
+
return PlatformType.UniApp;
|
|
298
|
+
}
|
|
299
|
+
if (typeof wx !== "undefined" && typeof wx.connectSocket === "function") {
|
|
300
|
+
return PlatformType.WeChat;
|
|
301
|
+
}
|
|
302
|
+
if (typeof my !== "undefined" && typeof my.connectSocket === "function") {
|
|
303
|
+
return PlatformType.Alipay;
|
|
304
|
+
}
|
|
305
|
+
if (typeof WebSocket !== "undefined") {
|
|
306
|
+
return PlatformType.Browser;
|
|
307
|
+
}
|
|
308
|
+
return PlatformType.NodeJS;
|
|
41
309
|
}
|
|
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
|
-
|
|
310
|
+
var currentPlatform = detectPlatform();
|
|
311
|
+
exports2.currentPlatform = currentPlatform;
|
|
312
|
+
function createWebSocket(url) {
|
|
313
|
+
switch (currentPlatform) {
|
|
314
|
+
case PlatformType.UniApp:
|
|
315
|
+
return new UniAppWebSocketAdapter(url);
|
|
316
|
+
case PlatformType.WeChat:
|
|
317
|
+
return new WeChatWebSocketAdapter(url);
|
|
318
|
+
case PlatformType.Alipay:
|
|
319
|
+
return new AlipayWebSocketAdapter(url);
|
|
320
|
+
case PlatformType.Browser:
|
|
321
|
+
return new WebSocket(url);
|
|
322
|
+
case PlatformType.NodeJS:
|
|
323
|
+
default:
|
|
324
|
+
try {
|
|
325
|
+
const dynamicRequire = new Function("mod", "return require(mod)");
|
|
326
|
+
const Ws = dynamicRequire("ws");
|
|
327
|
+
const WsImpl = Ws.WebSocket || Ws;
|
|
328
|
+
return new WsImpl(url);
|
|
329
|
+
} catch (e) {
|
|
330
|
+
throw new Error("WebSocket is not available in this environment. Install 'ws' package for Node.js.");
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
var ChannelType;
|
|
335
|
+
(function(ChannelType2) {
|
|
336
|
+
ChannelType2[ChannelType2["Person"] = 1] = "Person";
|
|
337
|
+
ChannelType2[ChannelType2["Group"] = 2] = "Group";
|
|
338
|
+
ChannelType2[ChannelType2["CustomerService"] = 3] = "CustomerService";
|
|
339
|
+
ChannelType2[ChannelType2["Community"] = 4] = "Community";
|
|
340
|
+
ChannelType2[ChannelType2["CommunityTopic"] = 5] = "CommunityTopic";
|
|
341
|
+
ChannelType2[ChannelType2["Info"] = 6] = "Info";
|
|
342
|
+
ChannelType2[ChannelType2["Data"] = 7] = "Data";
|
|
343
|
+
ChannelType2[ChannelType2["Temp"] = 8] = "Temp";
|
|
344
|
+
ChannelType2[ChannelType2["Live"] = 9] = "Live";
|
|
345
|
+
ChannelType2[ChannelType2["Visitors"] = 10] = "Visitors";
|
|
346
|
+
})(ChannelType || (exports2.WKIMChannelType = exports2.ChannelType = ChannelType = {}));
|
|
347
|
+
var Event;
|
|
348
|
+
(function(Event2) {
|
|
349
|
+
Event2["Connect"] = "connect";
|
|
350
|
+
Event2["Disconnect"] = "disconnect";
|
|
351
|
+
Event2["Message"] = "message";
|
|
352
|
+
Event2["Error"] = "error";
|
|
353
|
+
Event2["SendAck"] = "sendack";
|
|
354
|
+
Event2["Reconnecting"] = "reconnecting";
|
|
355
|
+
Event2["CustomEvent"] = "customevent";
|
|
356
|
+
})(Event || (exports2.WKIMEvent = exports2.Event = Event = {}));
|
|
357
|
+
var ReasonCode;
|
|
358
|
+
(function(ReasonCode2) {
|
|
359
|
+
ReasonCode2[ReasonCode2["Unknown"] = 0] = "Unknown";
|
|
360
|
+
ReasonCode2[ReasonCode2["Success"] = 1] = "Success";
|
|
361
|
+
ReasonCode2[ReasonCode2["AuthFail"] = 2] = "AuthFail";
|
|
362
|
+
ReasonCode2[ReasonCode2["SubscriberNotExist"] = 3] = "SubscriberNotExist";
|
|
363
|
+
ReasonCode2[ReasonCode2["InBlacklist"] = 4] = "InBlacklist";
|
|
364
|
+
ReasonCode2[ReasonCode2["ChannelNotExist"] = 5] = "ChannelNotExist";
|
|
365
|
+
ReasonCode2[ReasonCode2["UserNotOnNode"] = 6] = "UserNotOnNode";
|
|
366
|
+
ReasonCode2[ReasonCode2["SenderOffline"] = 7] = "SenderOffline";
|
|
367
|
+
ReasonCode2[ReasonCode2["MsgKeyError"] = 8] = "MsgKeyError";
|
|
368
|
+
ReasonCode2[ReasonCode2["PayloadDecodeError"] = 9] = "PayloadDecodeError";
|
|
369
|
+
ReasonCode2[ReasonCode2["ForwardSendPacketError"] = 10] = "ForwardSendPacketError";
|
|
370
|
+
ReasonCode2[ReasonCode2["NotAllowSend"] = 11] = "NotAllowSend";
|
|
371
|
+
ReasonCode2[ReasonCode2["ConnectKick"] = 12] = "ConnectKick";
|
|
372
|
+
ReasonCode2[ReasonCode2["NotInWhitelist"] = 13] = "NotInWhitelist";
|
|
373
|
+
ReasonCode2[ReasonCode2["QueryTokenError"] = 14] = "QueryTokenError";
|
|
374
|
+
ReasonCode2[ReasonCode2["SystemError"] = 15] = "SystemError";
|
|
375
|
+
ReasonCode2[ReasonCode2["ChannelIDError"] = 16] = "ChannelIDError";
|
|
376
|
+
ReasonCode2[ReasonCode2["NodeMatchError"] = 17] = "NodeMatchError";
|
|
377
|
+
ReasonCode2[ReasonCode2["NodeNotMatch"] = 18] = "NodeNotMatch";
|
|
378
|
+
ReasonCode2[ReasonCode2["Ban"] = 19] = "Ban";
|
|
379
|
+
ReasonCode2[ReasonCode2["NotSupportHeader"] = 20] = "NotSupportHeader";
|
|
380
|
+
ReasonCode2[ReasonCode2["ClientKeyIsEmpty"] = 21] = "ClientKeyIsEmpty";
|
|
381
|
+
ReasonCode2[ReasonCode2["RateLimit"] = 22] = "RateLimit";
|
|
382
|
+
ReasonCode2[ReasonCode2["NotSupportChannelType"] = 23] = "NotSupportChannelType";
|
|
383
|
+
ReasonCode2[ReasonCode2["Disband"] = 24] = "Disband";
|
|
384
|
+
ReasonCode2[ReasonCode2["SendBan"] = 25] = "SendBan";
|
|
385
|
+
})(ReasonCode || (exports2.ReasonCode = ReasonCode = {}));
|
|
386
|
+
var DeviceFlag;
|
|
387
|
+
(function(DeviceFlag2) {
|
|
388
|
+
DeviceFlag2[DeviceFlag2["App"] = 0] = "App";
|
|
389
|
+
DeviceFlag2[DeviceFlag2["Web"] = 1] = "Web";
|
|
390
|
+
DeviceFlag2[DeviceFlag2["Desktop"] = 2] = "Desktop";
|
|
391
|
+
})(DeviceFlag || (exports2.WKIMDeviceFlag = exports2.DeviceFlag = DeviceFlag = {}));
|
|
392
|
+
var WKIM2 = class _WKIM {
|
|
393
|
+
constructor(url, auth) {
|
|
394
|
+
this.ws = null;
|
|
395
|
+
this.isConnected = false;
|
|
396
|
+
this.connectionPromise = null;
|
|
397
|
+
this.pingInterval = null;
|
|
398
|
+
this.pingTimeout = null;
|
|
399
|
+
this.PING_INTERVAL_MS = 25 * 1e3;
|
|
400
|
+
this.PONG_TIMEOUT_MS = 10 * 1e3;
|
|
401
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
402
|
+
this.eventListeners = /* @__PURE__ */ new Map();
|
|
403
|
+
this.reconnectAttempts = 0;
|
|
404
|
+
this.maxReconnectAttempts = 5;
|
|
405
|
+
this.initialReconnectDelay = 1e3;
|
|
406
|
+
this.isReconnecting = false;
|
|
407
|
+
this.manualDisconnect = false;
|
|
408
|
+
this.beforeUnloadHandler = null;
|
|
409
|
+
this.url = url;
|
|
410
|
+
this.auth = auth || {};
|
|
411
|
+
this.sessionId = this.generateUUID();
|
|
412
|
+
if (!this.auth.deviceId || this.auth.deviceId === "") {
|
|
413
|
+
this.auth.deviceId = `web_${this.sessionId.slice(0, 8)}_${Date.now()}`;
|
|
414
|
+
}
|
|
415
|
+
Object.values(Event).forEach((event) => this.eventListeners.set(event, []));
|
|
416
|
+
this.setupBeforeUnloadHandler();
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Initializes the WKIM instance.
|
|
420
|
+
* @param url WebSocket server URL (e.g., "ws://localhost:5100")
|
|
421
|
+
* @param auth Authentication options { uid, token, ... }
|
|
422
|
+
* @param options Configuration options { singleton: boolean }
|
|
423
|
+
* @returns A WKIM instance
|
|
424
|
+
*/
|
|
425
|
+
static init(url, auth, options = {}) {
|
|
426
|
+
if (!url || !auth || !auth.uid || !auth.token) {
|
|
427
|
+
throw new Error("URL, uid, and token are required for initialization.");
|
|
428
|
+
}
|
|
429
|
+
if (options.singleton && _WKIM.globalInstance) {
|
|
430
|
+
console.log("Destroying previous global instance...");
|
|
431
|
+
_WKIM.globalInstance.destroy();
|
|
432
|
+
}
|
|
433
|
+
const instance2 = new _WKIM(url, auth);
|
|
434
|
+
if (options.singleton !== false) {
|
|
435
|
+
_WKIM.globalInstance = instance2;
|
|
436
|
+
}
|
|
437
|
+
return instance2;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Establishes connection and authenticates with the server.
|
|
441
|
+
* Returns a Promise that resolves on successful connection/authentication,
|
|
442
|
+
* or rejects on failure.
|
|
443
|
+
*/
|
|
444
|
+
connect() {
|
|
445
|
+
return new Promise((resolve, reject) => {
|
|
446
|
+
var _a;
|
|
447
|
+
if (this.isConnected || ((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WS_CONNECTING) {
|
|
448
|
+
console.warn("Connection already established or in progress.");
|
|
449
|
+
if (this.isConnected) {
|
|
450
|
+
resolve();
|
|
451
|
+
} else if (this.connectionPromise) {
|
|
452
|
+
this.connectionPromise.resolve = resolve;
|
|
453
|
+
this.connectionPromise.reject = reject;
|
|
454
|
+
} else {
|
|
455
|
+
reject(new Error("Already connecting, but no connection promise found."));
|
|
456
|
+
}
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
this.manualDisconnect = false;
|
|
460
|
+
this.connectionPromise = { resolve, reject };
|
|
461
|
+
try {
|
|
462
|
+
console.log(`Connecting to ${this.url}... (Platform: ${currentPlatform})`);
|
|
463
|
+
this.ws = createWebSocket(this.url);
|
|
464
|
+
this.ws.onopen = () => {
|
|
465
|
+
console.log("WebSocket connection opened. Authenticating...");
|
|
466
|
+
this.sendConnectRequest();
|
|
467
|
+
};
|
|
468
|
+
this.ws.onmessage = (event) => {
|
|
469
|
+
this.handleMessage(event.data);
|
|
470
|
+
};
|
|
471
|
+
this.ws.onerror = (event) => {
|
|
472
|
+
const errorMessage = event.message || (event.error ? event.error.message : "WebSocket error");
|
|
473
|
+
console.error("WebSocket error:", errorMessage, event);
|
|
474
|
+
this.emit(Event.Error, event.error || new Error(errorMessage));
|
|
475
|
+
};
|
|
476
|
+
this.ws.onclose = (event) => {
|
|
477
|
+
const wasConnected = this.isConnected;
|
|
478
|
+
console.log(`WebSocket connection closed. Code: ${event.code}, Reason: ${event.reason}`);
|
|
479
|
+
if (this.connectionPromise && !this.isConnected) {
|
|
480
|
+
this.connectionPromise.reject(new Error(`Connection closed before authentication (Code: ${event.code})`));
|
|
481
|
+
}
|
|
482
|
+
this.cleanupConnection();
|
|
483
|
+
this.emit(Event.Disconnect, { code: event.code, reason: event.reason });
|
|
484
|
+
if (wasConnected && !this.manualDisconnect) {
|
|
485
|
+
this.tryReconnect();
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
} catch (error) {
|
|
489
|
+
console.error("Failed to create WebSocket:", error);
|
|
490
|
+
this.emit(Event.Error, error);
|
|
491
|
+
if (this.connectionPromise) {
|
|
492
|
+
this.connectionPromise.reject(error);
|
|
493
|
+
this.connectionPromise = null;
|
|
494
|
+
}
|
|
495
|
+
this.cleanupConnection();
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Disconnects from the server.
|
|
501
|
+
*/
|
|
502
|
+
disconnect() {
|
|
503
|
+
console.log("Manual disconnect initiated.");
|
|
504
|
+
this.manualDisconnect = true;
|
|
505
|
+
this.isReconnecting = false;
|
|
506
|
+
this.cleanupBeforeUnloadHandler();
|
|
507
|
+
this.handleDisconnect(true, "Manual disconnection");
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Completely destroys the SDK instance, cleaning up all resources.
|
|
511
|
+
* Call this when you no longer need the SDK instance.
|
|
512
|
+
*/
|
|
513
|
+
destroy() {
|
|
514
|
+
console.log("Destroying SDK instance...");
|
|
515
|
+
this.disconnect();
|
|
516
|
+
this.eventListeners.clear();
|
|
517
|
+
this.pendingRequests.clear();
|
|
518
|
+
if (_WKIM.globalInstance === this) {
|
|
519
|
+
_WKIM.globalInstance = null;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Sends a message to a specific channel.
|
|
524
|
+
* @param channelId Target channel ID
|
|
525
|
+
* @param channelType Target channel type (e.g., WKIM.ChannelType.Person)
|
|
526
|
+
* @param payload Message payload (must be a JSON-serializable object)
|
|
527
|
+
* @param options Optional: { clientMsgNo, header, setting, msgKey, expire, topic }
|
|
528
|
+
* @returns Promise resolving with { messageId, messageSeq } on server ack, or rejecting on error.
|
|
529
|
+
*/
|
|
530
|
+
send(channelId, channelType, payload, options = {}) {
|
|
531
|
+
if (!this.isConnected || !this.ws || this.ws.readyState !== WS_OPEN) {
|
|
532
|
+
return Promise.reject(new Error("Not connected. Call connect() first."));
|
|
533
|
+
}
|
|
534
|
+
if (typeof payload !== "object" || payload === null) {
|
|
535
|
+
return Promise.reject(new Error("Payload must be a non-null object."));
|
|
536
|
+
}
|
|
537
|
+
const header = options.header || {};
|
|
538
|
+
header.redDot = true;
|
|
539
|
+
const clientMsgNo = options.clientMsgNo || this.generateUUID();
|
|
540
|
+
const params = {
|
|
541
|
+
clientMsgNo,
|
|
542
|
+
channelId,
|
|
543
|
+
channelType,
|
|
544
|
+
payload: this._encodePayloadToBase64(payload),
|
|
545
|
+
header,
|
|
546
|
+
topic: options.topic,
|
|
547
|
+
setting: options.setting
|
|
548
|
+
};
|
|
549
|
+
return this.sendRequest("send", params);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Registers an event listener.
|
|
553
|
+
* @param eventName The event to listen for (e.g., WKIM.Event.Message)
|
|
554
|
+
* @param callback The function to call when the event occurs
|
|
555
|
+
*/
|
|
556
|
+
on(eventName, callback) {
|
|
557
|
+
var _a;
|
|
558
|
+
if (this.eventListeners.has(eventName)) {
|
|
559
|
+
(_a = this.eventListeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.push(callback);
|
|
560
|
+
} else {
|
|
561
|
+
console.warn(`Attempted to register listener for unknown event: ${eventName}`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Removes an event listener.
|
|
566
|
+
* @param eventName The event to stop listening for
|
|
567
|
+
* @param callback The specific callback function to remove
|
|
568
|
+
*/
|
|
569
|
+
off(eventName, callback) {
|
|
570
|
+
if (this.eventListeners.has(eventName)) {
|
|
571
|
+
const listeners = this.eventListeners.get(eventName);
|
|
572
|
+
if (listeners) {
|
|
573
|
+
const index = listeners.indexOf(callback);
|
|
574
|
+
if (index > -1) {
|
|
575
|
+
listeners.splice(index, 1);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// --- Private Methods ---
|
|
581
|
+
emit(eventName, ...args) {
|
|
582
|
+
const listeners = this.eventListeners.get(eventName);
|
|
583
|
+
if (listeners) {
|
|
584
|
+
listeners.forEach((callback) => {
|
|
585
|
+
try {
|
|
586
|
+
callback(...args);
|
|
587
|
+
} catch (error) {
|
|
588
|
+
console.error(`Error in event listener for ${eventName}:`, error);
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
generateUUID() {
|
|
594
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
595
|
+
const r = Math.random() * 16 | 0, v = c === "x" ? r : r & 3 | 8;
|
|
596
|
+
return v.toString(16);
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
sendConnectRequest() {
|
|
600
|
+
var _a;
|
|
601
|
+
const params = {
|
|
602
|
+
uid: this.auth.uid,
|
|
603
|
+
token: this.auth.token,
|
|
604
|
+
deviceId: this.auth.deviceId,
|
|
605
|
+
deviceFlag: (_a = this.auth.deviceFlag) !== null && _a !== void 0 ? _a : DeviceFlag.Web,
|
|
606
|
+
// Default to WEB
|
|
607
|
+
clientTimestamp: Date.now()
|
|
608
|
+
// Add version, clientKey if needed
|
|
609
|
+
};
|
|
610
|
+
this.sendRequest("connect", params, 5e3).then((result) => {
|
|
611
|
+
console.log("Authentication successful:", result);
|
|
612
|
+
this.isConnected = true;
|
|
613
|
+
this.reconnectAttempts = 0;
|
|
614
|
+
this.isReconnecting = false;
|
|
615
|
+
this.manualDisconnect = false;
|
|
616
|
+
this.startPing();
|
|
617
|
+
this.emit(Event.Connect, result);
|
|
618
|
+
if (this.connectionPromise) {
|
|
619
|
+
this.connectionPromise.resolve();
|
|
620
|
+
this.connectionPromise = null;
|
|
621
|
+
}
|
|
622
|
+
}).catch((error) => {
|
|
623
|
+
console.error("Authentication failed:", error);
|
|
624
|
+
this.emit(Event.Error, new Error(`Authentication failed: ${error.message || JSON.stringify(error)}`));
|
|
625
|
+
if (this.connectionPromise) {
|
|
626
|
+
this.connectionPromise.reject(error);
|
|
627
|
+
this.connectionPromise = null;
|
|
628
|
+
}
|
|
629
|
+
this.handleDisconnect(false, "Authentication failed");
|
|
630
|
+
this.cleanupConnection();
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
sendRequest(method, params, timeoutMs = 15e3) {
|
|
634
|
+
return new Promise((resolve, reject) => {
|
|
635
|
+
if (!this.ws || this.ws.readyState !== WS_OPEN) {
|
|
636
|
+
return reject(new Error("WebSocket is not open."));
|
|
637
|
+
}
|
|
638
|
+
const requestId = this.generateUUID();
|
|
639
|
+
const request = {
|
|
640
|
+
method,
|
|
641
|
+
params,
|
|
642
|
+
id: requestId
|
|
643
|
+
};
|
|
644
|
+
const timeoutTimer = setTimeout(() => {
|
|
645
|
+
this.pendingRequests.delete(requestId);
|
|
646
|
+
reject(new Error(`Request timeout for method ${method} (id: ${requestId})`));
|
|
647
|
+
}, timeoutMs);
|
|
648
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeoutTimer });
|
|
649
|
+
try {
|
|
650
|
+
console.debug(`--> Sending request (id: ${requestId}):`, JSON.stringify(request));
|
|
651
|
+
this.ws.send(JSON.stringify(request));
|
|
652
|
+
} catch (error) {
|
|
653
|
+
clearTimeout(timeoutTimer);
|
|
654
|
+
this.pendingRequests.delete(requestId);
|
|
655
|
+
console.error(`Error sending request (id: ${requestId}):`, error);
|
|
656
|
+
reject(error);
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
sendNotification(method, params) {
|
|
661
|
+
if (!this.ws || this.ws.readyState !== WS_OPEN) {
|
|
662
|
+
console.error("Cannot send notification, WebSocket is not open.");
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
const notification = {
|
|
666
|
+
method,
|
|
667
|
+
params
|
|
668
|
+
};
|
|
669
|
+
console.debug(`--> Sending notification:`, JSON.stringify(notification));
|
|
670
|
+
try {
|
|
671
|
+
this.ws.send(JSON.stringify(notification));
|
|
672
|
+
} catch (error) {
|
|
673
|
+
console.error(`Error sending notification (${method}):`, error);
|
|
674
|
+
this.emit(Event.Error, new Error(`Failed to send notification ${method}: ${error}`));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
handleMessage(data) {
|
|
678
|
+
console.debug("<-- Received raw:", data);
|
|
679
|
+
let message;
|
|
680
|
+
try {
|
|
681
|
+
message = JSON.parse(data.toString());
|
|
682
|
+
} catch (error) {
|
|
683
|
+
console.error("Failed to parse incoming message:", error, data);
|
|
684
|
+
this.emit(Event.Error, new Error(`Failed to parse message: ${error}`));
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
if ("id" in message) {
|
|
688
|
+
this.handleResponse(message);
|
|
689
|
+
} else if ("method" in message) {
|
|
690
|
+
this.handleNotification(message);
|
|
691
|
+
} else {
|
|
692
|
+
console.warn("Received unknown message format:", message);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
handleResponse(response) {
|
|
696
|
+
console.debug(`<-- Handling response (id: ${response.id}):`, response);
|
|
697
|
+
const pending = this.pendingRequests.get(response.id);
|
|
698
|
+
if (pending) {
|
|
699
|
+
clearTimeout(pending.timeoutTimer);
|
|
700
|
+
this.pendingRequests.delete(response.id);
|
|
701
|
+
if (response.error) {
|
|
702
|
+
pending.reject(response.error);
|
|
703
|
+
} else {
|
|
704
|
+
pending.resolve(response.result);
|
|
705
|
+
}
|
|
706
|
+
} else {
|
|
707
|
+
console.warn(`Received response for unknown request ID: ${response.id}`);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
handleNotification(notification) {
|
|
711
|
+
var _a, _b;
|
|
712
|
+
console.debug(`<-- Handling notification (${notification.method}):`, notification.params);
|
|
713
|
+
switch (notification.method) {
|
|
714
|
+
case "recv":
|
|
715
|
+
const messageData = notification.params;
|
|
716
|
+
if (typeof messageData.payload === "string") {
|
|
717
|
+
try {
|
|
718
|
+
messageData.payload = JSON.parse(this._decodeBase64ToStr(messageData.payload));
|
|
719
|
+
} catch (e) {
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
this.emit(Event.Message, messageData);
|
|
723
|
+
this.sendRecvAck(messageData.header, messageData.messageId, messageData.messageSeq);
|
|
724
|
+
break;
|
|
725
|
+
case "pong":
|
|
726
|
+
this.handlePong();
|
|
727
|
+
break;
|
|
728
|
+
case "disconnect":
|
|
729
|
+
console.warn("Server initiated disconnect:", notification.params);
|
|
730
|
+
this.emit(Event.Disconnect, notification.params);
|
|
731
|
+
this.handleDisconnect(false, `Server disconnected: ${((_a = notification.params) === null || _a === void 0 ? void 0 : _a.reason) || ((_b = notification.params) === null || _b === void 0 ? void 0 : _b.reasonCode)}`);
|
|
732
|
+
break;
|
|
733
|
+
case "event":
|
|
734
|
+
this.handleEventNotification(notification.params);
|
|
735
|
+
break;
|
|
736
|
+
// Handle other notifications if needed
|
|
737
|
+
default:
|
|
738
|
+
console.warn(`Received unhandled notification method: ${notification.method}`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Encode payload object to base64 string.
|
|
743
|
+
* WuKongIM server expects payload as []byte (base64 in JSON).
|
|
744
|
+
*/
|
|
745
|
+
_encodePayloadToBase64(payload) {
|
|
746
|
+
const json = JSON.stringify(payload);
|
|
747
|
+
if (typeof TextEncoder !== "undefined" && typeof btoa !== "undefined") {
|
|
748
|
+
const bytes = new TextEncoder().encode(json);
|
|
749
|
+
let binary = "";
|
|
750
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
751
|
+
binary += String.fromCharCode(bytes[i]);
|
|
752
|
+
}
|
|
753
|
+
return btoa(binary);
|
|
754
|
+
}
|
|
755
|
+
if (typeof Buffer !== "undefined") {
|
|
756
|
+
return Buffer.from(json, "utf-8").toString("base64");
|
|
757
|
+
}
|
|
758
|
+
if (typeof wx !== "undefined" && (wx === null || wx === void 0 ? void 0 : wx.arrayBufferToBase64)) {
|
|
759
|
+
const encoder = new TextEncoder();
|
|
760
|
+
const bytes = encoder.encode(json);
|
|
761
|
+
return wx.arrayBufferToBase64(bytes.buffer);
|
|
762
|
+
}
|
|
763
|
+
throw new Error("No base64 encoding method available");
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Decode base64 string to UTF-8 string.
|
|
767
|
+
*/
|
|
768
|
+
_decodeBase64ToStr(base64Str) {
|
|
769
|
+
if (typeof atob !== "undefined" && typeof TextDecoder !== "undefined") {
|
|
770
|
+
const binary = atob(base64Str);
|
|
771
|
+
const bytes = new Uint8Array(binary.length);
|
|
772
|
+
for (let i = 0; i < binary.length; i++) {
|
|
773
|
+
bytes[i] = binary.charCodeAt(i);
|
|
774
|
+
}
|
|
775
|
+
return new TextDecoder().decode(bytes);
|
|
776
|
+
}
|
|
777
|
+
if (typeof Buffer !== "undefined") {
|
|
778
|
+
return Buffer.from(base64Str, "base64").toString("utf-8");
|
|
779
|
+
}
|
|
780
|
+
if (typeof wx !== "undefined" && (wx === null || wx === void 0 ? void 0 : wx.base64ToArrayBuffer)) {
|
|
781
|
+
const buf = wx.base64ToArrayBuffer(base64Str);
|
|
782
|
+
return new TextDecoder().decode(new Uint8Array(buf));
|
|
783
|
+
}
|
|
784
|
+
throw new Error("No base64 decoding method available");
|
|
785
|
+
}
|
|
786
|
+
sendRecvAck(header, messageId, messageSeq) {
|
|
787
|
+
const params = { header, messageId, messageSeq };
|
|
788
|
+
this.sendNotification("recvack", params);
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Handles incoming event notifications from the server
|
|
792
|
+
* @param params Event notification parameters
|
|
793
|
+
*/
|
|
794
|
+
handleEventNotification(params) {
|
|
795
|
+
try {
|
|
796
|
+
const eventData = {
|
|
797
|
+
header: params.header,
|
|
798
|
+
id: params.id,
|
|
799
|
+
type: params.type,
|
|
800
|
+
timestamp: params.timestamp,
|
|
801
|
+
data: params.data
|
|
802
|
+
};
|
|
803
|
+
if (!eventData.id || !eventData.type) {
|
|
804
|
+
console.error("Invalid event notification: missing required fields", params);
|
|
805
|
+
this.emit(Event.Error, new Error("Invalid event notification: missing required fields"));
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
if (typeof eventData.data === "string") {
|
|
809
|
+
try {
|
|
810
|
+
eventData.data = JSON.parse(eventData.data);
|
|
811
|
+
} catch (e) {
|
|
812
|
+
console.debug("Event data is not JSON, keeping as string");
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
console.log(`Event notification received: type=${eventData.type}, id=${eventData.id}`);
|
|
816
|
+
this.emit(Event.CustomEvent, eventData);
|
|
817
|
+
} catch (error) {
|
|
818
|
+
console.error("Error handling event notification:", error);
|
|
819
|
+
this.emit(Event.Error, new Error(`Failed to handle event notification: ${error}`));
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
startPing() {
|
|
823
|
+
this.stopPing();
|
|
824
|
+
this.pingInterval = setInterval(() => {
|
|
825
|
+
if (this.ws && this.ws.readyState === WS_OPEN) {
|
|
826
|
+
this.sendRequest("ping", {}, this.PONG_TIMEOUT_MS).then(this.handlePong.bind(this)).catch((err) => {
|
|
827
|
+
console.error("Ping failed or timed out:", err);
|
|
828
|
+
this.emit(Event.Error, new Error(`Ping timeout: ${(err === null || err === void 0 ? void 0 : err.message) || err}`));
|
|
829
|
+
if (!this.manualDisconnect) {
|
|
830
|
+
this.handleDisconnect(false, "Ping timeout");
|
|
831
|
+
this.tryReconnect();
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
} else {
|
|
835
|
+
this.stopPing();
|
|
836
|
+
}
|
|
837
|
+
}, this.PING_INTERVAL_MS);
|
|
838
|
+
console.log(`Ping interval started (${this.PING_INTERVAL_MS}ms).`);
|
|
839
|
+
}
|
|
840
|
+
stopPing() {
|
|
841
|
+
if (this.pingInterval) {
|
|
842
|
+
clearInterval(this.pingInterval);
|
|
843
|
+
this.pingInterval = null;
|
|
844
|
+
console.log("Ping interval stopped.");
|
|
845
|
+
}
|
|
846
|
+
if (this.pingTimeout) {
|
|
847
|
+
clearTimeout(this.pingTimeout);
|
|
848
|
+
this.pingTimeout = null;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
handlePong() {
|
|
852
|
+
}
|
|
853
|
+
handleDisconnect(graceful, reason) {
|
|
854
|
+
console.log(`Handling disconnect. Graceful: ${graceful}, Reason: ${reason}`);
|
|
855
|
+
if (this.ws) {
|
|
856
|
+
this.stopPing();
|
|
857
|
+
if (graceful && this.ws.readyState === WS_OPEN) {
|
|
858
|
+
this.ws.close(1e3, "Client disconnected");
|
|
859
|
+
} else if (this.ws.readyState === WS_CONNECTING || this.ws.readyState === WS_OPEN) {
|
|
860
|
+
this.ws.close(3001, reason.substring(0, 123));
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
this.cleanupConnection();
|
|
864
|
+
}
|
|
865
|
+
cleanupConnection() {
|
|
866
|
+
console.log("Cleaning up connection resources.");
|
|
867
|
+
this.isConnected = false;
|
|
868
|
+
this.stopPing();
|
|
869
|
+
this.pendingRequests.forEach((pending) => {
|
|
870
|
+
clearTimeout(pending.timeoutTimer);
|
|
871
|
+
pending.reject(new Error("Connection closed"));
|
|
872
|
+
});
|
|
873
|
+
this.pendingRequests.clear();
|
|
874
|
+
if (this.connectionPromise) {
|
|
875
|
+
if (!this.isReconnecting && !this.isConnected) {
|
|
876
|
+
this.connectionPromise.reject(new Error("Connection closed during operation"));
|
|
877
|
+
}
|
|
878
|
+
this.connectionPromise = null;
|
|
879
|
+
}
|
|
880
|
+
if (this.ws) {
|
|
881
|
+
this.ws.onopen = null;
|
|
882
|
+
this.ws.onmessage = null;
|
|
883
|
+
this.ws.onerror = null;
|
|
884
|
+
this.ws.onclose = null;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
// --- Reconnection Methods ---
|
|
888
|
+
setupBeforeUnloadHandler() {
|
|
889
|
+
if (typeof window !== "undefined") {
|
|
890
|
+
this.beforeUnloadHandler = () => {
|
|
891
|
+
console.log("Page unloading, closing WebSocket connection...");
|
|
892
|
+
this.manualDisconnect = true;
|
|
893
|
+
this.isReconnecting = false;
|
|
894
|
+
if (this.ws && this.ws.readyState === WS_OPEN) {
|
|
895
|
+
this.ws.close(1e3, "Page unloaded");
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
window.addEventListener("beforeunload", this.beforeUnloadHandler);
|
|
899
|
+
window.addEventListener("pagehide", this.beforeUnloadHandler);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
cleanupBeforeUnloadHandler() {
|
|
903
|
+
if (typeof window !== "undefined" && this.beforeUnloadHandler) {
|
|
904
|
+
window.removeEventListener("beforeunload", this.beforeUnloadHandler);
|
|
905
|
+
window.removeEventListener("pagehide", this.beforeUnloadHandler);
|
|
906
|
+
this.beforeUnloadHandler = null;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
tryReconnect() {
|
|
910
|
+
if (this.isReconnecting || this.manualDisconnect) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
this.isReconnecting = true;
|
|
914
|
+
this.scheduleReconnect();
|
|
915
|
+
}
|
|
916
|
+
scheduleReconnect() {
|
|
917
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
918
|
+
console.error("Max reconnect attempts reached. Giving up.");
|
|
919
|
+
this.isReconnecting = false;
|
|
920
|
+
this.reconnectAttempts = 0;
|
|
921
|
+
this.emit(Event.Error, new Error("Reconnection failed."));
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
const delay = this.initialReconnectDelay * Math.pow(2, this.reconnectAttempts);
|
|
925
|
+
this.reconnectAttempts++;
|
|
926
|
+
console.log(`Will attempt to reconnect in ${delay / 1e3}s (Attempt ${this.reconnectAttempts}).`);
|
|
927
|
+
this.emit(Event.Reconnecting, { attempt: this.reconnectAttempts, delay });
|
|
928
|
+
setTimeout(() => {
|
|
929
|
+
if (!this.isReconnecting) {
|
|
930
|
+
console.log("Reconnection aborted.");
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
this.connect().catch(() => {
|
|
934
|
+
if (this.isReconnecting) {
|
|
935
|
+
this.scheduleReconnect();
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
}, delay);
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
exports2.WKIM = WKIM2;
|
|
942
|
+
WKIM2.globalInstance = null;
|
|
113
943
|
}
|
|
114
|
-
}
|
|
944
|
+
});
|
|
115
945
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
946
|
+
// miniprogram_dist/services/wukongim.js
|
|
947
|
+
var WKIM = require_cjs().WKIM;
|
|
948
|
+
var WKIMEvent = require_cjs().WKIMEvent;
|
|
949
|
+
var adapter = require("../adapters/request");
|
|
950
|
+
function WuKongIMService() {
|
|
951
|
+
this._inited = false;
|
|
952
|
+
this._im = null;
|
|
953
|
+
this._cfg = null;
|
|
954
|
+
this._uid = null;
|
|
955
|
+
this._bound = false;
|
|
956
|
+
this._hConnect = null;
|
|
957
|
+
this._hDisconnect = null;
|
|
958
|
+
this._hError = null;
|
|
959
|
+
this._hMessage = null;
|
|
960
|
+
this._hCustom = null;
|
|
961
|
+
this._msgListeners = [];
|
|
962
|
+
this._statusListeners = [];
|
|
963
|
+
this._customListeners = [];
|
|
120
964
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
965
|
+
WuKongIMService.prototype.isReady = function() {
|
|
966
|
+
return this._inited && !!this._im && !!this._cfg;
|
|
967
|
+
};
|
|
968
|
+
WuKongIMService.prototype.getUid = function() {
|
|
969
|
+
return this._uid;
|
|
970
|
+
};
|
|
971
|
+
WuKongIMService.prototype.init = function(opts) {
|
|
972
|
+
var self = this;
|
|
973
|
+
this._cfg = Object.assign({}, opts, { channelType: opts.channelType || "person" });
|
|
974
|
+
this._uid = opts.uid;
|
|
975
|
+
return this._fetchRouteWsAddr(opts.apiBase, opts.uid, 1e4).then(function(wsAddr) {
|
|
976
|
+
if (self._im && self._bound) {
|
|
977
|
+
try {
|
|
978
|
+
self._unbindInternalEvents();
|
|
979
|
+
} catch (e) {
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
self._im = WKIM.init(wsAddr, { uid: opts.uid, token: opts.token || "" });
|
|
983
|
+
self._bindInternalEvents();
|
|
984
|
+
self._inited = true;
|
|
985
|
+
});
|
|
986
|
+
};
|
|
987
|
+
WuKongIMService.prototype._bindInternalEvents = function() {
|
|
988
|
+
if (!this._im || this._bound) return;
|
|
989
|
+
var self = this;
|
|
990
|
+
this._hConnect = function(result) {
|
|
991
|
+
self._emitStatus("connected", result);
|
|
992
|
+
};
|
|
993
|
+
this._hDisconnect = function(info) {
|
|
994
|
+
self._emitStatus("disconnected", info);
|
|
995
|
+
};
|
|
996
|
+
this._hError = function(err) {
|
|
997
|
+
self._emitStatus("error", err);
|
|
998
|
+
};
|
|
999
|
+
this._hMessage = function(message) {
|
|
1000
|
+
self._emitMessage(message);
|
|
1001
|
+
};
|
|
1002
|
+
this._hCustom = function(ev) {
|
|
1003
|
+
self._emitCustom(ev);
|
|
1004
|
+
};
|
|
1005
|
+
this._im.on(WKIMEvent.Connect, this._hConnect);
|
|
1006
|
+
this._im.on(WKIMEvent.Disconnect, this._hDisconnect);
|
|
1007
|
+
this._im.on(WKIMEvent.Error, this._hError);
|
|
1008
|
+
this._im.on(WKIMEvent.Message, this._hMessage);
|
|
1009
|
+
this._im.on(WKIMEvent.CustomEvent, this._hCustom);
|
|
1010
|
+
this._bound = true;
|
|
1011
|
+
};
|
|
1012
|
+
WuKongIMService.prototype._unbindInternalEvents = function() {
|
|
1013
|
+
if (!this._im || !this._bound) return;
|
|
1014
|
+
if (this._hConnect) this._im.off(WKIMEvent.Connect, this._hConnect);
|
|
1015
|
+
if (this._hDisconnect) this._im.off(WKIMEvent.Disconnect, this._hDisconnect);
|
|
1016
|
+
if (this._hError) this._im.off(WKIMEvent.Error, this._hError);
|
|
1017
|
+
if (this._hMessage) this._im.off(WKIMEvent.Message, this._hMessage);
|
|
1018
|
+
if (this._hCustom) this._im.off(WKIMEvent.CustomEvent, this._hCustom);
|
|
1019
|
+
this._hConnect = this._hDisconnect = this._hError = this._hMessage = this._hCustom = null;
|
|
1020
|
+
this._bound = false;
|
|
1021
|
+
};
|
|
1022
|
+
WuKongIMService.prototype._emitMessage = function(m) {
|
|
1023
|
+
this._msgListeners.forEach(function(fn) {
|
|
1024
|
+
try {
|
|
1025
|
+
fn(m);
|
|
1026
|
+
} catch (e) {
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
};
|
|
1030
|
+
WuKongIMService.prototype._emitStatus = function(s, info) {
|
|
1031
|
+
this._statusListeners.forEach(function(fn) {
|
|
1032
|
+
try {
|
|
1033
|
+
fn(s, info);
|
|
1034
|
+
} catch (e) {
|
|
1035
|
+
}
|
|
1036
|
+
});
|
|
1037
|
+
};
|
|
1038
|
+
WuKongIMService.prototype._emitCustom = function(e) {
|
|
1039
|
+
this._customListeners.forEach(function(fn) {
|
|
1040
|
+
try {
|
|
1041
|
+
fn(e);
|
|
1042
|
+
} catch (e2) {
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
};
|
|
1046
|
+
WuKongIMService.prototype.onMessage = function(cb) {
|
|
1047
|
+
this._msgListeners.push(cb);
|
|
1048
|
+
var self = this;
|
|
1049
|
+
return function() {
|
|
1050
|
+
var idx = self._msgListeners.indexOf(cb);
|
|
1051
|
+
if (idx >= 0) self._msgListeners.splice(idx, 1);
|
|
1052
|
+
};
|
|
1053
|
+
};
|
|
1054
|
+
WuKongIMService.prototype.onStatus = function(cb) {
|
|
1055
|
+
this._statusListeners.push(cb);
|
|
1056
|
+
var self = this;
|
|
1057
|
+
return function() {
|
|
1058
|
+
var idx = self._statusListeners.indexOf(cb);
|
|
1059
|
+
if (idx >= 0) self._statusListeners.splice(idx, 1);
|
|
1060
|
+
};
|
|
1061
|
+
};
|
|
1062
|
+
WuKongIMService.prototype.onCustom = function(cb) {
|
|
1063
|
+
this._customListeners.push(cb);
|
|
1064
|
+
var self = this;
|
|
1065
|
+
return function() {
|
|
1066
|
+
var idx = self._customListeners.indexOf(cb);
|
|
1067
|
+
if (idx >= 0) self._customListeners.splice(idx, 1);
|
|
1068
|
+
};
|
|
1069
|
+
};
|
|
1070
|
+
WuKongIMService.prototype.connect = function() {
|
|
1071
|
+
if (!this._im) throw new Error("WuKongIMService not initialized");
|
|
1072
|
+
this._emitStatus("connecting");
|
|
1073
|
+
return this._im.connect();
|
|
1074
|
+
};
|
|
1075
|
+
WuKongIMService.prototype.disconnect = function() {
|
|
1076
|
+
if (!this._im) return Promise.resolve();
|
|
1077
|
+
if (typeof this._im.disconnect === "function") {
|
|
1078
|
+
try {
|
|
1079
|
+
return this._im.disconnect();
|
|
1080
|
+
} catch (e) {
|
|
1081
|
+
return Promise.resolve();
|
|
1082
|
+
}
|
|
126
1083
|
}
|
|
127
|
-
return Promise.resolve()
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
var
|
|
132
|
-
var url = base + 'v1/wukongim/route?uid=' + encodeURIComponent(uid)
|
|
133
|
-
|
|
1084
|
+
return Promise.resolve();
|
|
1085
|
+
};
|
|
1086
|
+
WuKongIMService.prototype._fetchRouteWsAddr = function(apiBase, uid, timeoutMs) {
|
|
1087
|
+
var base = apiBase.endsWith("/") ? apiBase : apiBase + "/";
|
|
1088
|
+
var url = base + "v1/wukongim/route?uid=" + encodeURIComponent(uid);
|
|
134
1089
|
return adapter.request({
|
|
135
|
-
url
|
|
136
|
-
method:
|
|
137
|
-
timeout: timeoutMs ||
|
|
138
|
-
}).then(function
|
|
139
|
-
if (!res.ok) throw new Error(
|
|
140
|
-
return res.json().then(function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
opts = opts || {}
|
|
162
|
-
var to = opts.to || this._cfg.target
|
|
163
|
-
var payload = { type: 1, content: text }
|
|
1090
|
+
url,
|
|
1091
|
+
method: "GET",
|
|
1092
|
+
timeout: timeoutMs || 1e4
|
|
1093
|
+
}).then(function(res) {
|
|
1094
|
+
if (!res.ok) throw new Error("route HTTP " + res.status);
|
|
1095
|
+
return res.json().then(function(data) {
|
|
1096
|
+
if (data && data.wss_addr && typeof data.wss_addr === "string" && data.wss_addr.trim()) {
|
|
1097
|
+
return data.wss_addr.trim();
|
|
1098
|
+
}
|
|
1099
|
+
var addr = data.ws_addr || data.ws || data.ws_url || data.wsAddr || data.websocket;
|
|
1100
|
+
if (!addr && data.wss) addr = data.wss;
|
|
1101
|
+
if (!addr || typeof addr !== "string") throw new Error("missing ws address");
|
|
1102
|
+
var wsAddr = String(addr);
|
|
1103
|
+
if (/^http(s)?:/i.test(wsAddr)) wsAddr = wsAddr.replace(/^http/i, "ws");
|
|
1104
|
+
return wsAddr;
|
|
1105
|
+
});
|
|
1106
|
+
}).catch(function(e) {
|
|
1107
|
+
var msg = e && e.message ? String(e.message) : String(e);
|
|
1108
|
+
throw new Error("[WuKongIM] route fetch failed: " + msg);
|
|
1109
|
+
});
|
|
1110
|
+
};
|
|
1111
|
+
WuKongIMService.prototype.sendText = function(text, opts) {
|
|
1112
|
+
if (!this._im || !this._cfg) throw new Error("WuKongIMService not ready");
|
|
1113
|
+
opts = opts || {};
|
|
1114
|
+
var to = opts.to || this._cfg.target;
|
|
1115
|
+
var payload = { type: 1, content: text };
|
|
164
1116
|
return this._im.send(to, opts.channelType || 251, payload, {
|
|
165
1117
|
clientMsgNo: opts.clientMsgNo,
|
|
166
1118
|
header: opts.header
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
var to = opts.to || this._cfg.target
|
|
1119
|
+
});
|
|
1120
|
+
};
|
|
1121
|
+
WuKongIMService.prototype.sendPayload = function(payload, opts) {
|
|
1122
|
+
if (!this._im || !this._cfg) throw new Error("WuKongIMService not ready");
|
|
1123
|
+
opts = opts || {};
|
|
1124
|
+
var to = opts.to || this._cfg.target;
|
|
174
1125
|
return this._im.send(to, opts.channelType || 251, payload, {
|
|
175
1126
|
clientMsgNo: opts.clientMsgNo,
|
|
176
1127
|
header: opts.header
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
var instance = new WuKongIMService()
|
|
182
|
-
|
|
183
|
-
module.exports = instance
|
|
1128
|
+
});
|
|
1129
|
+
};
|
|
1130
|
+
var instance = new WuKongIMService();
|
|
1131
|
+
module.exports = instance;
|