egos-transfer 0.2.6 → 0.2.7

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.
@@ -0,0 +1,47 @@
1
+ import { DataConnection, Peer } from 'peerjs';
2
+ export interface ConnectionManagerDeps {
3
+ /** 获取当前 Peer 实例(PeerTransfer 可能异步重建) */
4
+ getPeer: () => Peer | undefined;
5
+ peerId: string;
6
+ ping: (peerId: string) => Promise<boolean>;
7
+ /** 连接关闭时回调,由 PeerTransfer 处理未完成的请求结算 */
8
+ onConnClosed: (conn: DataConnection) => void;
9
+ }
10
+ /**
11
+ * DataConnection 连接池管理器
12
+ * - 管理 DataConnection 的生命周期(注册/移除/有效性检查)
13
+ * - 15 秒定时健康检查:ping 每个连接,不通则丢弃
14
+ * - 监听 connectionstatechange,终态时自动清理
15
+ */
16
+ export declare class ConnectionManager {
17
+ private pool;
18
+ private healthCheckTimer;
19
+ private pingRequests;
20
+ private destroyed;
21
+ private readonly deps;
22
+ constructor(deps: ConnectionManagerDeps);
23
+ get(peerId: string): DataConnection | undefined;
24
+ has(peerId: string): boolean;
25
+ get size(): number;
26
+ getAllPeers(): string[];
27
+ clean(): void;
28
+ /**
29
+ * 注册一个连接:入池、绑定 data/close/error/connectionstatechange 事件
30
+ * @param conn - 已打开的 DataConnection
31
+ * @param onData - 数据事件回调(由 PeerTransfer 提供,路由消息)
32
+ */
33
+ setup(conn: DataConnection, onData: (message: any) => void): DataConnection;
34
+ remove(peerId: string, connectionId?: string): void;
35
+ isValid(conn?: DataConnection): boolean;
36
+ private handleConnClosed;
37
+ startHealthCheck(): void;
38
+ stopHealthCheck(): void;
39
+ private checkAllConnections;
40
+ private pingConnection;
41
+ /**
42
+ * 由 PeerTransfer.onResponse 调用,优先处理 ping 回调
43
+ * @returns true 表示该 requestId 是 health check 并已处理
44
+ */
45
+ tryResolvePing(requestId: string): boolean;
46
+ destroy(): void;
47
+ }
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ConnectionManager = void 0;
13
+ const HEALTH_CHECK_INTERVAL = 15000;
14
+ /**
15
+ * DataConnection 连接池管理器
16
+ * - 管理 DataConnection 的生命周期(注册/移除/有效性检查)
17
+ * - 15 秒定时健康检查:ping 每个连接,不通则丢弃
18
+ * - 监听 connectionstatechange,终态时自动清理
19
+ */
20
+ class ConnectionManager {
21
+ constructor(deps) {
22
+ this.pool = new Map();
23
+ this.healthCheckTimer = null;
24
+ this.pingRequests = new Map();
25
+ this.destroyed = false;
26
+ this.deps = deps;
27
+ }
28
+ // ── Pool access ──────────────────────────────────────────────────
29
+ get(peerId) {
30
+ const conn = this.pool.get(peerId);
31
+ if (!conn) {
32
+ return;
33
+ }
34
+ if (this.isValid(conn)) {
35
+ return conn;
36
+ }
37
+ else {
38
+ this.remove(peerId);
39
+ return;
40
+ }
41
+ }
42
+ has(peerId) {
43
+ return this.pool.has(peerId);
44
+ }
45
+ get size() {
46
+ return this.pool.size;
47
+ }
48
+ getAllPeers() {
49
+ return Array.from(this.pool.keys());
50
+ }
51
+ clean() {
52
+ for (const peerId of this.getAllPeers()) {
53
+ this.remove(peerId);
54
+ }
55
+ }
56
+ // ── Connection lifecycle ─────────────────────────────────────────
57
+ /**
58
+ * 注册一个连接:入池、绑定 data/close/error/connectionstatechange 事件
59
+ * @param conn - 已打开的 DataConnection
60
+ * @param onData - 数据事件回调(由 PeerTransfer 提供,路由消息)
61
+ */
62
+ setup(conn, onData) {
63
+ this.pool.set(conn.peer, conn);
64
+ conn.on('data', onData);
65
+ conn.on('close', () => this.handleConnClosed(conn));
66
+ conn.on('error', () => this.handleConnClosed(conn));
67
+ // 监听底层 RTCPeerConnection 的 connectionstatechange,终态时自动清理
68
+ const pc = conn.peerConnection;
69
+ if (pc) {
70
+ const onStateChange = () => {
71
+ if (pc.connectionState === 'failed' || pc.connectionState === 'closed') {
72
+ this.handleConnClosed(conn);
73
+ }
74
+ };
75
+ pc.addEventListener('connectionstatechange', onStateChange);
76
+ // 将清理函数挂到 conn 上,remove 时一并移除
77
+ conn.__cm_stateChangeCleanup = () => {
78
+ pc.removeEventListener('connectionstatechange', onStateChange);
79
+ };
80
+ }
81
+ return conn;
82
+ }
83
+ remove(peerId, connectionId) {
84
+ var _a, _b;
85
+ const conn = this.pool.get(peerId);
86
+ if (conn) {
87
+ if (connectionId && conn.connectionId !== connectionId)
88
+ return;
89
+ this.pool.delete(peerId);
90
+ // 清理 connectionstatechange listener
91
+ // (conn as any).__cm_stateChangeCleanup?.();
92
+ // conn.removeAllListeners();
93
+ // conn.close();
94
+ // this.deps.getPeer()?._removeConnection(conn);
95
+ }
96
+ else {
97
+ // 清理 Peer 内部残留的 connection 引用
98
+ const connections = ((_a = this.deps.getPeer()) === null || _a === void 0 ? void 0 : _a.connections) || {};
99
+ for (const c of connections[peerId] || []) {
100
+ c.removeAllListeners();
101
+ c.close();
102
+ (_b = this.deps.getPeer()) === null || _b === void 0 ? void 0 : _b._removeConnection(c);
103
+ }
104
+ }
105
+ }
106
+ isValid(conn) {
107
+ if (!(conn === null || conn === void 0 ? void 0 : conn.open))
108
+ return false;
109
+ if (!(conn === null || conn === void 0 ? void 0 : conn.peerConnection))
110
+ return false;
111
+ return ['connected', 'completed'].includes(conn.peerConnection.connectionState);
112
+ }
113
+ handleConnClosed(conn) {
114
+ this.pool.delete(conn.peer);
115
+ this.deps.onConnClosed(conn);
116
+ }
117
+ // ── Health check ─────────────────────────────────────────────────
118
+ startHealthCheck() {
119
+ if (this.destroyed)
120
+ return;
121
+ this.stopHealthCheck();
122
+ this.healthCheckTimer = setInterval(() => {
123
+ this.checkAllConnections();
124
+ }, HEALTH_CHECK_INTERVAL);
125
+ }
126
+ stopHealthCheck() {
127
+ if (this.healthCheckTimer !== null) {
128
+ clearInterval(this.healthCheckTimer);
129
+ this.healthCheckTimer = null;
130
+ }
131
+ }
132
+ checkAllConnections() {
133
+ return __awaiter(this, void 0, void 0, function* () {
134
+ const peers = this.getAllPeers();
135
+ for (const peerId of peers) {
136
+ const conn = this.pool.get(peerId);
137
+ if (!conn)
138
+ continue;
139
+ const alive = yield this.pingConnection(conn);
140
+ if (!alive) {
141
+ this.remove(peerId);
142
+ }
143
+ }
144
+ });
145
+ }
146
+ pingConnection(conn) {
147
+ return __awaiter(this, void 0, void 0, function* () {
148
+ try {
149
+ if (!this.isValid(conn)) {
150
+ return false;
151
+ }
152
+ return yield this.deps.ping(conn.peer);
153
+ // const requestId = await this.deps.genRequestId();
154
+ // return new Promise<boolean>((resolve) => {
155
+ // const timer = setTimeout(() => {
156
+ // this.pingRequests.delete(requestId);
157
+ // resolve(false);
158
+ // }, PING_TIMEOUT);
159
+ // this.pingRequests.set(requestId, () => {
160
+ // clearTimeout(timer);
161
+ // resolve(true);
162
+ // });
163
+ // conn.send({
164
+ // route: PeerRoutes.HEARTBEAT,
165
+ // method: 'get',
166
+ // body: {},
167
+ // requestId,
168
+ // scope: PeerScope.REQUEST,
169
+ // action: PeerAction.SEND,
170
+ // src: this.deps.peerId,
171
+ // dest: conn.peer,
172
+ // headers: {},
173
+ // createdAt: Date.now(),
174
+ // });
175
+ // });
176
+ }
177
+ catch (_a) {
178
+ return false;
179
+ }
180
+ });
181
+ }
182
+ /**
183
+ * 由 PeerTransfer.onResponse 调用,优先处理 ping 回调
184
+ * @returns true 表示该 requestId 是 health check 并已处理
185
+ */
186
+ tryResolvePing(requestId) {
187
+ const cb = this.pingRequests.get(requestId);
188
+ if (cb) {
189
+ cb({});
190
+ this.pingRequests.delete(requestId);
191
+ return true;
192
+ }
193
+ return false;
194
+ }
195
+ // ── Lifecycle ───────────────────────────────────────────────────
196
+ destroy() {
197
+ this.destroyed = true;
198
+ this.stopHealthCheck();
199
+ for (const peerId of this.getAllPeers()) {
200
+ this.remove(peerId);
201
+ }
202
+ this.pool.clear();
203
+ this.pingRequests.clear();
204
+ }
205
+ }
206
+ exports.ConnectionManager = ConnectionManager;
@@ -302,7 +302,6 @@ class FileTransfer {
302
302
  }
