ly-utils-lib 1.0.12 → 2.5.0
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/LICENSE +21 -0
- package/README.md +1002 -685
- package/dist/array.cjs +237 -0
- package/dist/array.cjs.map +1 -0
- package/dist/array.d.cts +2 -0
- package/dist/array.d.ts +2 -0
- package/dist/array.js +150 -0
- package/dist/array.js.map +1 -0
- package/dist/crypto.cjs +193 -0
- package/dist/crypto.cjs.map +1 -0
- package/dist/crypto.d.cts +3 -0
- package/dist/crypto.d.ts +3 -0
- package/dist/crypto.js +144 -0
- package/dist/crypto.js.map +1 -0
- package/dist/date.cjs +563 -0
- package/dist/date.cjs.map +1 -0
- package/dist/date.d.cts +2 -0
- package/dist/date.d.ts +2 -0
- package/dist/date.js +451 -0
- package/dist/date.js.map +1 -0
- package/dist/excel.cjs +227 -0
- package/dist/excel.cjs.map +1 -0
- package/dist/excel.d.cts +2 -0
- package/dist/excel.d.ts +2 -0
- package/dist/excel.js +196 -0
- package/dist/excel.js.map +1 -0
- package/dist/index-B80SEVzM.d.cts +382 -0
- package/dist/index-B80SEVzM.d.ts +382 -0
- package/dist/index-Ba1rjTzj.d.cts +299 -0
- package/dist/index-Ba1rjTzj.d.ts +299 -0
- package/dist/index-Bg1ise7y.d.cts +253 -0
- package/dist/index-Bg1ise7y.d.ts +253 -0
- package/dist/index-BoqNpwNa.d.cts +203 -0
- package/dist/index-BoqNpwNa.d.ts +203 -0
- package/dist/index-C0qUnb9Y.d.cts +533 -0
- package/dist/index-C0qUnb9Y.d.ts +533 -0
- package/dist/index-Cq1GhjpY.d.cts +229 -0
- package/dist/index-Cq1GhjpY.d.ts +229 -0
- package/dist/index-Cy-mb5v_.d.cts +262 -0
- package/dist/index-Cy-mb5v_.d.ts +262 -0
- package/dist/index-D1f9Sym2.d.cts +148 -0
- package/dist/index-D1f9Sym2.d.ts +148 -0
- package/dist/index-Dan5oF-5.d.cts +213 -0
- package/dist/index-Dan5oF-5.d.ts +213 -0
- package/dist/index-XABfrs7z.d.cts +596 -0
- package/dist/index-XABfrs7z.d.ts +596 -0
- package/dist/index-YXWfKCK7.d.cts +109 -0
- package/dist/index-YXWfKCK7.d.ts +109 -0
- package/dist/index.cjs +3691 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +3629 -0
- package/dist/index.js.map +1 -0
- package/dist/map.cjs +839 -0
- package/dist/map.cjs.map +1 -0
- package/dist/map.d.cts +6 -0
- package/dist/map.d.ts +6 -0
- package/dist/map.js +811 -0
- package/dist/map.js.map +1 -0
- package/dist/object.cjs +316 -0
- package/dist/object.cjs.map +1 -0
- package/dist/object.d.cts +2 -0
- package/dist/object.d.ts +2 -0
- package/dist/object.js +247 -0
- package/dist/object.js.map +1 -0
- package/dist/pdf.cjs +197 -0
- package/dist/pdf.cjs.map +1 -0
- package/dist/pdf.d.cts +3 -0
- package/dist/pdf.d.ts +3 -0
- package/dist/pdf.js +173 -0
- package/dist/pdf.js.map +1 -0
- package/dist/storage.cjs +255 -0
- package/dist/storage.cjs.map +1 -0
- package/dist/storage.d.cts +1 -0
- package/dist/storage.d.ts +1 -0
- package/dist/storage.js +226 -0
- package/dist/storage.js.map +1 -0
- package/dist/string.cjs +232 -0
- package/dist/string.cjs.map +1 -0
- package/dist/string.d.cts +2 -0
- package/dist/string.d.ts +2 -0
- package/dist/string.js +170 -0
- package/dist/string.js.map +1 -0
- package/dist/utils.cjs +429 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +2 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +371 -0
- package/dist/utils.js.map +1 -0
- package/dist/websocket.cjs +338 -0
- package/dist/websocket.cjs.map +1 -0
- package/dist/websocket.d.cts +1 -0
- package/dist/websocket.d.ts +1 -0
- package/dist/websocket.js +330 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +159 -33
- package/dist/ly-utils-lib.cjs.js +0 -115
- package/dist/ly-utils-lib.cjs.js.map +0 -1
- package/dist/ly-utils-lib.es.js +0 -58589
- package/dist/ly-utils-lib.es.js.map +0 -1
- package/dist/ly-utils-lib.umd.js +0 -115
- package/dist/ly-utils-lib.umd.js.map +0 -1
- package/dist/types/index.d.ts +0 -15
- package/dist/types/utils/esToolkit.d.ts +0 -2
- package/dist/types/utils/ol.d.ts +0 -175
- package/dist/types/utils/router.d.ts +0 -10
- package/dist/types/utils/storage.d.ts +0 -42
- package/dist/types/utils/time.d.ts +0 -66
- package/dist/types/utils/tool.d.ts +0 -80
- package/dist/vite.svg +0 -1
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
// src/modules/websocket/index.ts
|
|
6
|
+
var WebSocketState = /* @__PURE__ */ ((WebSocketState2) => {
|
|
7
|
+
WebSocketState2[WebSocketState2["CONNECTING"] = 0] = "CONNECTING";
|
|
8
|
+
WebSocketState2[WebSocketState2["OPEN"] = 1] = "OPEN";
|
|
9
|
+
WebSocketState2[WebSocketState2["CLOSING"] = 2] = "CLOSING";
|
|
10
|
+
WebSocketState2[WebSocketState2["CLOSED"] = 3] = "CLOSED";
|
|
11
|
+
return WebSocketState2;
|
|
12
|
+
})(WebSocketState || {});
|
|
13
|
+
var WebSocketClient = class {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.ws = null;
|
|
16
|
+
this.handlers = {};
|
|
17
|
+
this.reconnectTimer = null;
|
|
18
|
+
this.heartbeatTimer = null;
|
|
19
|
+
this.heartbeatTimeoutTimer = null;
|
|
20
|
+
this.reconnectCount = 0;
|
|
21
|
+
this.isManualDisconnect = false;
|
|
22
|
+
this.messageQueue = [];
|
|
23
|
+
this.connectResolve = null;
|
|
24
|
+
this.connectReject = null;
|
|
25
|
+
this.options = {
|
|
26
|
+
url: options.url,
|
|
27
|
+
protocol: options.protocol || (options.url.startsWith("https") ? "wss" : "ws"),
|
|
28
|
+
protocols: options.protocols || [],
|
|
29
|
+
autoReconnect: options.autoReconnect ?? true,
|
|
30
|
+
reconnectAttempts: options.reconnectAttempts ?? 3,
|
|
31
|
+
reconnectInterval: options.reconnectInterval ?? 3e3,
|
|
32
|
+
heartbeatInterval: options.heartbeatInterval ?? 3e4,
|
|
33
|
+
heartbeatMessage: options.heartbeatMessage ?? "ping",
|
|
34
|
+
heartbeatTimeout: options.heartbeatTimeout ?? 5e3,
|
|
35
|
+
connectTimeout: options.connectTimeout ?? 1e4,
|
|
36
|
+
debug: options.debug ?? true
|
|
37
|
+
};
|
|
38
|
+
if (options.autoReconnect !== false) {
|
|
39
|
+
this.connect();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 连接 WebSocket
|
|
44
|
+
*/
|
|
45
|
+
connect() {
|
|
46
|
+
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
|
|
47
|
+
this.log("WebSocket already connected or connecting");
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.isManualDisconnect = false;
|
|
51
|
+
this.reconnectCount = 0;
|
|
52
|
+
const protocol = this.options.url.startsWith("ws://") || this.options.url.startsWith("wss://") ? "" : `${this.options.protocol}://`;
|
|
53
|
+
const wsUrl = protocol ? `${protocol}${this.options.url}` : this.options.url;
|
|
54
|
+
this.log(`Connecting to ${wsUrl}`);
|
|
55
|
+
try {
|
|
56
|
+
this.ws = new WebSocket(wsUrl, this.options.protocols);
|
|
57
|
+
this.setupEventHandlers();
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
if (this.ws && this.ws.readyState === WebSocket.CONNECTING) {
|
|
60
|
+
this.ws.close();
|
|
61
|
+
this.log("Connection timeout");
|
|
62
|
+
if (this.connectReject) {
|
|
63
|
+
this.connectReject(new Error("Connection timeout"));
|
|
64
|
+
this.connectResolve = null;
|
|
65
|
+
this.connectReject = null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}, this.options.connectTimeout);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
this.log("Connection failed:", error);
|
|
71
|
+
this.handleError(error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 断开连接
|
|
76
|
+
*/
|
|
77
|
+
disconnect() {
|
|
78
|
+
this.isManualDisconnect = true;
|
|
79
|
+
this.cleanup();
|
|
80
|
+
if (this.ws) {
|
|
81
|
+
this.ws.close();
|
|
82
|
+
this.ws = null;
|
|
83
|
+
}
|
|
84
|
+
this.log("Disconnected manually");
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 发送消息(异步)
|
|
88
|
+
*/
|
|
89
|
+
async send(data) {
|
|
90
|
+
if (!this.isConnected()) {
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
this.messageQueue.push(data);
|
|
93
|
+
const checkConnection = () => {
|
|
94
|
+
if (this.isConnected()) {
|
|
95
|
+
this.sendSync(data);
|
|
96
|
+
resolve();
|
|
97
|
+
} else if (!this.ws) {
|
|
98
|
+
reject(new Error("WebSocket is not connected"));
|
|
99
|
+
} else {
|
|
100
|
+
setTimeout(checkConnection, 100);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
checkConnection();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
this.sendSync(data);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 发送消息(同步)
|
|
110
|
+
*/
|
|
111
|
+
sendSync(data) {
|
|
112
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
113
|
+
this.log("WebSocket is not connected, message queued");
|
|
114
|
+
this.messageQueue.push(data);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const message = typeof data === "object" ? JSON.stringify(data) : data;
|
|
119
|
+
this.ws.send(message);
|
|
120
|
+
this.log("Message sent:", message);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
this.log("Send error:", error);
|
|
123
|
+
this.handleError(error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 获取连接状态
|
|
128
|
+
*/
|
|
129
|
+
getState() {
|
|
130
|
+
return this.ws?.readyState ?? 3 /* CLOSED */;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 是否已连接
|
|
134
|
+
*/
|
|
135
|
+
isConnected() {
|
|
136
|
+
return this.ws?.readyState === WebSocket.OPEN;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 获取 WebSocket 实例
|
|
140
|
+
*/
|
|
141
|
+
getInstance() {
|
|
142
|
+
return this.ws;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 设置事件处理器
|
|
146
|
+
*/
|
|
147
|
+
on(event, handler) {
|
|
148
|
+
this.handlers[event] = handler;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 移除事件处理器
|
|
152
|
+
*/
|
|
153
|
+
off(event, handler) {
|
|
154
|
+
if (!handler || this.handlers[event] === handler) {
|
|
155
|
+
delete this.handlers[event];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 重新连接
|
|
160
|
+
*/
|
|
161
|
+
reconnect() {
|
|
162
|
+
this.disconnect();
|
|
163
|
+
this.reconnectCount = 0;
|
|
164
|
+
this.isManualDisconnect = false;
|
|
165
|
+
this.connect();
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 设置事件处理器
|
|
169
|
+
*/
|
|
170
|
+
setupEventHandlers() {
|
|
171
|
+
if (!this.ws) return;
|
|
172
|
+
this.ws.onopen = (event) => {
|
|
173
|
+
this.log("Connected");
|
|
174
|
+
this.reconnectCount = 0;
|
|
175
|
+
while (this.messageQueue.length > 0) {
|
|
176
|
+
const message = this.messageQueue.shift();
|
|
177
|
+
if (message) {
|
|
178
|
+
this.sendSync(message);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
this.startHeartbeat();
|
|
182
|
+
if (this.handlers.onOpen) {
|
|
183
|
+
this.handlers.onOpen(event);
|
|
184
|
+
}
|
|
185
|
+
if (this.connectResolve) {
|
|
186
|
+
this.connectResolve();
|
|
187
|
+
this.connectResolve = null;
|
|
188
|
+
this.connectReject = null;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
this.ws.onmessage = (event) => {
|
|
192
|
+
this.log("Message received:", event.data);
|
|
193
|
+
let data = event.data;
|
|
194
|
+
if (typeof event.data === "string") {
|
|
195
|
+
try {
|
|
196
|
+
data = JSON.parse(event.data);
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (this.handlers.onMessage) {
|
|
201
|
+
this.handlers.onMessage(data, event);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
this.ws.onclose = (event) => {
|
|
205
|
+
this.log("Connection closed:", event.code, event.reason);
|
|
206
|
+
this.cleanup();
|
|
207
|
+
if (this.handlers.onClose) {
|
|
208
|
+
this.handlers.onClose(event);
|
|
209
|
+
}
|
|
210
|
+
if (!this.isManualDisconnect && this.options.autoReconnect) {
|
|
211
|
+
this.attemptReconnect();
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
this.ws.onerror = (event) => {
|
|
215
|
+
this.log("Error:", event);
|
|
216
|
+
if (this.handlers.onError) {
|
|
217
|
+
this.handlers.onError(event);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 尝试重连
|
|
223
|
+
*/
|
|
224
|
+
attemptReconnect() {
|
|
225
|
+
if (this.reconnectCount >= this.options.reconnectAttempts) {
|
|
226
|
+
this.log("Reconnect failed, max attempts reached");
|
|
227
|
+
this.cleanup();
|
|
228
|
+
if (this.handlers.onReconnectFailed) {
|
|
229
|
+
this.handlers.onReconnectFailed();
|
|
230
|
+
}
|
|
231
|
+
if (this.connectReject) {
|
|
232
|
+
this.connectReject(new Error("Reconnect failed"));
|
|
233
|
+
this.connectResolve = null;
|
|
234
|
+
this.connectReject = null;
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
this.reconnectCount++;
|
|
239
|
+
this.log(`Reconnecting... Attempt ${this.reconnectCount}/${this.options.reconnectAttempts}`);
|
|
240
|
+
if (this.handlers.onReconnect) {
|
|
241
|
+
this.handlers.onReconnect(this.reconnectCount);
|
|
242
|
+
}
|
|
243
|
+
this.reconnectTimer = setTimeout(() => {
|
|
244
|
+
this.connect();
|
|
245
|
+
}, this.options.reconnectInterval);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* 启动心跳
|
|
249
|
+
*/
|
|
250
|
+
startHeartbeat() {
|
|
251
|
+
this.stopHeartbeat();
|
|
252
|
+
this.heartbeatTimer = setInterval(() => {
|
|
253
|
+
if (this.isConnected()) {
|
|
254
|
+
const message = this.options.heartbeatMessage;
|
|
255
|
+
this.log("Sending heartbeat");
|
|
256
|
+
if (this.handlers.onHeartbeat) {
|
|
257
|
+
this.handlers.onHeartbeat();
|
|
258
|
+
}
|
|
259
|
+
this.sendSync(message);
|
|
260
|
+
this.heartbeatTimeoutTimer = setTimeout(() => {
|
|
261
|
+
this.log("Heartbeat timeout");
|
|
262
|
+
if (this.handlers.onHeartbeatTimeout) {
|
|
263
|
+
this.handlers.onHeartbeatTimeout();
|
|
264
|
+
}
|
|
265
|
+
if (this.ws) {
|
|
266
|
+
this.ws.close();
|
|
267
|
+
}
|
|
268
|
+
}, this.options.heartbeatTimeout);
|
|
269
|
+
}
|
|
270
|
+
}, this.options.heartbeatInterval);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* 停止心跳
|
|
274
|
+
*/
|
|
275
|
+
stopHeartbeat() {
|
|
276
|
+
if (this.heartbeatTimer) {
|
|
277
|
+
clearInterval(this.heartbeatTimer);
|
|
278
|
+
this.heartbeatTimer = null;
|
|
279
|
+
}
|
|
280
|
+
if (this.heartbeatTimeoutTimer) {
|
|
281
|
+
clearTimeout(this.heartbeatTimeoutTimer);
|
|
282
|
+
this.heartbeatTimeoutTimer = null;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* 清理资源
|
|
287
|
+
*/
|
|
288
|
+
cleanup() {
|
|
289
|
+
this.stopHeartbeat();
|
|
290
|
+
if (this.reconnectTimer) {
|
|
291
|
+
clearTimeout(this.reconnectTimer);
|
|
292
|
+
this.reconnectTimer = null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* 处理错误
|
|
297
|
+
*/
|
|
298
|
+
handleError(error) {
|
|
299
|
+
this.log("Error:", error.message);
|
|
300
|
+
if (this.handlers.onError) {
|
|
301
|
+
this.handlers.onError(new ErrorEvent("error", { error }));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* 日志输出
|
|
306
|
+
*/
|
|
307
|
+
log(...args) {
|
|
308
|
+
if (this.options.debug) {
|
|
309
|
+
console.log("[WebSocket]", ...args);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
function createWebSocket(options) {
|
|
314
|
+
return new WebSocketClient(options);
|
|
315
|
+
}
|
|
316
|
+
function quickConnect(url, handlers) {
|
|
317
|
+
const client = new WebSocketClient({ url, autoReconnect: true });
|
|
318
|
+
if (handlers) {
|
|
319
|
+
Object.entries(handlers).forEach(([event, handler]) => {
|
|
320
|
+
client.on(event, handler);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
return client;
|
|
324
|
+
}
|
|
325
|
+
var websocket_default = {
|
|
326
|
+
WebSocketClient,
|
|
327
|
+
createWebSocket,
|
|
328
|
+
quickConnect,
|
|
329
|
+
WebSocketState
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
exports.WebSocketClient = WebSocketClient;
|
|
333
|
+
exports.WebSocketState = WebSocketState;
|
|
334
|
+
exports.createWebSocket = createWebSocket;
|
|
335
|
+
exports.default = websocket_default;
|
|
336
|
+
exports.quickConnect = quickConnect;
|
|
337
|
+
//# sourceMappingURL=websocket.cjs.map
|
|
338
|
+
//# sourceMappingURL=websocket.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/modules/websocket/index.ts"],"names":["WebSocketState"],"mappings":"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","file":"websocket.cjs","sourcesContent":["/**\n * WebSocket Module - WebSocket 工具\n *\n * 提供简化的 WebSocket 连接、消息发送、心跳检测和重连机制\n */\n\n// ==================== 类型定义 ====================\n\n/**\n * WebSocket 连接状态\n */\nexport enum WebSocketState {\n CONNECTING = 0,\n OPEN = 1,\n CLOSING = 2,\n CLOSED = 3,\n}\n\n/**\n * WebSocket 配置选项\n */\nexport interface WebSocketOptions {\n /** WebSocket 服务器地址 */\n url: string\n /** 协议(wss:// 或 ws://),默认自动检测 */\n protocol?: 'ws' | 'wss'\n /** 子协议 */\n protocols?: string | string[]\n /** 是否自动重连,默认 true */\n autoReconnect?: boolean\n /** 重连次数,默认 3 */\n reconnectAttempts?: number\n /** 重连间隔(毫秒),默认 3000 */\n reconnectInterval?: number\n /** 心跳检测间隔(毫秒),默认 30000 */\n heartbeatInterval?: number\n /** 心跳消息内容,默认 'ping' */\n heartbeatMessage?: string | object\n /** 心跳超时时间(毫秒),默认 5000 */\n heartbeatTimeout?: number\n /** 连接超时时间(毫秒),默认 10000 */\n connectTimeout?: number\n /** 是否记录日志,默认 true */\n debug?: boolean\n}\n\n/**\n * WebSocket 消息类型\n */\nexport type WebSocketMessage = string | object | ArrayBuffer | Blob\n\n/**\n * WebSocket 事件处理器\n */\nexport interface WebSocketEventHandlers {\n /** 连接成功回调 */\n onOpen?: (event: Event) => void\n /** 接收消息回调 */\n onMessage?: (data: WebSocketMessage, event: MessageEvent) => void\n /** 连接关闭回调 */\n onClose?: (event: CloseEvent) => void\n /** 错误回调 */\n onError?: (event: Event) => void\n /** 重连开始回调 */\n onReconnect?: (attempt: number) => void\n /** 重连成功回调 */\n onReconnectSuccess?: (attempt: number) => void\n /** 重连失败回调 */\n onReconnectFailed?: () => void\n /** 心跳回调 */\n onHeartbeat?: () => void\n /** 心跳超时回调 */\n onHeartbeatTimeout?: () => void\n}\n\n/**\n * WebSocket 实例接口\n */\nexport interface IWebSocketClient {\n /** 连接 WebSocket */\n connect(): void\n /** 断开连接 */\n disconnect(): void\n /** 发送消息 */\n send(data: WebSocketMessage): Promise<void>\n /** 发送消息(不带 Promise) */\n sendSync(data: WebSocketMessage): void\n /** 获取连接状态 */\n getState(): WebSocketState\n /** 是否已连接 */\n isConnected(): boolean\n /** 获取 WebSocket 实例 */\n getInstance(): WebSocket | null\n /** 设置事件处理器 */\n on<K extends keyof WebSocketEventHandlers>(\n event: K,\n handler: WebSocketEventHandlers[K]\n ): void\n /** 移除事件处理器 */\n off<K extends keyof WebSocketEventHandlers>(\n event: K,\n handler?: WebSocketEventHandlers[K]\n ): void\n /** 重新连接 */\n reconnect(): void\n}\n\n// ==================== WebSocket 客户端类 ====================\n\n/**\n * WebSocket 客户端类\n */\nexport class WebSocketClient implements IWebSocketClient {\n private ws: WebSocket | null = null\n private options: Required<Omit<WebSocketOptions, 'protocols' | 'debug'>> &\n Pick<WebSocketOptions, 'protocols' | 'debug'>\n private handlers: WebSocketEventHandlers = {}\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private heartbeatTimeoutTimer: ReturnType<typeof setTimeout> | null = null\n private reconnectCount = 0\n private isManualDisconnect = false\n private messageQueue: WebSocketMessage[] = []\n private connectResolve: (() => void) | null = null\n private connectReject: ((error: Error) => void) | null = null\n\n constructor(options: WebSocketOptions) {\n this.options = {\n url: options.url,\n protocol: options.protocol || (options.url.startsWith('https') ? 'wss' : 'ws'),\n protocols: options.protocols || [],\n autoReconnect: options.autoReconnect ?? true,\n reconnectAttempts: options.reconnectAttempts ?? 3,\n reconnectInterval: options.reconnectInterval ?? 3000,\n heartbeatInterval: options.heartbeatInterval ?? 30000,\n heartbeatMessage: options.heartbeatMessage ?? 'ping',\n heartbeatTimeout: options.heartbeatTimeout ?? 5000,\n connectTimeout: options.connectTimeout ?? 10000,\n debug: options.debug ?? true,\n }\n\n // 自动连接\n if (options.autoReconnect !== false) {\n this.connect()\n }\n }\n\n /**\n * 连接 WebSocket\n */\n connect(): void {\n if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {\n this.log('WebSocket already connected or connecting')\n return\n }\n\n this.isManualDisconnect = false\n this.reconnectCount = 0\n\n const protocol = this.options.url.startsWith('ws://') || this.options.url.startsWith('wss://')\n ? ''\n : `${this.options.protocol}://`\n\n const wsUrl = protocol ? `${protocol}${this.options.url}` : this.options.url\n\n this.log(`Connecting to ${wsUrl}`)\n\n try {\n this.ws = new WebSocket(wsUrl, this.options.protocols)\n\n this.setupEventHandlers()\n\n // 设置连接超时\n setTimeout(() => {\n if (this.ws && this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close()\n this.log('Connection timeout')\n if (this.connectReject) {\n this.connectReject(new Error('Connection timeout'))\n this.connectResolve = null\n this.connectReject = null\n }\n }\n }, this.options.connectTimeout)\n } catch (error) {\n this.log('Connection failed:', error)\n this.handleError(error as Error)\n }\n }\n\n /**\n * 断开连接\n */\n disconnect(): void {\n this.isManualDisconnect = true\n this.cleanup()\n\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n\n this.log('Disconnected manually')\n }\n\n /**\n * 发送消息(异步)\n */\n async send(data: WebSocketMessage): Promise<void> {\n if (!this.isConnected()) {\n return new Promise((resolve, reject) => {\n this.messageQueue.push(data)\n const checkConnection = () => {\n if (this.isConnected()) {\n this.sendSync(data)\n resolve()\n } else if (!this.ws) {\n reject(new Error('WebSocket is not connected'))\n } else {\n setTimeout(checkConnection, 100)\n }\n }\n checkConnection()\n })\n }\n\n this.sendSync(data)\n }\n\n /**\n * 发送消息(同步)\n */\n sendSync(data: WebSocketMessage): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n this.log('WebSocket is not connected, message queued')\n this.messageQueue.push(data)\n return\n }\n\n try {\n const message = typeof data === 'object' ? JSON.stringify(data) : data\n this.ws.send(message)\n this.log('Message sent:', message)\n } catch (error) {\n this.log('Send error:', error)\n this.handleError(error as Error)\n }\n }\n\n /**\n * 获取连接状态\n */\n getState(): WebSocketState {\n return this.ws?.readyState ?? WebSocketState.CLOSED\n }\n\n /**\n * 是否已连接\n */\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN\n }\n\n /**\n * 获取 WebSocket 实例\n */\n getInstance(): WebSocket | null {\n return this.ws\n }\n\n /**\n * 设置事件处理器\n */\n on<K extends keyof WebSocketEventHandlers>(\n event: K,\n handler: WebSocketEventHandlers[K]\n ): void {\n this.handlers[event] = handler\n }\n\n /**\n * 移除事件处理器\n */\n off<K extends keyof WebSocketEventHandlers>(\n event: K,\n handler?: WebSocketEventHandlers[K]\n ): void {\n if (!handler || this.handlers[event] === handler) {\n delete this.handlers[event]\n }\n }\n\n /**\n * 重新连接\n */\n reconnect(): void {\n this.disconnect()\n this.reconnectCount = 0\n this.isManualDisconnect = false\n this.connect()\n }\n\n /**\n * 设置事件处理器\n */\n private setupEventHandlers(): void {\n if (!this.ws) return\n\n this.ws.onopen = (event) => {\n this.log('Connected')\n this.reconnectCount = 0\n\n // 发送队列中的消息\n while (this.messageQueue.length > 0) {\n const message = this.messageQueue.shift()\n if (message) {\n this.sendSync(message)\n }\n }\n\n // 启动心跳\n this.startHeartbeat()\n\n // 触发 onOpen 回调\n if (this.handlers.onOpen) {\n this.handlers.onOpen(event)\n }\n\n // 解析连接 Promise\n if (this.connectResolve) {\n this.connectResolve()\n this.connectResolve = null\n this.connectReject = null\n }\n }\n\n this.ws.onmessage = (event) => {\n this.log('Message received:', event.data)\n\n let data: WebSocketMessage = event.data\n\n // 尝试解析 JSON\n if (typeof event.data === 'string') {\n try {\n data = JSON.parse(event.data)\n } catch {\n // 不是 JSON 格式,保持原样\n }\n }\n\n // 触发 onMessage 回调\n if (this.handlers.onMessage) {\n this.handlers.onMessage(data, event)\n }\n }\n\n this.ws.onclose = (event) => {\n this.log('Connection closed:', event.code, event.reason)\n this.cleanup()\n\n // 触发 onClose 回调\n if (this.handlers.onClose) {\n this.handlers.onClose(event)\n }\n\n // 自动重连\n if (!this.isManualDisconnect && this.options.autoReconnect) {\n this.attemptReconnect()\n }\n }\n\n this.ws.onerror = (event) => {\n this.log('Error:', event)\n\n // 触发 onError 回调\n if (this.handlers.onError) {\n this.handlers.onError(event)\n }\n }\n }\n\n /**\n * 尝试重连\n */\n private attemptReconnect(): void {\n if (this.reconnectCount >= this.options.reconnectAttempts) {\n this.log('Reconnect failed, max attempts reached')\n this.cleanup()\n\n // 触发 onReconnectFailed 回调\n if (this.handlers.onReconnectFailed) {\n this.handlers.onReconnectFailed()\n }\n\n if (this.connectReject) {\n this.connectReject(new Error('Reconnect failed'))\n this.connectResolve = null\n this.connectReject = null\n }\n return\n }\n\n this.reconnectCount++\n this.log(`Reconnecting... Attempt ${this.reconnectCount}/${this.options.reconnectAttempts}`)\n\n // 触发 onReconnect 回调\n if (this.handlers.onReconnect) {\n this.handlers.onReconnect(this.reconnectCount)\n }\n\n this.reconnectTimer = setTimeout(() => {\n this.connect()\n }, this.options.reconnectInterval)\n }\n\n /**\n * 启动心跳\n */\n private startHeartbeat(): void {\n this.stopHeartbeat()\n\n this.heartbeatTimer = setInterval(() => {\n if (this.isConnected()) {\n const message = this.options.heartbeatMessage\n this.log('Sending heartbeat')\n\n // 触发 onHeartbeat 回调\n if (this.handlers.onHeartbeat) {\n this.handlers.onHeartbeat()\n }\n\n // 发送心跳消息\n this.sendSync(message)\n\n // 设置心跳超时检测\n this.heartbeatTimeoutTimer = setTimeout(() => {\n this.log('Heartbeat timeout')\n\n // 触发 onHeartbeatTimeout 回调\n if (this.handlers.onHeartbeatTimeout) {\n this.handlers.onHeartbeatTimeout()\n }\n\n // 关闭连接,触发重连\n if (this.ws) {\n this.ws.close()\n }\n }, this.options.heartbeatTimeout)\n }\n }, this.options.heartbeatInterval)\n }\n\n /**\n * 停止心跳\n */\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimeoutTimer = null\n }\n }\n\n /**\n * 清理资源\n */\n private cleanup(): void {\n this.stopHeartbeat()\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n }\n\n /**\n * 处理错误\n */\n private handleError(error: Error): void {\n this.log('Error:', error.message)\n\n // 触发 onError 回调\n if (this.handlers.onError) {\n this.handlers.onError(new ErrorEvent('error', { error }))\n }\n }\n\n /**\n * 日志输出\n */\n private log(...args: unknown[]): void {\n if (this.options.debug) {\n console.log('[WebSocket]', ...args)\n }\n }\n}\n\n// ==================== 工厂函数 ====================\n\n/**\n * 创建 WebSocket 客户端\n * @param options - 配置选项\n * @returns WebSocket 客户端实例\n * @example\n * ```ts\n * const ws = createWebSocket({\n * url: 'echo.websocket.org',\n * autoReconnect: true,\n * onMessage: (data) => console.log('Received:', data)\n * })\n *\n * ws.send('Hello, WebSocket!')\n * ```\n */\nexport function createWebSocket(options: WebSocketOptions): IWebSocketClient {\n return new WebSocketClient(options)\n}\n\n/**\n * 快速连接 WebSocket\n * @param url - WebSocket 服务器地址\n * @param handlers - 事件处理器\n * @returns WebSocket 客户端实例\n * @example\n * ```ts\n * const ws = quickConnect('echo.websocket.org', {\n * onMessage: (data) => console.log('Received:', data)\n * })\n * ```\n */\nexport function quickConnect(\n url: string,\n handlers?: WebSocketEventHandlers\n): IWebSocketClient {\n const client = new WebSocketClient({ url, autoReconnect: true })\n\n if (handlers) {\n Object.entries(handlers).forEach(([event, handler]) => {\n client.on(event as keyof WebSocketEventHandlers, handler)\n })\n }\n\n return client\n}\n\n// ==================== 导出 ====================\n\nexport default {\n WebSocketClient,\n createWebSocket,\n quickConnect,\n WebSocketState,\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { I as IWebSocketClient, W as WebSocketClient, a as WebSocketEventHandlers, b as WebSocketMessage, c as WebSocketOptions, d as WebSocketState, e as createWebSocket, _ as default, q as quickConnect } from './index-Cq1GhjpY.cjs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { I as IWebSocketClient, W as WebSocketClient, a as WebSocketEventHandlers, b as WebSocketMessage, c as WebSocketOptions, d as WebSocketState, e as createWebSocket, _ as default, q as quickConnect } from './index-Cq1GhjpY.js';
|