@0xchain/web-socket 1.1.0-beta.7 → 1.1.0-beta.71

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present 0xchain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.js CHANGED
@@ -1,251 +1,407 @@
1
- import { ConnectionStatus } from './type.js';
2
- /**
3
- * WebSocket单例连接类
4
- * 提供WebSocket连接的创建、管理、重连等功能
5
- */
6
- class SocketConnection {
7
- static instance = null;
8
- socket = null;
9
- config;
10
- status = ConnectionStatus.DISCONNECTED;
11
- reconnectAttempts = 0;
12
- reconnectTimer = null;
13
- heartbeatTimer = null;
14
- eventListeners = {};
15
- constructor(config) {
16
- this.config = {
17
- reconnectInterval: 3000,
18
- maxReconnectAttempts: 5,
19
- heartbeatInterval: 30000,
20
- debug: false,
21
- ...config
22
- };
1
+ import { useState, useRef, useEffect, useCallback } from "react";
2
+ var ConnectionStatus = /* @__PURE__ */ ((ConnectionStatus2) => {
3
+ ConnectionStatus2["CONNECTING"] = "connecting";
4
+ ConnectionStatus2["CONNECTED"] = "connected";
5
+ ConnectionStatus2["DISCONNECTED"] = "disconnected";
6
+ ConnectionStatus2["RECONNECTING"] = "reconnecting";
7
+ ConnectionStatus2["ERROR"] = "error";
8
+ return ConnectionStatus2;
9
+ })(ConnectionStatus || {});
10
+ function useSocket(config) {
11
+ const [status, setStatus] = useState(ConnectionStatus.DISCONNECTED);
12
+ const [error, setError] = useState(null);
13
+ const [reconnectAttempts, setReconnectAttempts] = useState(0);
14
+ const socketRef = useRef(null);
15
+ const isInitializedRef = useRef(false);
16
+ const configRef = useRef(config);
17
+ useEffect(() => {
18
+ configRef.current = config;
19
+ }, [config]);
20
+ const getSocket = useCallback(() => {
21
+ if (!socketRef.current) {
22
+ try {
23
+ socketRef.current = SocketConnection.getInstance(configRef.current);
24
+ } catch (err) {
25
+ console.error("Failed to create socket instance:", err);
26
+ throw err;
27
+ }
23
28
  }
24
- /**
25
- * 获取单例实例
26
- */
27
- static getInstance(config) {
28
- if (!SocketConnection.instance) {
29
- if (!config) {
30
- throw new Error('首次创建SocketConnection实例时必须提供配置');
31
- }
32
- SocketConnection.instance = new SocketConnection(config);
33
- }
34
- else if (config) {
35
- if (JSON.stringify(SocketConnection.instance.config) !== JSON.stringify(config)) {
36
- SocketConnection.instance = new SocketConnection(config);
37
- }
38
- if (config) {
39
- SocketConnection.instance.config = {
40
- ...SocketConnection.instance.config,
41
- ...config
42
- };
43
- }
44
- }
45
- return SocketConnection.instance;
46
- }
47
- /**
48
- * 连接WebSocket
49
- */
50
- connect(config) {
51
- this.config = {
52
- ...this.config,
53
- ...config
54
- };
55
- return new Promise((resolve, reject) => {
56
- if (this.socket?.readyState === WebSocket.OPEN) {
57
- resolve();
58
- return;
59
- }
60
- const url = this.config.url + (this.config?.params ? `?${Object.entries(this.config.params).map(([key, value]) => `${key}=${value}`).join('&')}` : '');
61
- if (url) {
62
- this.setStatus(ConnectionStatus.CONNECTING);
63
- this.log('正在连接WebSocket...', url);
64
- try {
65
- this.socket = new WebSocket(url, this.config.protocols);
66
- this.setupEventListeners();
67
- this.socket.onopen = () => {
68
- this.log('WebSocket连接成功');
69
- this.setStatus(ConnectionStatus.CONNECTED);
70
- this.reconnectAttempts = 0;
71
- this.startHeartbeat();
72
- this.eventListeners.open?.();
73
- resolve();
74
- };
75
- this.socket.onerror = (error) => {
76
- this.log('WebSocket连接错误:', error);
77
- this.setStatus(ConnectionStatus.ERROR);
78
- this.eventListeners.error?.(error);
79
- reject(error);
80
- };
81
- }
82
- catch (error) {
83
- this.log('创建WebSocket连接失败:', error);
84
- this.setStatus(ConnectionStatus.ERROR);
85
- reject(error);
86
- }
87
- }
88
- });
89
- }
90
- /**
91
- * 断开连接
92
- */
93
- disconnect() {
94
- this.log('正在断开WebSocket连接...');
95
- this.stopHeartbeat();
96
- this.clearReconnectTimer();
97
- if (this.socket) {
98
- this.socket.close(1000, '主动断开连接');
99
- this.socket = null;
100
- }
101
- this.setStatus(ConnectionStatus.DISCONNECTED);
102
- }
103
- /**
104
- * 发送消息
105
- */
106
- send(data) {
107
- if (this.socket?.readyState === WebSocket.OPEN) {
108
- this.socket.send(data);
109
- this.log('发送消息:', data);
110
- return true;
111
- }
112
- else {
113
- this.log('WebSocket未连接,无法发送消息');
114
- return false;
29
+ return socketRef.current;
30
+ }, []);
31
+ const connect = useCallback(async () => {
32
+ try {
33
+ setError(null);
34
+ const socket = getSocket();
35
+ await socket.connect();
36
+ } catch (err) {
37
+ const errorEvent = err;
38
+ setError(errorEvent);
39
+ throw err;
40
+ }
41
+ }, [getSocket]);
42
+ const disconnect = useCallback(() => {
43
+ const socket = socketRef.current;
44
+ if (socket) {
45
+ socket.disconnect();
46
+ }
47
+ }, []);
48
+ const send = useCallback((data) => {
49
+ const socket = socketRef.current;
50
+ if (socket) {
51
+ return socket.send(data);
52
+ }
53
+ return false;
54
+ }, []);
55
+ const sendJSON = useCallback((data) => {
56
+ const socket = socketRef.current;
57
+ if (socket) {
58
+ return socket.sendJSON(data);
59
+ }
60
+ return false;
61
+ }, []);
62
+ const on = useCallback((event, listener) => {
63
+ const socket = socketRef.current;
64
+ if (socket) {
65
+ socket.on(event, listener);
66
+ }
67
+ }, []);
68
+ const off = useCallback((event) => {
69
+ const socket = socketRef.current;
70
+ if (socket) {
71
+ socket.off(event);
72
+ }
73
+ }, []);
74
+ const reconnect = useCallback(async () => {
75
+ disconnect();
76
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
77
+ await connect();
78
+ }, [disconnect, connect]);
79
+ useEffect(() => {
80
+ if (isInitializedRef.current) return;
81
+ try {
82
+ const socket = getSocket();
83
+ socket.on("statusChange", (newStatus) => {
84
+ setStatus(newStatus);
85
+ if (newStatus === ConnectionStatus.RECONNECTING) {
86
+ setReconnectAttempts((prev) => prev + 1);
87
+ } else if (newStatus === ConnectionStatus.CONNECTED) {
88
+ setReconnectAttempts(0);
115
89
  }
90
+ });
91
+ socket.on("error", (errorEvent) => {
92
+ setError(errorEvent);
93
+ });
94
+ socket.on("close", () => {
95
+ setError(null);
96
+ });
97
+ isInitializedRef.current = true;
98
+ } catch (err) {
99
+ console.error("Failed to initialize socket:", err);
100
+ setError(err);
116
101
  }
117
- /**
118
- * 发送JSON消息
119
- */
120
- sendJSON(data) {
121
- return this.send(JSON.stringify(data));
122
- }
123
- /**
124
- * 添加事件监听器
125
- */
126
- on(event, listener) {
127
- this.eventListeners[event] = listener;
128
- }
129
- /**
130
- * 移除事件监听器
131
- */
132
- off(event) {
133
- delete this.eventListeners[event];
134
- }
135
- /**
136
- * 获取连接状态
137
- */
138
- getStatus() {
139
- return this.status;
140
- }
141
- /**
142
- * 检查是否已连接
143
- */
144
- isConnected() {
145
- return this.status === ConnectionStatus.CONNECTED && this.socket?.readyState === WebSocket.OPEN;
146
- }
147
- /**
148
- * 设置事件监听器
149
- */
150
- setupEventListeners() {
151
- if (!this.socket)
152
- return;
153
- this.socket.onmessage = (event) => {
154
- this.log('收到消息:', event.data);
155
- if (event.data !== 'pong') {
156
- this.eventListeners.message?.(event.data);
157
- }
158
- };
159
- this.socket.onclose = (event) => {
160
- this.log('WebSocket连接关闭:', event.code, event.reason);
161
- this.setStatus(ConnectionStatus.DISCONNECTED);
162
- this.stopHeartbeat();
163
- this.eventListeners.close?.(event);
164
- // 如果不是主动断开,尝试重连
165
- if (event.code !== 1000 && this.reconnectAttempts < (this.config.maxReconnectAttempts || 5)) {
166
- this.scheduleReconnect();
167
- }
102
+ }, [getSocket]);
103
+ useEffect(() => {
104
+ if (config.autoConnect !== false && !isInitializedRef.current) {
105
+ connect().catch(console.error);
106
+ }
107
+ }, [config.autoConnect, connect]);
108
+ useEffect(() => {
109
+ return () => {
110
+ const socket = socketRef.current;
111
+ if (socket && config.autoConnect !== false) {
112
+ socket.disconnect();
113
+ }
114
+ };
115
+ }, [config.autoConnect]);
116
+ const isConnected = status === ConnectionStatus.CONNECTED;
117
+ return {
118
+ status,
119
+ isConnected,
120
+ connect,
121
+ disconnect,
122
+ send,
123
+ sendJSON,
124
+ on,
125
+ off,
126
+ error,
127
+ reconnectAttempts,
128
+ reconnect
129
+ };
130
+ }
131
+ function useSocketMessage(config, messageHandler) {
132
+ const socket = useSocket(config);
133
+ useEffect(() => {
134
+ socket.on("message", (data) => {
135
+ try {
136
+ const parsedData = typeof data === "string" ? JSON.parse(data) : data;
137
+ messageHandler(parsedData);
138
+ } catch (err) {
139
+ console.error("Failed to parse message:", err);
140
+ }
141
+ });
142
+ return () => {
143
+ socket.off("message");
144
+ };
145
+ }, [socket, messageHandler]);
146
+ return socket;
147
+ }
148
+ function useSocketStatus(config) {
149
+ const [status, setStatus] = useState(ConnectionStatus.DISCONNECTED);
150
+ const socket = useSocket(config);
151
+ useEffect(() => {
152
+ socket.on("statusChange", setStatus);
153
+ return () => {
154
+ socket.off("statusChange");
155
+ };
156
+ }, [socket]);
157
+ return {
158
+ status,
159
+ isConnected: status === ConnectionStatus.CONNECTED,
160
+ isConnecting: status === ConnectionStatus.CONNECTING,
161
+ isReconnecting: status === ConnectionStatus.RECONNECTING,
162
+ isDisconnected: status === ConnectionStatus.DISCONNECTED,
163
+ hasError: status === ConnectionStatus.ERROR
164
+ };
165
+ }
166
+ class SocketConnection {
167
+ static instance = null;
168
+ socket = null;
169
+ config;
170
+ status = ConnectionStatus.DISCONNECTED;
171
+ reconnectAttempts = 0;
172
+ reconnectTimer = null;
173
+ heartbeatTimer = null;
174
+ eventListeners = {};
175
+ constructor(config) {
176
+ this.config = {
177
+ reconnectInterval: 3e3,
178
+ maxReconnectAttempts: 5,
179
+ heartbeatInterval: 3e4,
180
+ debug: false,
181
+ ...config
182
+ };
183
+ }
184
+ /**
185
+ * 获取单例实例
186
+ */
187
+ static getInstance(config) {
188
+ if (!SocketConnection.instance) {
189
+ if (!config) {
190
+ throw new Error("首次创建SocketConnection实例时必须提供配置");
191
+ }
192
+ SocketConnection.instance = new SocketConnection(config);
193
+ } else if (config) {
194
+ if (JSON.stringify(SocketConnection.instance.config) !== JSON.stringify(config)) {
195
+ SocketConnection.instance = new SocketConnection(config);
196
+ }
197
+ if (config) {
198
+ SocketConnection.instance.config = {
199
+ ...SocketConnection.instance.config,
200
+ ...config
168
201
  };
169
- this.socket.onerror = (error) => {
170
- this.log('WebSocket错误:', error);
202
+ }
203
+ }
204
+ return SocketConnection.instance;
205
+ }
206
+ /**
207
+ * 连接WebSocket
208
+ */
209
+ connect(config) {
210
+ this.config = {
211
+ ...this.config,
212
+ ...config
213
+ };
214
+ return new Promise((resolve, reject) => {
215
+ if (this.socket?.readyState === WebSocket.OPEN) {
216
+ resolve();
217
+ return;
218
+ }
219
+ const url = this.config.url + (this.config?.params ? `?${Object.entries(this.config.params).map(([key, value]) => `${key}=${value}`).join("&")}` : "");
220
+ if (url) {
221
+ this.setStatus(ConnectionStatus.CONNECTING);
222
+ this.log("正在连接WebSocket...", url);
223
+ try {
224
+ this.socket = new WebSocket(url, this.config.protocols);
225
+ this.setupEventListeners();
226
+ this.socket.onopen = () => {
227
+ this.log("WebSocket连接成功");
228
+ this.setStatus(ConnectionStatus.CONNECTED);
229
+ this.reconnectAttempts = 0;
230
+ this.startHeartbeat();
231
+ this.eventListeners.open?.();
232
+ resolve();
233
+ };
234
+ this.socket.onerror = (error) => {
235
+ this.log("WebSocket连接错误:", error);
171
236
  this.setStatus(ConnectionStatus.ERROR);
172
237
  this.eventListeners.error?.(error);
173
- };
174
- }
175
- /**
176
- * 设置连接状态
177
- */
178
- setStatus(status) {
179
- if (this.status !== status) {
180
- this.status = status;
181
- this.log('连接状态变更:', status);
182
- this.eventListeners.statusChange?.(status);
238
+ reject(error);
239
+ };
240
+ } catch (error) {
241
+ this.log("创建WebSocket连接失败:", error);
242
+ this.setStatus(ConnectionStatus.ERROR);
243
+ reject(error);
183
244
  }
245
+ }
246
+ });
247
+ }
248
+ /**
249
+ * 断开连接
250
+ */
251
+ disconnect() {
252
+ this.log("正在断开WebSocket连接...");
253
+ this.stopHeartbeat();
254
+ this.clearReconnectTimer();
255
+ if (this.socket) {
256
+ this.socket.close(1e3, "主动断开连接");
257
+ this.socket = null;
184
258
  }
185
- /**
186
- * 安排重连
187
- */
188
- scheduleReconnect() {
189
- if (this.reconnectTimer)
190
- return;
191
- this.reconnectAttempts++;
192
- this.setStatus(ConnectionStatus.RECONNECTING);
193
- this.log(`准备重连 (第${this.reconnectAttempts}次)...`);
194
- this.reconnectTimer = setTimeout(() => {
195
- this.reconnectTimer = null;
196
- this.connect().catch(() => {
197
- // 重连失败,继续尝试
198
- });
199
- }, this.config.reconnectInterval || 3000);
200
- }
201
- /**
202
- * 清除重连定时器
203
- */
204
- clearReconnectTimer() {
205
- if (this.reconnectTimer) {
206
- clearTimeout(this.reconnectTimer);
207
- this.reconnectTimer = null;
208
- }
259
+ this.setStatus(ConnectionStatus.DISCONNECTED);
260
+ }
261
+ /**
262
+ * 发送消息
263
+ */
264
+ send(data) {
265
+ if (this.socket?.readyState === WebSocket.OPEN) {
266
+ this.socket.send(data);
267
+ this.log("发送消息:", data);
268
+ return true;
269
+ } else {
270
+ this.log("WebSocket未连接,无法发送消息");
271
+ return false;
209
272
  }
210
- /**
211
- * 开始心跳检测
212
- */
213
- startHeartbeat() {
214
- this.stopHeartbeat();
215
- if (this.config.heartbeatInterval && this.config.heartbeatInterval > 0) {
216
- this.heartbeatTimer = setInterval(() => {
217
- if (this.isConnected()) {
218
- this.send('ping');
219
- }
220
- }, this.config.heartbeatInterval);
221
- }
273
+ }
274
+ /**
275
+ * 发送JSON消息
276
+ */
277
+ sendJSON(data) {
278
+ return this.send(JSON.stringify(data));
279
+ }
280
+ /**
281
+ * 添加事件监听器
282
+ */
283
+ on(event, listener) {
284
+ this.eventListeners[event] = listener;
285
+ }
286
+ /**
287
+ * 移除事件监听器
288
+ */
289
+ off(event) {
290
+ delete this.eventListeners[event];
291
+ }
292
+ /**
293
+ * 获取连接状态
294
+ */
295
+ getStatus() {
296
+ return this.status;
297
+ }
298
+ /**
299
+ * 检查是否已连接
300
+ */
301
+ isConnected() {
302
+ return this.status === ConnectionStatus.CONNECTED && this.socket?.readyState === WebSocket.OPEN;
303
+ }
304
+ /**
305
+ * 设置事件监听器
306
+ */
307
+ setupEventListeners() {
308
+ if (!this.socket) return;
309
+ this.socket.onmessage = (event) => {
310
+ this.log("收到消息:", event.data);
311
+ if (event.data !== "pong") {
312
+ this.eventListeners.message?.(event.data);
313
+ }
314
+ };
315
+ this.socket.onclose = (event) => {
316
+ this.log("WebSocket连接关闭:", event.code, event.reason);
317
+ this.setStatus(ConnectionStatus.DISCONNECTED);
318
+ this.stopHeartbeat();
319
+ this.eventListeners.close?.(event);
320
+ if (event.code !== 1e3 && this.reconnectAttempts < (this.config.maxReconnectAttempts || 5)) {
321
+ this.scheduleReconnect();
322
+ }
323
+ };
324
+ this.socket.onerror = (error) => {
325
+ this.log("WebSocket错误:", error);
326
+ this.setStatus(ConnectionStatus.ERROR);
327
+ this.eventListeners.error?.(error);
328
+ };
329
+ }
330
+ /**
331
+ * 设置连接状态
332
+ */
333
+ setStatus(status) {
334
+ if (this.status !== status) {
335
+ this.status = status;
336
+ this.log("连接状态变更:", status);
337
+ this.eventListeners.statusChange?.(status);
222
338
  }
223
- /**
224
- * 停止心跳检测
225
- */
226
- stopHeartbeat() {
227
- if (this.heartbeatTimer) {
228
- clearInterval(this.heartbeatTimer);
229
- this.heartbeatTimer = null;
230
- }
339
+ }
340
+ /**
341
+ * 安排重连
342
+ */
343
+ scheduleReconnect() {
344
+ if (this.reconnectTimer) return;
345
+ this.reconnectAttempts++;
346
+ this.setStatus(ConnectionStatus.RECONNECTING);
347
+ this.log(`准备重连 (第${this.reconnectAttempts}次)...`);
348
+ this.reconnectTimer = setTimeout(() => {
349
+ this.reconnectTimer = null;
350
+ this.connect().catch(() => {
351
+ });
352
+ }, this.config.reconnectInterval || 3e3);
353
+ }
354
+ /**
355
+ * 清除重连定时器
356
+ */
357
+ clearReconnectTimer() {
358
+ if (this.reconnectTimer) {
359
+ clearTimeout(this.reconnectTimer);
360
+ this.reconnectTimer = null;
231
361
  }
232
- /**
233
- * 日志输出
234
- */
235
- log(...args) {
236
- if (this.config.debug) {
237
- console.log('[SocketConnection]', ...args);
362
+ }
363
+ /**
364
+ * 开始心跳检测
365
+ */
366
+ startHeartbeat() {
367
+ this.stopHeartbeat();
368
+ if (this.config.heartbeatInterval && this.config.heartbeatInterval > 0) {
369
+ this.heartbeatTimer = setInterval(() => {
370
+ if (this.isConnected()) {
371
+ this.send("ping");
238
372
  }
373
+ }, this.config.heartbeatInterval);
374
+ }
375
+ }
376
+ /**
377
+ * 停止心跳检测
378
+ */
379
+ stopHeartbeat() {
380
+ if (this.heartbeatTimer) {
381
+ clearInterval(this.heartbeatTimer);
382
+ this.heartbeatTimer = null;
239
383
  }
240
- /**
241
- * 销毁实例
242
- */
243
- destroy() {
244
- this.disconnect();
245
- this.eventListeners = {};
246
- SocketConnection.instance = null;
384
+ }
385
+ /**
386
+ * 日志输出
387
+ */
388
+ log(...args) {
389
+ if (this.config.debug) {
390
+ console.log("[SocketConnection]", ...args);
247
391
  }
392
+ }
393
+ /**
394
+ * 销毁实例
395
+ */
396
+ destroy() {
397
+ this.disconnect();
398
+ this.eventListeners = {};
399
+ SocketConnection.instance = null;
400
+ }
248
401
  }
249
- export default SocketConnection;
250
- // 导出React Hooks
251
- export { useSocket, useSocketMessage, useSocketStatus } from './useSocket.js';
402
+ export {
403
+ SocketConnection as default,
404
+ useSocket,
405
+ useSocketMessage,
406
+ useSocketStatus
407
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xchain/web-socket",
3
- "version": "1.1.0-beta.7",
3
+ "version": "1.1.0-beta.71",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -17,10 +17,21 @@
17
17
  "dist",
18
18
  "!**/*.tsbuildinfo"
19
19
  ],
20
- "dependencies": {
20
+ "peerDependencies": {
21
21
  "react": "19.1.1",
22
+ "react-dom": "19.1.1",
22
23
  "tslib": "2.8.1"
23
24
  },
25
+ "devDependencies": {
26
+ "react": "19.1.1",
27
+ "react-dom": "19.1.1",
28
+ "tslib": "2.8.1"
29
+ },
30
+ "nx": {
31
+ "tags": [
32
+ "type:util"
33
+ ]
34
+ },
24
35
  "publishConfig": {
25
36
  "access": "public"
26
37
  }
package/dist/type.js DELETED
@@ -1,19 +0,0 @@
1
- /**
2
- * WebSocket事件类型枚举
3
- */
4
- export var WebSocketEventType;
5
- (function (WebSocketEventType) {
6
- WebSocketEventType["ALL_CHAIN_LATEST_BLOCK"] = "allChainLatestBlock";
7
- WebSocketEventType["CHAIN_LATEST_BLOCK"] = "chainLatestBlock";
8
- })(WebSocketEventType || (WebSocketEventType = {}));
9
- /**
10
- * WebSocket连接状态枚举
11
- */
12
- export var ConnectionStatus;
13
- (function (ConnectionStatus) {
14
- ConnectionStatus["CONNECTING"] = "connecting";
15
- ConnectionStatus["CONNECTED"] = "connected";
16
- ConnectionStatus["DISCONNECTED"] = "disconnected";
17
- ConnectionStatus["RECONNECTING"] = "reconnecting";
18
- ConnectionStatus["ERROR"] = "error";
19
- })(ConnectionStatus || (ConnectionStatus = {}));
package/dist/useSocket.js DELETED
@@ -1,204 +0,0 @@
1
- import { useEffect, useRef, useState, useCallback } from 'react';
2
- import SocketConnection from './index.js';
3
- import { ConnectionStatus } from './type.js';
4
- /**
5
- * useSocket Hook
6
- * 提供在React组件中使用WebSocket连接的便捷方法
7
- *
8
- * @param config WebSocket配置选项
9
- * @returns useSocket的返回值对象
10
- */
11
- export function useSocket(config) {
12
- const [status, setStatus] = useState(ConnectionStatus.DISCONNECTED);
13
- const [error, setError] = useState(null);
14
- const [reconnectAttempts, setReconnectAttempts] = useState(0);
15
- const socketRef = useRef(null);
16
- const isInitializedRef = useRef(false);
17
- const configRef = useRef(config);
18
- // 更新配置引用
19
- useEffect(() => {
20
- configRef.current = config;
21
- }, [config]);
22
- // 获取或创建socket实例
23
- const getSocket = useCallback(() => {
24
- if (!socketRef.current) {
25
- try {
26
- socketRef.current = SocketConnection.getInstance(configRef.current);
27
- }
28
- catch (err) {
29
- console.error('Failed to create socket instance:', err);
30
- throw err;
31
- }
32
- }
33
- return socketRef.current;
34
- }, []);
35
- // 连接WebSocket
36
- const connect = useCallback(async () => {
37
- try {
38
- setError(null);
39
- const socket = getSocket();
40
- await socket.connect();
41
- }
42
- catch (err) {
43
- const errorEvent = err;
44
- setError(errorEvent);
45
- throw err;
46
- }
47
- }, [getSocket]);
48
- // 断开连接
49
- const disconnect = useCallback(() => {
50
- const socket = socketRef.current;
51
- if (socket) {
52
- socket.disconnect();
53
- }
54
- }, []);
55
- // 发送消息
56
- const send = useCallback((data) => {
57
- const socket = socketRef.current;
58
- if (socket) {
59
- return socket.send(data);
60
- }
61
- return false;
62
- }, []);
63
- // 发送JSON消息
64
- const sendJSON = useCallback((data) => {
65
- const socket = socketRef.current;
66
- if (socket) {
67
- return socket.sendJSON(data);
68
- }
69
- return false;
70
- }, []);
71
- // 添加事件监听器
72
- const on = useCallback((event, listener) => {
73
- const socket = socketRef.current;
74
- if (socket) {
75
- socket.on(event, listener);
76
- }
77
- }, []);
78
- // 移除事件监听器
79
- const off = useCallback((event) => {
80
- const socket = socketRef.current;
81
- if (socket) {
82
- socket.off(event);
83
- }
84
- }, []);
85
- // 手动重连
86
- const reconnect = useCallback(async () => {
87
- disconnect();
88
- await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒
89
- await connect();
90
- }, [disconnect, connect]);
91
- // 初始化socket和事件监听
92
- useEffect(() => {
93
- if (isInitializedRef.current)
94
- return;
95
- try {
96
- const socket = getSocket();
97
- // 监听状态变化
98
- socket.on('statusChange', (newStatus) => {
99
- setStatus(newStatus);
100
- // 更新重连次数
101
- if (newStatus === ConnectionStatus.RECONNECTING) {
102
- setReconnectAttempts(prev => prev + 1);
103
- }
104
- else if (newStatus === ConnectionStatus.CONNECTED) {
105
- setReconnectAttempts(0);
106
- }
107
- });
108
- // 监听错误
109
- socket.on('error', (errorEvent) => {
110
- setError(errorEvent);
111
- });
112
- // 监听连接关闭
113
- socket.on('close', () => {
114
- setError(null);
115
- });
116
- isInitializedRef.current = true;
117
- }
118
- catch (err) {
119
- console.error('Failed to initialize socket:', err);
120
- setError(err);
121
- }
122
- }, [getSocket]);
123
- // 自动连接
124
- useEffect(() => {
125
- if (config.autoConnect !== false && !isInitializedRef.current) {
126
- connect().catch(console.error);
127
- }
128
- }, [config.autoConnect, connect]);
129
- // 组件卸载时清理
130
- useEffect(() => {
131
- return () => {
132
- const socket = socketRef.current;
133
- if (socket && config.autoConnect !== false) {
134
- socket.disconnect();
135
- }
136
- };
137
- }, [config.autoConnect]);
138
- // 检查是否已连接
139
- const isConnected = status === ConnectionStatus.CONNECTED;
140
- return {
141
- status,
142
- isConnected,
143
- connect,
144
- disconnect,
145
- send,
146
- sendJSON,
147
- on,
148
- off,
149
- error,
150
- reconnectAttempts,
151
- reconnect,
152
- };
153
- }
154
- /**
155
- * useSocketMessage Hook
156
- * 专门用于监听特定类型消息的简化Hook
157
- *
158
- * @param config WebSocket配置选项
159
- * @param messageHandler 消息处理函数
160
- * @returns useSocket的返回值对象
161
- */
162
- export function useSocketMessage(config, messageHandler) {
163
- const socket = useSocket(config);
164
- useEffect(() => {
165
- socket.on('message', (data) => {
166
- try {
167
- const parsedData = typeof data === 'string' ? JSON.parse(data) : data;
168
- messageHandler(parsedData);
169
- }
170
- catch (err) {
171
- console.error('Failed to parse message:', err);
172
- }
173
- });
174
- return () => {
175
- socket.off('message');
176
- };
177
- }, [socket, messageHandler]);
178
- return socket;
179
- }
180
- /**
181
- * useSocketStatus Hook
182
- * 专门用于监听连接状态的简化Hook
183
- *
184
- * @param config WebSocket配置选项
185
- * @returns 连接状态和状态变化回调
186
- */
187
- export function useSocketStatus(config) {
188
- const [status, setStatus] = useState(ConnectionStatus.DISCONNECTED);
189
- const socket = useSocket(config);
190
- useEffect(() => {
191
- socket.on('statusChange', setStatus);
192
- return () => {
193
- socket.off('statusChange');
194
- };
195
- }, [socket]);
196
- return {
197
- status,
198
- isConnected: status === ConnectionStatus.CONNECTED,
199
- isConnecting: status === ConnectionStatus.CONNECTING,
200
- isReconnecting: status === ConnectionStatus.RECONNECTING,
201
- isDisconnected: status === ConnectionStatus.DISCONNECTED,
202
- hasError: status === ConnectionStatus.ERROR,
203
- };
204
- }