303
303
  if (processed.length === totalChunk) {
304
304
  const checksum = yield this.taskService.verifyFile(task.transId);
305
- console.log('file verify', checksum);
306
305
  if (checksum) {
307
306
  yield this.done(task);
308
307
  yield this.updateTask(task.transId, {
package/dist/index.d.ts CHANGED
@@ -1,80 +1,4 @@
1
- import { DataConnection, Peer, PeerOptions } from 'peerjs';
2
- import { IDeviceStatus, IMessage, PeerMessage, PeerRequestPayload, RequestCallbackFn, RouteItem } from './interfaces';
3
- import { InternalApi, PeerAction } from './entity';
4
- import { PeerRouter } from './router';
5
- export interface ContentPayload {
6
- file: string;
7
- parent: string;
8
- }
9
- type ResponseCb<T = any> = (args: T) => void;
10
- type PeerTransferOptions = PeerOptions & {
11
- turnExpiredAt: number;
12
- };
13
- export declare abstract class PeerTransfer {
14
- protected peer: Peer | undefined;
15
- protected connectPool: Map<string, DataConnection>;
16
- protected peerConfig: PeerTransferOptions | undefined;
17
- readonly deviceId: string;
18
- readonly peerId: string;
19
- protected requests: Map<string, ResponseCb<any>>;
20
- protected router: PeerRouter;
21
- protected reconnectAttempt: number;
22
- protected destroyed: boolean;
23
- /** connectionId → Set<requestId> — settle in-flight requests on connection drop */
24
- private connRequests;
25
- private _reconnecting;
26
- constructor(deviceId: string, config: PeerTransferOptions);
27
- abstract getStore(): any;
28
- abstract online(deviceId: string): void;
29
- abstract offline(deviceId: string): void;
30
- abstract genRequestId(): Promise<string>;
31
- abstract getApi(peerId: string): Promise<InternalApi | undefined>;
32
- abstract discoverDeviceById(deviceId: string): Promise<void>;
33
- abstract onDestroy(): void;
34
- abstract requireAuth(): Promise<void>;
35
- abstract onConnectLimit(): void;
36
- abstract reloadConfig(config?: Record<string, any>): Promise<void>;
37
- createPeer(): Promise<Peer>;
38
- private waitForOpen;
39
- handleSocketMessage(message: IMessage): void;
40
- connectToPeer(peerId: string): Promise<DataConnection | undefined>;
41
- private createConnection;
42
- onConnect(conn: DataConnection): Promise<DataConnection | undefined>;
43
- private setupConnection;
44
- private onConnClosed;
45
- removeConnection(peerId: string, connectionId?: string): void;
46
- isValidConnection(conn?: DataConnection): boolean;
47
- private bindConnectionData;
48
- request(peerId: string, payload: PeerRequestPayload): Promise<PeerMessage>;
49
- private doRequestOnce;
50
- reply(conn: DataConnection, oldMessage: PeerMessage, message: {
51
- body?: Record<string, any>;
52
- headers?: Record<string, string | number>;
53
- error?: string | Record<string, any>;
54
- }): Promise<void>;
55
- send(conn: DataConnection, message: PeerRequestPayload): Promise<void>;
56
- ping(peerId: string): Promise<boolean>;
57
- getApiHost(): string;
58
- getDeviceStatus(peerId: string): Promise<IDeviceStatus | undefined>;
59
- reconnect(): Promise<Peer | undefined>;
60
- inheritMessage(receiveMsg: PeerMessage): {
61
- src: string;
62
- id: string;
63
- requestId: string;
64
- route: string;
65
- createdAt: string | number;
66
- action: PeerAction;
67
- };
68
- onRequest(conn: DataConnection, message: PeerMessage): Promise<void>;
69
- onResponse(_conn: DataConnection, message: PeerMessage): Promise<void>;
70
- responseOk(conn: DataConnection, message: PeerMessage): Promise<void>;
71
- responseFail(conn: DataConnection, message: PeerMessage, err: string | Record<string, any>): Promise<void>;
72
- use(handler: RequestCallbackFn, prefix?: string): void;
73
- addRoute(route: Omit<RouteItem, 'scope'>): void;
74
- clearInstance(): void;
75
- destroy(): void;
76
- private destroyPeer;
77
- }
1
+ export * from './peer-transfer';
78
2
  export * from './interfaces';
79
3
  export * from './handler';
80
4
  export * from './file-transfer';
@@ -84,3 +8,4 @@ export * from './locker';
84
8
  export * from './entity';
85
9
  export * from './http-transformer';
86
10
  export * from './http-transfer';
11
+ export * from './connection-manager';