sx-peerjs-http-util 1.0.6 → 1.1.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/README.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  一个浏览器端库,将 PeerJS 封装成简单易用的类似 HTTP 的 API,并支持语音/视频通话。
4
4
 
5
+ ## 在线 Demo
6
+
7
+ | Demo | 说明 |
8
+ |------|------|
9
+ | [文字传输](https://anarckk.github.io/sx-peerjs-http-util/demos/text-chat/index.html) | P2P 即时聊天 |
10
+ | [文件传输](https://anarckk.github.io/sx-peerjs-http-util/demos/file-transfer/index.html) | 点对点文件传输 |
11
+ | [语音通话](https://anarckk.github.io/sx-peerjs-http-util/demos/voice-call/index.html) | 一对一语音通话 |
12
+ | [视频通话](https://anarckk.github.io/sx-peerjs-http-util/demos/video-call/index.html) | 一对一视频通话 |
13
+
14
+ > **提示**:打开两个浏览器窗口,分别选择"身份1"和"身份2"即可开始通信,无需手动复制 Peer ID。
15
+
5
16
  ## 特性
6
17
 
7
18
  - 简单的请求-响应 API,类似 HTTP
@@ -89,19 +100,21 @@ wrapper.onIncomingCall((event) => {
89
100
  // event.reject();
90
101
  });
91
102
 
92
- // 获取媒体流用于显示
93
- const remoteStream = callSession.getRemoteStream();
103
+ // 获取本地媒体流(立即可用)
94
104
  const localStream = callSession.getLocalStream();
95
105
 
106
+ // 远程媒体流需要等待 connected 状态
107
+ callSession.onStateChange((state) => {
108
+ if (state === 'connected') {
109
+ const remoteStream = callSession.getRemoteStream();
110
+ // 将 remoteStream 设置到 <audio> 或 <video> 元素
111
+ }
112
+ });
113
+
96
114
  // 控制通话
97
115
  callSession.toggleMute(); // 切换静音
98
116
  callSession.toggleVideo(); // 切换视频开关
99
117
  callSession.hangUp(); // 挂断
100
-
101
- // 监听通话状态
102
- callSession.onStateChange((state, reason) => {
103
- console.log('通话状态:', state); // 'connecting' | 'connected' | 'ended'
104
- });
105
118
  ```
106
119
 
107
120
  ### 销毁实例 (destroy)
@@ -110,93 +123,6 @@ callSession.onStateChange((state, reason) => {
110
123
  wrapper.destroy();
111
124
  ```
112
125
 
113
- ## 完整示例
114
-
115
- ### NPM 方式 - 服务器端
116
-
117
- ```html
118
- <!DOCTYPE html>
119
- <html>
120
- <head>
121
- <script src="https://unpkg.com/peerjs@1.5.5/dist/peerjs.min.js"></script>
122
- </head>
123
- <body>
124
- <h1>Server</h1>
125
- <div id="peer-id"></div>
126
-
127
- <script type="module">
128
- import { PeerJsWrapper } from 'https://unpkg.com/sx-peerjs-http-util/dist/index.esm.js';
129
-
130
- const wrapper = new PeerJsWrapper();
131
-
132
- wrapper.registerHandler('/api/hello', (from, data) => {
133
- return { message: 'Hello from server', received: data };
134
- });
135
-
136
- wrapper.whenReady().then(() => {
137
- document.getElementById('peer-id').textContent = `Peer ID: ${wrapper.getPeerId()}`;
138
- });
139
- </script>
140
- </body>
141
- </html>
142
- ```
143
-
144
- ### CDN 方式 - 服务器端
145
-
146
- ```html
147
- <!DOCTYPE html>
148
- <html>
149
- <head>
150
- <!-- CDN 版本已内置 PeerJS -->
151
- <script src="https://unpkg.com/sx-peerjs-http-util/dist/index.umd.js"></script>
152
- </head>
153
- <body>
154
- <h1>Server</h1>
155
- <div id="peer-id"></div>
156
-
157
- <script>
158
- const wrapper = new PeerJsHttpUtil.PeerJsWrapper();
159
-
160
- wrapper.registerHandler('/api/hello', (from, data) => {
161
- return { message: 'Hello from server', received: data };
162
- });
163
-
164
- wrapper.whenReady().then(() => {
165
- document.getElementById('peer-id').textContent = `Peer ID: ${wrapper.getPeerId()}`;
166
- });
167
- </script>
168
- </body>
169
- </html>
170
- ```
171
-
172
- ### 客户端
173
-
174
- ```html
175
- <!DOCTYPE html>
176
- <html>
177
- <head>
178
- <script src="https://unpkg.com/sx-peerjs-http-util/dist/index.umd.js"></script>
179
- </head>
180
- <body>
181
- <h1>Client</h1>
182
- <button onclick="sendRequest()">Send Request</button>
183
-
184
- <script>
185
- const wrapper = new PeerJsHttpUtil.PeerJsWrapper();
186
-
187
- async function sendRequest() {
188
- try {
189
- const data = await wrapper.send('server-peer-id', '/api/hello', { test: 'data' });
190
- console.log('Response:', data);
191
- } catch (err) {
192
- console.error('Error:', err.message);
193
- }
194
- }
195
- </script>
196
- </body>
197
- </html>
198
- ```
199
-
200
126
  ## API 参考
201
127
 
202
128
  ### `new PeerJsWrapper(peerId?: string, isDebug?: boolean, server?: ServerConfig)`
@@ -0,0 +1,99 @@
1
+ /**
2
+ * CallSessionImpl - 通话会话的内部实现
3
+ *
4
+ * 负责管理单个语音/视频通话的完整生命周期:
5
+ * - 音视频流管理
6
+ * - 静音/视频开关状态
7
+ * - 通话状态变化通知
8
+ *
9
+ * @example
10
+ * const session = new CallSessionImpl(peerId, mediaConnection, hasVideo, debugLog, onCleanup);
11
+ * session.toggleMute(); // 切换静音
12
+ * session.toggleVideo(); // 切换视频
13
+ * session.hangUp(); // 挂断通话
14
+ */
15
+ import type { MediaConnection } from 'peerjs';
16
+ import type { CallSession, CallState, CallStateListener } from './types';
17
+ /**
18
+ * 通话会话实现类
19
+ * 实现 CallSession 接口,提供通话控制功能
20
+ */
21
+ export declare class CallSessionImpl implements CallSession {
22
+ /** 对端的 Peer ID */
23
+ readonly peerId: string;
24
+ /** 是否包含视频 */
25
+ readonly hasVideo: boolean;
26
+ /** PeerJS MediaConnection 实例 */
27
+ private mediaConnection;
28
+ /** 本地媒体流(麦克风/摄像头) */
29
+ private localStream;
30
+ /** 远程媒体流(对方的音频/视频) */
31
+ private remoteStream;
32
+ /** 通话状态监听器集合 */
33
+ private stateListeners;
34
+ /** 调试日志函数 */
35
+ private debugLogFn;
36
+ /** 清理回调(通话结束时调用) */
37
+ private onCleanup;
38
+ /** 当前通话状态 */
39
+ private _state;
40
+ /** 是否已静音 */
41
+ private isMuted;
42
+ /** 视频是否开启 */
43
+ private isVideoEnabled;
44
+ /**
45
+ * 创建通话会话实例
46
+ * @param peerId 对端 Peer ID
47
+ * @param mediaConnection PeerJS MediaConnection 实例
48
+ * @param hasVideo 是否包含视频
49
+ * @param debugLog 调试日志函数
50
+ * @param onCleanup 通话结束时的清理回调
51
+ */
52
+ constructor(peerId: string, mediaConnection: MediaConnection, hasVideo: boolean, debugLog: (obj: string, event: string, data?: unknown) => void, onCleanup: (session: CallSessionImpl) => void);
53
+ /** 是否已连接 */
54
+ get isConnected(): boolean;
55
+ /** 当前通话状态 */
56
+ get state(): CallState;
57
+ /**
58
+ * 设置通话状态
59
+ * @param state 新的通话状态
60
+ * @param reason 状态变化原因(可选)
61
+ */
62
+ setState(state: CallState, reason?: string): void;
63
+ /** 设置本地媒体流 */
64
+ setLocalStream(stream: MediaStream): void;
65
+ /** 设置远程媒体流 */
66
+ setRemoteStream(stream: MediaStream): void;
67
+ /** 获取本地媒体流 */
68
+ getLocalStream(): MediaStream | null;
69
+ /** 获取远程媒体流 */
70
+ getRemoteStream(): MediaStream | null;
71
+ /**
72
+ * 切换静音状态
73
+ * @returns 切换后的静音状态(true = 已静音)
74
+ */
75
+ toggleMute(): boolean;
76
+ /**
77
+ * 切换视频开关(仅视频通话有效)
78
+ * @returns 切换后的视频状态(true = 视频开启)
79
+ */
80
+ toggleVideo(): boolean;
81
+ /** 挂断通话 */
82
+ hangUp(): void;
83
+ /**
84
+ * 关闭通话会话
85
+ * 停止本地流,清理资源
86
+ */
87
+ close(): void;
88
+ /** 注册通话状态变化监听器 */
89
+ onStateChange(listener: CallStateListener): void;
90
+ /** 移除通话状态变化监听器 */
91
+ offStateChange(listener: CallStateListener): void;
92
+ /**
93
+ * 通知状态变化
94
+ * @param state 新状态
95
+ * @param reason 变化原因(可选)
96
+ */
97
+ private notifyStateChange;
98
+ }
99
+ //# sourceMappingURL=CallSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CallSession.d.ts","sourceRoot":"","sources":["../src/CallSession.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEzE;;;GAGG;AACH,qBAAa,eAAgB,YAAW,WAAW;IACjD,kBAAkB;IAClB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,aAAa;IACb,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B,gCAAgC;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,qBAAqB;IACrB,OAAO,CAAC,WAAW,CAA4B;IAC/C,sBAAsB;IACtB,OAAO,CAAC,YAAY,CAA4B;IAChD,gBAAgB;IAChB,OAAO,CAAC,cAAc,CAAgC;IACtD,aAAa;IACb,OAAO,CAAC,UAAU,CAAuD;IACzE,oBAAoB;IACpB,OAAO,CAAC,SAAS,CAAqC;IAEtD,aAAa;IACb,OAAO,CAAC,MAAM,CAA2B;IACzC,YAAY;IACZ,OAAO,CAAC,OAAO,CAAS;IACxB,aAAa;IACb,OAAO,CAAC,cAAc,CAAQ;IAE9B;;;;;;;OAOG;gBAED,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,eAAe,EAChC,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,EAC9D,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI;IAS/C,YAAY;IACZ,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,aAAa;IACb,IAAI,KAAK,IAAI,SAAS,CAErB;IAED;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAKjD,cAAc;IACd,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIzC,cAAc;IACd,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAI1C,cAAc;IACd,cAAc,IAAI,WAAW,GAAG,IAAI;IAIpC,cAAc;IACd,eAAe,IAAI,WAAW,GAAG,IAAI;IAIrC;;;OAGG;IACH,UAAU,IAAI,OAAO;IAYrB;;;OAGG;IACH,WAAW,IAAI,OAAO;IAYtB,WAAW;IACX,MAAM,IAAI,IAAI;IAKd;;;OAGG;IACH,KAAK,IAAI,IAAI;IASb,kBAAkB;IAClB,aAAa,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAIhD,kBAAkB;IAClB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAIjD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAe1B"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * MessageHandler - 消息处理模块
3
+ *
4
+ * 负责处理接收到的各类消息:
5
+ * - 直连请求(request)
6
+ * - 中继请求(relay-request)
7
+ * - 路由更新(route-update)
8
+ *
9
+ * 中继请求处理流程:
10
+ * 1. 收到 relay-request 消息
11
+ * 2. 如果是目标节点,处理请求并返回响应
12
+ * 3. 如果不是目标节点,根据 forwardPath 转发到下一个节点
13
+ * 4. 如果 forwardPath 为空,尝试直连到目标节点
14
+ *
15
+ * @example
16
+ * const handler = new MessageHandler(callbacks);
17
+ * const response = await handler.handleRequest(from, request, relayMessage);
18
+ */
19
+ import type { Peer } from 'peerjs';
20
+ import type { Request, Response, SimpleHandler, RelayMessage } from './types';
21
+ /**
22
+ * 消息处理器回调接口
23
+ */
24
+ export interface MessageHandlerCallbacks {
25
+ /** 获取本地 Peer ID */
26
+ getMyPeerId(): string;
27
+ /** 获取 PeerJS 实例 */
28
+ getPeerInstance(): Peer | null;
29
+ /** 等待连接就绪 */
30
+ waitForReady(): Promise<void>;
31
+ /** 获取处理器映射表 */
32
+ getSimpleHandlers(): Map<string, SimpleHandler>;
33
+ /** 调试日志函数 */
34
+ debugLog: (obj: string, event: string, data?: unknown) => void;
35
+ /** 路由更新回调(可选) */
36
+ onRouteUpdate?: (fromPeerId: string, message: RelayMessage) => void;
37
+ }
38
+ /**
39
+ * 消息处理器类
40
+ * 负责解析和处理接收到的各类消息
41
+ */
42
+ export declare class MessageHandler {
43
+ /** 回调函数集合 */
44
+ private callbacks;
45
+ /**
46
+ * 创建消息处理器
47
+ * @param callbacks 回调函数集合
48
+ */
49
+ constructor(callbacks: MessageHandlerCallbacks);
50
+ /**
51
+ * 处理收到的请求
52
+ * 根据是否有中继消息上下文判断是直连请求还是中继请求
53
+ * @param from 发送者 Peer ID
54
+ * @param request 请求数据
55
+ * @param relayMessage 中继消息上下文(可选,有则为中继请求)
56
+ * @returns 响应数据
57
+ */
58
+ handleRequest(from: string, request: Request, relayMessage?: RelayMessage): Promise<Response>;
59
+ /**
60
+ * 处理直连请求
61
+ * @param from 发送者 Peer ID
62
+ * @param request 请求数据
63
+ * @returns 响应数据
64
+ */
65
+ private handleDirectRequest;
66
+ /**
67
+ * 处理中继请求
68
+ * @param from 发送者 Peer ID
69
+ * @param request 请求数据
70
+ * @param relayMessage 中继消息上下文
71
+ * @returns 响应数据
72
+ */
73
+ private handleRelayRequest;
74
+ /**
75
+ * 调用注册的处理器
76
+ * @param path 请求路径
77
+ * @param from 发送者 Peer ID
78
+ * @param data 请求数据
79
+ * @returns 处理器返回的数据,或 404 错误
80
+ */
81
+ processHandler(path: string, from: string, data?: unknown): Promise<unknown>;
82
+ /**
83
+ * 判断结果是否为错误响应
84
+ */
85
+ private isErrorResponse;
86
+ /**
87
+ * 转发中继请求到下一个节点
88
+ * @param nextHop 下一跳节点 ID
89
+ * @param message 要转发的消息
90
+ * @returns 响应数据
91
+ */
92
+ private forwardRelay;
93
+ /**
94
+ * 转发到最终目标节点(当没有更多中继节点时使用)
95
+ * @param targetId 目标节点 ID
96
+ * @param request 请求数据
97
+ * @param originalMessage 原始中继消息
98
+ * @returns 响应数据
99
+ */
100
+ private forwardToTarget;
101
+ }
102
+ //# sourceMappingURL=MessageHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageHandler.d.ts","sourceRoot":"","sources":["../src/MessageHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,mBAAmB;IACnB,WAAW,IAAI,MAAM,CAAC;IACtB,mBAAmB;IACnB,eAAe,IAAI,IAAI,GAAG,IAAI,CAAC;IAC/B,aAAa;IACb,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,eAAe;IACf,iBAAiB,IAAI,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAChD,aAAa;IACb,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/D,iBAAiB;IACjB,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;CACrE;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,aAAa;IACb,OAAO,CAAC,SAAS,CAA0B;IAE3C;;;OAGG;gBACS,SAAS,EAAE,uBAAuB;IAI9C;;;;;;;OAOG;IACG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC;IAOnG;;;;;OAKG;YACW,mBAAmB;IAQjC;;;;;;OAMG;YACW,kBAAkB;IAgDhC;;;;;;OAMG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlF;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;;;;OAKG;YACW,YAAY;IAsD1B;;;;;;OAMG;YACW,eAAe;CAgE9B"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * PeerJsWrapper - 封装 PeerJS 为类似 HTTP 的 API
3
+ *
4
+ * 核心功能:
5
+ * 1. 类似 HTTP 的请求/响应机制(send/relaySend)
6
+ * 2. 语音/视频通话(call/onIncomingCall)
7
+ * 3. 中继路由(relaySend/getRoutingTable/getKnownNodes)
8
+ *
9
+ * @example
10
+ * // 基本请求
11
+ * const wrapper = new PeerJsWrapper();
12
+ * const data = await wrapper.send(peerId, '/api/hello', { name: 'world' });
13
+ *
14
+ * // 中继请求
15
+ * await wrapper.relaySend(targetId, '/api/data', 'test', ['relayNode1', 'relayNode2']);
16
+ *
17
+ * // 语音通话
18
+ * const call = await wrapper.call(peerId, { video: true });
19
+ */
20
+ import type { Request, Response, SimpleHandler, CallOptions, CallSession, CallState, CallStateListener, IncomingCallEvent, IncomingCallListener, RouteEntry, RelayConfig, RelayMessage, ServerConfig } from './types';
21
+ export declare const VERSION: string;
22
+ /**
23
+ * PeerJsWrapper 主类
24
+ * 封装 PeerJS,提供类似 HTTP 的 API
25
+ */
26
+ export declare class PeerJsWrapper {
27
+ /** 本地 Peer ID */
28
+ private myPeerId;
29
+ /** PeerJS 实例 */
30
+ private peerInstance;
31
+ /** 当前活跃的传入连接集合 */
32
+ private connections;
33
+ /** 待处理的请求映射表(用于请求-响应匹配) */
34
+ private pendingRequests;
35
+ /** 路径处理器映射表 */
36
+ private simpleHandlers;
37
+ /** 重连定时器 */
38
+ private reconnectTimer;
39
+ /** 是否已销毁 */
40
+ private isDestroyed;
41
+ /** 是否开启调试模式 */
42
+ private isDebug;
43
+ /** 服务器配置 */
44
+ private serverConfig?;
45
+ /** 当前活跃的通话 */
46
+ private activeCall;
47
+ /** 来电监听器集合 */
48
+ private incomingCallListeners;
49
+ /** 路由管理器 */
50
+ private routingManager;
51
+ /** 消息处理器 */
52
+ private messageHandler;
53
+ /**
54
+ * 创建 PeerJsWrapper 实例
55
+ * @param peerId 可选的 Peer ID,如果不提供则自动生成 UUID
56
+ * @param isDebug 是否开启调试模式,开启后会打印事件日志
57
+ * @param server 可选的信令服务器配置,不提供则使用 PeerJS 公共服务器
58
+ * @param relayConfig 可选的中继配置
59
+ */
60
+ constructor(peerId?: string, isDebug?: boolean, server?: ServerConfig, relayConfig?: RelayConfig);
61
+ private debugLog;
62
+ private connect;
63
+ private setupPeerEventHandlers;
64
+ private scheduleReconnect;
65
+ private reconnect;
66
+ getPeerId(): string;
67
+ whenReady(): Promise<void>;
68
+ private waitForReady;
69
+ relaySend(targetId: string, path: string, data: unknown, relayNodes: string[]): Promise<unknown>;
70
+ getRoutingTable(): Record<string, RouteEntry>;
71
+ getKnownNodes(): string[];
72
+ send(peerId: string, path: string, data?: unknown): Promise<unknown>;
73
+ private setupIncomingConnectionHandler;
74
+ call(peerId: string, options?: CallOptions): Promise<CallSession>;
75
+ onIncomingCall(listener: IncomingCallListener): void;
76
+ offIncomingCall(listener: IncomingCallListener): void;
77
+ getActiveCall(): CallSession | null;
78
+ private setupMediaConnectionHandlers;
79
+ private cleanupCall;
80
+ private handleIncomingCall;
81
+ registerHandler(path: string, handler: SimpleHandler): void;
82
+ unregisterHandler(path: string): void;
83
+ destroy(): void;
84
+ }
85
+ export type { Request, Response, SimpleHandler, CallOptions, CallSession, CallState, CallStateListener, IncomingCallEvent, IncomingCallListener, RouteEntry, RelayConfig, RelayMessage };
86
+ //# sourceMappingURL=PeerJsWrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PeerJsWrapper.d.ts","sourceRoot":"","sources":["../src/PeerJsWrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,aAAa,EACb,WAAW,EACX,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACb,MAAM,SAAS,CAAC;AAIjB,eAAO,MAAM,OAAO,QAAc,CAAC;AAoCnC;;;GAGG;AACH,qBAAa,aAAa;IACxB,iBAAiB;IACjB,OAAO,CAAC,QAAQ,CAAS;IACzB,gBAAgB;IAChB,OAAO,CAAC,YAAY,CAAqB;IACzC,kBAAkB;IAClB,OAAO,CAAC,WAAW,CAA6B;IAChD,2BAA2B;IAC3B,OAAO,CAAC,eAAe,CAAqC;IAC5D,eAAe;IACf,OAAO,CAAC,cAAc,CAAoC;IAC1D,YAAY;IACZ,OAAO,CAAC,cAAc,CAA8C;IACpE,YAAY;IACZ,OAAO,CAAC,WAAW,CAAS;IAC5B,eAAe;IACf,OAAO,CAAC,OAAO,CAAU;IACzB,YAAY;IACZ,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,cAAc;IACd,OAAO,CAAC,UAAU,CAAgC;IAClD,cAAc;IACd,OAAO,CAAC,qBAAqB,CAAmC;IAEhE,YAAY;IACZ,OAAO,CAAC,cAAc,CAAiB;IACvC,YAAY;IACZ,OAAO,CAAC,cAAc,CAAiB;IAEvC;;;;;;OAMG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,WAAW,CAAC,EAAE,WAAW;IAsBhG,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,sBAAsB;IAuC9B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,SAAS;IAgBjB,SAAS,IAAI,MAAM;IAInB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAI1B,OAAO,CAAC,YAAY;IA6BpB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IA6EhG,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;IAI7C,aAAa,IAAI,MAAM,EAAE;IAIzB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAkFpE,OAAO,CAAC,8BAA8B;IA2FtC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IA+EjE,cAAc,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAIpD,eAAe,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAIrD,aAAa,IAAI,WAAW,GAAG,IAAI;IAInC,OAAO,CAAC,4BAA4B;IAoBpC,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,kBAAkB;IA6D1B,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAI3D,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIrC,OAAO,IAAI,IAAI;CAgChB;AAED,YAAY,EACV,OAAO,EACP,QAAQ,EACR,aAAa,EACb,WAAW,EACX,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,WAAW,EACX,YAAY,EACb,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * RoutingManager - 路由管理模块
3
+ *
4
+ * 负责中继通信的核心功能:
5
+ * - 维护已知的成功通信节点列表(knownNodes)
6
+ * - 维护路由表(routingTable)
7
+ * - 广播路由更新到邻居节点
8
+ * - 处理收到的路由更新消息
9
+ *
10
+ * 路由机制:
11
+ * 1. 每次成功通信后,记录对方节点为已知节点
12
+ * 2. 成功后广播路由更新,告知对方自己可达的节点
13
+ * 3. 收到路由更新后,合并到本地路由表
14
+ *
15
+ * @example
16
+ * const routing = new RoutingManager(callbacks, { maxRelayNodes: 5 });
17
+ * routing.recordSuccessfulNode(peerId); // 记录成功节点
18
+ * routing.broadcastRouteUpdate(); // 广播路由
19
+ * const table = routing.getRoutingTable(); // 获取路由表
20
+ */
21
+ import type { Peer } from 'peerjs';
22
+ import type { RouteEntry, RelayConfig, RelayMessage } from './types';
23
+ /**
24
+ * 路由管理器回调接口
25
+ */
26
+ export interface RoutingCallbacks {
27
+ /** 获取本地 Peer ID */
28
+ getMyPeerId(): string;
29
+ /** 获取 PeerJS 实例 */
30
+ getPeerInstance(): Peer | null;
31
+ /** 调试日志函数 */
32
+ debugLog: (obj: string, event: string, data?: unknown) => void;
33
+ }
34
+ /**
35
+ * 路由管理器类
36
+ * 负责维护路由表和节点发现
37
+ */
38
+ export declare class RoutingManager {
39
+ /** 路由表:target -> RouteEntry */
40
+ private routingTable;
41
+ /** 已知的成功通信节点列表 */
42
+ private knownNodes;
43
+ /** 中继配置 */
44
+ private relayConfig;
45
+ /** 回调函数集合 */
46
+ private callbacks;
47
+ /**
48
+ * 创建路由管理器
49
+ * @param callbacks 回调函数集合
50
+ * @param relayConfig 中继配置(可选)
51
+ */
52
+ constructor(callbacks: RoutingCallbacks, relayConfig?: RelayConfig);
53
+ /**
54
+ * 记录成功的通信节点
55
+ * 将成功通信的节点添加到已知节点列表
56
+ * @param nodeId 节点 ID
57
+ */
58
+ recordSuccessfulNode(nodeId: string): void;
59
+ /**
60
+ * 广播路由更新
61
+ * 向所有已知节点发送路由更新消息,告知它们本节点可达的节点列表
62
+ */
63
+ broadcastRouteUpdate(): Promise<void>;
64
+ /**
65
+ * 发送路由更新到指定节点
66
+ * @param targetId 目标节点 ID
67
+ * @param reachableNodes 可达的节点列表
68
+ */
69
+ private sendRouteUpdate;
70
+ /**
71
+ * 处理收到的路由更新
72
+ * 合并对端发来的可达节点信息到本地路由表
73
+ * @param fromPeerId 发送路由更新的节点 ID
74
+ * @param message 路由更新消息
75
+ */
76
+ handleRouteUpdate(fromPeerId: string, message: RelayMessage): void;
77
+ /**
78
+ * 获取路由表(用于调试和显示)
79
+ * @returns 路由表对象
80
+ */
81
+ getRoutingTable(): Record<string, RouteEntry>;
82
+ /**
83
+ * 获取已知节点列表
84
+ * @returns 已知节点 ID 数组
85
+ */
86
+ getKnownNodes(): string[];
87
+ }
88
+ //# sourceMappingURL=Routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Routing.d.ts","sourceRoot":"","sources":["../src/Routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mBAAmB;IACnB,WAAW,IAAI,MAAM,CAAC;IACtB,mBAAmB;IACnB,eAAe,IAAI,IAAI,GAAG,IAAI,CAAC;IAC/B,aAAa;IACb,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAChE;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,+BAA+B;IAC/B,OAAO,CAAC,YAAY,CAAiC;IACrD,kBAAkB;IAClB,OAAO,CAAC,UAAU,CAAgB;IAClC,WAAW;IACX,OAAO,CAAC,WAAW,CAAc;IACjC,aAAa;IACb,OAAO,CAAC,SAAS,CAAmB;IAEpC;;;;OAIG;gBACS,SAAS,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,WAAW;IAKlE;;;;OAIG;IACH,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAe1C;;;OAGG;IACG,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3C;;;;OAIG;YACW,eAAe;IA2C7B;;;;;OAKG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IA6BlE;;;OAGG;IACH,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;IAQ7C;;;OAGG;IACH,aAAa,IAAI,MAAM,EAAE;CAG1B"}