@iicp/client 0.6.0 → 0.7.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +24 -0
- package/dist/cli.js.map +1 -1
- package/dist/iicp_tcp.d.ts +4 -1
- package/dist/iicp_tcp.d.ts.map +1 -1
- package/dist/iicp_tcp.js +3 -0
- package/dist/iicp_tcp.js.map +1 -1
- package/dist/node.d.ts +10 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +86 -4
- package/dist/node.js.map +1 -1
- package/dist/peer_manager.d.ts +19 -2
- package/dist/peer_manager.d.ts.map +1 -1
- package/dist/peer_manager.js +52 -3
- package/dist/peer_manager.js.map +1 -1
- package/dist/relay_session.d.ts +42 -0
- package/dist/relay_session.d.ts.map +1 -0
- package/dist/relay_session.js +276 -0
- package/dist/relay_session.js.map +1 -0
- package/dist/relay_worker_client.d.ts +37 -0
- package/dist/relay_worker_client.d.ts.map +1 -0
- package/dist/relay_worker_client.js +216 -0
- package/dist/relay_worker_client.js.map +1 -0
- package/package.json +1 -1
package/dist/peer_manager.d.ts
CHANGED
|
@@ -12,23 +12,40 @@ export interface PeerInfo {
|
|
|
12
12
|
region: string;
|
|
13
13
|
last_seen: string;
|
|
14
14
|
last_contact: number;
|
|
15
|
+
/** R3: relay election fields — advertised in gossip exchange */
|
|
16
|
+
relay_capable?: boolean;
|
|
17
|
+
relay_accept_port?: number;
|
|
18
|
+
relay_load?: number;
|
|
15
19
|
}
|
|
16
20
|
export declare class PeerManager {
|
|
17
21
|
private readonly directoryUrl;
|
|
18
22
|
private readonly nodeToken;
|
|
19
23
|
private peers;
|
|
20
24
|
private ownId;
|
|
25
|
+
private ownEndpoint;
|
|
26
|
+
private readonly ownRelayCapable;
|
|
27
|
+
private readonly ownRelayAcceptPort;
|
|
21
28
|
private timer;
|
|
22
|
-
constructor(directoryUrl: string, nodeToken?: string
|
|
29
|
+
constructor(directoryUrl: string, nodeToken?: string, opts?: {
|
|
30
|
+
relayCapable?: boolean;
|
|
31
|
+
relayAcceptPort?: number;
|
|
32
|
+
});
|
|
23
33
|
getPeers(): PeerInfo[];
|
|
24
34
|
relayTarget(nodeId: string): PeerInfo | undefined;
|
|
25
35
|
/** Merge incoming peer entries. Returns the count of newly added peers. */
|
|
26
36
|
mergePeers(incoming: Array<Partial<PeerInfo>>): number;
|
|
37
|
+
/** R3: return relay-capable peers, for relay election. */
|
|
38
|
+
getRelayCandidates(): PeerInfo[];
|
|
39
|
+
/** R3: deterministic relay election — rank by load, tiebreak by SHA-256 hash. */
|
|
40
|
+
electRelay(workerId: string): Promise<(PeerInfo & {
|
|
41
|
+
_relayHost: string;
|
|
42
|
+
_relayPort: number;
|
|
43
|
+
}) | null>;
|
|
27
44
|
/** Drop peers not contacted within the expiry window. Returns count pruned. */
|
|
28
45
|
prune(): number;
|
|
29
46
|
/** Verify an inbound /v1/peers HMAC signature. No token configured → accept. */
|
|
30
47
|
verifyExchange(body: string, signature: string | undefined | null): boolean;
|
|
31
|
-
start(nodeId: string): Promise<void>;
|
|
48
|
+
start(nodeId: string, ownEndpoint?: string): Promise<void>;
|
|
32
49
|
stop(): void;
|
|
33
50
|
gossipRound(): Promise<void>;
|
|
34
51
|
private bootstrap;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer_manager.d.ts","sourceRoot":"","sources":["../src/peer_manager.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAQH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"peer_manager.d.ts","sourceRoot":"","sources":["../src/peer_manager.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAQH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,KAAK,CAA6C;gBAGxD,YAAY,EAAE,MAAM,EACpB,SAAS,SAAK,EACd,IAAI,GAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAO;IAQjE,QAAQ,IAAI,QAAQ,EAAE;IAItB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIjD,2EAA2E;IAC3E,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM;IAqBtD,0DAA0D;IAC1D,kBAAkB,IAAI,QAAQ,EAAE;IAIhC,iFAAiF;IAC3E,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,QAAQ,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IAsB3G,+EAA+E;IAC/E,KAAK,IAAI,MAAM;IAYf,gFAAgF;IAChF,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO;IAMrE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,SAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D,IAAI,IAAI,IAAI;IAIN,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAWpB,SAAS;YAaT,QAAQ;CAkCvB"}
|
package/dist/peer_manager.js
CHANGED
|
@@ -19,10 +19,15 @@ class PeerManager {
|
|
|
19
19
|
nodeToken;
|
|
20
20
|
peers = new Map();
|
|
21
21
|
ownId = "";
|
|
22
|
+
ownEndpoint = "";
|
|
23
|
+
ownRelayCapable;
|
|
24
|
+
ownRelayAcceptPort;
|
|
22
25
|
timer;
|
|
23
|
-
constructor(directoryUrl, nodeToken = "") {
|
|
26
|
+
constructor(directoryUrl, nodeToken = "", opts = {}) {
|
|
24
27
|
this.directoryUrl = directoryUrl.replace(/\/$/, "");
|
|
25
28
|
this.nodeToken = nodeToken;
|
|
29
|
+
this.ownRelayCapable = opts.relayCapable ?? false;
|
|
30
|
+
this.ownRelayAcceptPort = opts.relayAcceptPort ?? 9485;
|
|
26
31
|
}
|
|
27
32
|
getPeers() {
|
|
28
33
|
return [...this.peers.values()];
|
|
@@ -46,10 +51,41 @@ class PeerManager {
|
|
|
46
51
|
region: p.region ?? "",
|
|
47
52
|
last_seen: p.last_seen ?? "",
|
|
48
53
|
last_contact: now,
|
|
54
|
+
relay_capable: p.relay_capable ?? false,
|
|
55
|
+
relay_accept_port: p.relay_accept_port ?? 9485,
|
|
56
|
+
relay_load: p.relay_load ?? 0,
|
|
49
57
|
});
|
|
50
58
|
}
|
|
51
59
|
return added;
|
|
52
60
|
}
|
|
61
|
+
/** R3: return relay-capable peers, for relay election. */
|
|
62
|
+
getRelayCandidates() {
|
|
63
|
+
return [...this.peers.values()].filter((p) => p.relay_capable && p.endpoint);
|
|
64
|
+
}
|
|
65
|
+
/** R3: deterministic relay election — rank by load, tiebreak by SHA-256 hash. */
|
|
66
|
+
async electRelay(workerId) {
|
|
67
|
+
const { createHash } = await import("node:crypto");
|
|
68
|
+
const candidates = this.getRelayCandidates();
|
|
69
|
+
if (candidates.length === 0)
|
|
70
|
+
return null;
|
|
71
|
+
const scored = candidates.map((p) => {
|
|
72
|
+
const load = p.relay_load ?? 0;
|
|
73
|
+
const hash = createHash("sha256").update(`${workerId}:${p.node_id}`).digest("hex");
|
|
74
|
+
return { p, score: [load, hash] };
|
|
75
|
+
});
|
|
76
|
+
scored.sort((a, b) => {
|
|
77
|
+
if (a.score[0] !== b.score[0])
|
|
78
|
+
return a.score[0] - b.score[0];
|
|
79
|
+
return a.score[1] < b.score[1] ? -1 : 1;
|
|
80
|
+
});
|
|
81
|
+
const elected = scored[0].p;
|
|
82
|
+
const url = new URL(elected.endpoint.startsWith("http") ? elected.endpoint : `http://${elected.endpoint}`);
|
|
83
|
+
return {
|
|
84
|
+
...elected,
|
|
85
|
+
_relayHost: url.hostname,
|
|
86
|
+
_relayPort: elected.relay_accept_port ?? 9485,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
53
89
|
/** Drop peers not contacted within the expiry window. Returns count pruned. */
|
|
54
90
|
prune() {
|
|
55
91
|
const cutoff = Date.now() - PEER_EXPIRY_MS;
|
|
@@ -70,8 +106,9 @@ class PeerManager {
|
|
|
70
106
|
return false;
|
|
71
107
|
return (0, pricing_js_1.signBody)(body, this.nodeToken) === signature;
|
|
72
108
|
}
|
|
73
|
-
async start(nodeId) {
|
|
109
|
+
async start(nodeId, ownEndpoint = "") {
|
|
74
110
|
this.ownId = nodeId;
|
|
111
|
+
this.ownEndpoint = ownEndpoint;
|
|
75
112
|
await this.bootstrap();
|
|
76
113
|
this.timer = setInterval(() => {
|
|
77
114
|
void this.gossipRound();
|
|
@@ -105,7 +142,19 @@ class PeerManager {
|
|
|
105
142
|
}
|
|
106
143
|
}
|
|
107
144
|
async exchange(target) {
|
|
108
|
-
|
|
145
|
+
// R3: send full peer objects + own relay entry so recipients can elect us as a relay.
|
|
146
|
+
const peers = [...this.peers.values()];
|
|
147
|
+
const knownPeers = [...peers];
|
|
148
|
+
if (this.ownId) {
|
|
149
|
+
knownPeers.push({
|
|
150
|
+
node_id: this.ownId,
|
|
151
|
+
endpoint: this.ownEndpoint,
|
|
152
|
+
relay_capable: this.ownRelayCapable,
|
|
153
|
+
relay_accept_port: this.ownRelayAcceptPort,
|
|
154
|
+
relay_load: 0,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const body = JSON.stringify({ known_peers: knownPeers });
|
|
109
158
|
const headers = { "Content-Type": "application/json" };
|
|
110
159
|
if (this.nodeToken)
|
|
111
160
|
headers["X-IICP-Signature"] = (0, pricing_js_1.signBody)(body, this.nodeToken);
|
package/dist/peer_manager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer_manager.js","sourceRoot":"","sources":["../src/peer_manager.ts"],"names":[],"mappings":";AAAA,sCAAsC;AACtC;;;;;;;GAOG;;;AAEH,6CAAwC;AAExC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,eAAe,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"peer_manager.js","sourceRoot":"","sources":["../src/peer_manager.ts"],"names":[],"mappings":";AAAA,sCAAsC;AACtC;;;;;;;GAOG;;;AAEH,6CAAwC;AAExC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,eAAe,GAAG,CAAC,CAAC;AAc1B,MAAa,WAAW;IACL,YAAY,CAAS;IACrB,SAAS,CAAS;IAC3B,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IACpC,KAAK,GAAG,EAAE,CAAC;IACX,WAAW,GAAG,EAAE,CAAC;IACR,eAAe,CAAU;IACzB,kBAAkB,CAAS;IACpC,KAAK,CAA6C;IAE1D,YACE,YAAoB,EACpB,SAAS,GAAG,EAAE,EACd,OAA6D,EAAE;QAE/D,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC;QAClD,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC;IACzD,CAAC;IAED,QAAQ;QACN,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,WAAW,CAAC,MAAc;QACxB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,2EAA2E;IAC3E,UAAU,CAAC,QAAkC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC;YACtB,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,IAAI,CAAC,KAAK;gBAAE,SAAS;YACzC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,KAAK,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;gBAClB,OAAO,EAAE,GAAG;gBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;gBAC1B,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;gBACtB,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE;gBAC5B,YAAY,EAAE,GAAG;gBACjB,aAAa,EAAE,CAAC,CAAC,aAAa,IAAI,KAAK;gBACvC,iBAAiB,EAAE,CAAC,CAAC,iBAAiB,IAAI,IAAI;gBAC9C,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC;aAC9B,CAAC,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0DAA0D;IAC1D,kBAAkB;QAChB,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC/E,CAAC;IAED,iFAAiF;IACjF,KAAK,CAAC,UAAU,CAAC,QAAgB;QAC/B,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC7C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAClC,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC;YAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnF,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAqB,EAAE,CAAC;QACxD,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACnB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC3G,OAAO;YACL,GAAG,OAAO;YACV,UAAU,EAAE,GAAG,CAAC,QAAQ;YACxB,UAAU,EAAE,OAAO,CAAC,iBAAiB,IAAI,IAAI;SAC9C,CAAC;IACJ,CAAC;IAED,+EAA+E;IAC/E,KAAK;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;QAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,CAAC,CAAC,YAAY,GAAG,MAAM,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,MAAM,EAAE,CAAC;YACX,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,gFAAgF;IAChF,cAAc,CAAC,IAAY,EAAE,SAAoC;QAC/D,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QACjC,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAC7B,OAAO,IAAA,qBAAQ,EAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,SAAS,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc,EAAE,WAAW,GAAG,EAAE;QAC1C,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1B,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACzB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK;YAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/D,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,SAAS;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,YAAY,uBAAuB,eAAe,EAAE,CAAC;YACzE,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACrE,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAyC,CAAC;gBACzE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;QAC1D,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,MAAgB;QACrC,sFAAsF;QACtF,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACvC,MAAM,UAAU,GAA6B,CAAC,GAAG,KAAK,CAAC,CAAC;QACxD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC;gBACd,OAAO,EAAE,IAAI,CAAC,KAAK;gBACnB,QAAQ,EAAE,IAAI,CAAC,WAAW;gBAC1B,aAAa,EAAE,IAAI,CAAC,eAAe;gBACnC,iBAAiB,EAAE,IAAI,CAAC,kBAAkB;gBAC1C,UAAU,EAAE,CAAC;aACd,CAAC,CAAC;QACL,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;QACzD,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;QAC/E,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAA,qBAAQ,EAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACjF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,EAAE;gBACzE,MAAM,EAAE,MAAM;gBACd,OAAO;gBACP,IAAI;gBACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;aAClC,CAAC,CAAC;YACH,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAyC,CAAC;gBACzE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAClC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACzC,IAAI,CAAC;oBAAE,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACrC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACzC,IAAI,CAAC;gBAAE,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;CACF;AA1KD,kCA0KC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relay-as-last-resort — ADR-041 tier-3, Part 3 R1 (#341).
|
|
3
|
+
*
|
|
4
|
+
* TypeScript port of iicp-client-python/relay_session.py.
|
|
5
|
+
* Workers behind CGNAT hold an outbound IICP-TCP connection here.
|
|
6
|
+
* The relay pushes CALL frames down when /v1/relay is invoked and routes
|
|
7
|
+
* RESPONSE frames back to the waiting HTTP handler.
|
|
8
|
+
*/
|
|
9
|
+
import * as net from "node:net";
|
|
10
|
+
export declare class RelayWorkerSession {
|
|
11
|
+
readonly workerId: string;
|
|
12
|
+
private readonly _socket;
|
|
13
|
+
private readonly _pending;
|
|
14
|
+
private _writeLocked;
|
|
15
|
+
constructor(workerId: string, socket: net.Socket);
|
|
16
|
+
/** Push a task CALL to the worker and await the RESPONSE (via Promise). */
|
|
17
|
+
forwardTask(task: unknown, timeoutMs?: number): Promise<Record<string, unknown>>;
|
|
18
|
+
/** Called by relay accept server when a RESPONSE arrives from the worker. */
|
|
19
|
+
onResponse(callId: string, result: Record<string, unknown>): void;
|
|
20
|
+
}
|
|
21
|
+
export declare class RelaySessionRegistry {
|
|
22
|
+
private readonly _sessions;
|
|
23
|
+
bind(workerId: string, session: RelayWorkerSession): void;
|
|
24
|
+
unbind(workerId: string): void;
|
|
25
|
+
get(workerId: string): RelayWorkerSession | undefined;
|
|
26
|
+
isBound(workerId: string): boolean;
|
|
27
|
+
boundWorkerIds(): string[];
|
|
28
|
+
}
|
|
29
|
+
export declare class RelayAcceptServer {
|
|
30
|
+
private readonly _registry;
|
|
31
|
+
private readonly _host;
|
|
32
|
+
private readonly _port;
|
|
33
|
+
private _server?;
|
|
34
|
+
constructor(registry: RelaySessionRegistry, opts?: {
|
|
35
|
+
host?: string;
|
|
36
|
+
port?: number;
|
|
37
|
+
});
|
|
38
|
+
start(): Promise<void>;
|
|
39
|
+
stop(): Promise<void>;
|
|
40
|
+
private _handleConnection;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=relay_session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay_session.d.ts","sourceRoot":"","sources":["../src/relay_session.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA0ChC,qBAAa,kBAAkB;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgE;IACzF,OAAO,CAAC,YAAY,CAAS;gBAEjB,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM;IAKhD,2EAA2E;IACrE,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,SAAU,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAyBvF,6EAA6E;IAC7E,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAOlE;AAID,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IAEnE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAIzD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI9B,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIrD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIlC,cAAc,IAAI,MAAM,EAAE;CAG3B;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAC,CAAa;gBAEjB,QAAQ,EAAE,oBAAoB,EAAE,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO;IAMvF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAUP,iBAAiB;CAkGhC"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Relay-as-last-resort — ADR-041 tier-3, Part 3 R1 (#341).
|
|
5
|
+
*
|
|
6
|
+
* TypeScript port of iicp-client-python/relay_session.py.
|
|
7
|
+
* Workers behind CGNAT hold an outbound IICP-TCP connection here.
|
|
8
|
+
* The relay pushes CALL frames down when /v1/relay is invoked and routes
|
|
9
|
+
* RESPONSE frames back to the waiting HTTP handler.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.RelayAcceptServer = exports.RelaySessionRegistry = exports.RelayWorkerSession = void 0;
|
|
13
|
+
const net = require("node:net");
|
|
14
|
+
const IICP_MAGIC = Buffer.from("IICP");
|
|
15
|
+
const FRAMING_VERSION = 0x01;
|
|
16
|
+
const FRAME_HEADER_LEN = 12;
|
|
17
|
+
// Frame type constants (mirrors MsgType enum in iicp_tcp.ts)
|
|
18
|
+
const MT_INIT = 0x01;
|
|
19
|
+
const MT_ACK = 0x02;
|
|
20
|
+
const MT_CALL = 0x05;
|
|
21
|
+
const MT_RESPONSE = 0x06;
|
|
22
|
+
const MT_CLOSE = 0x07;
|
|
23
|
+
const MT_PING = 0x09;
|
|
24
|
+
const MT_PONG = 0x0a;
|
|
25
|
+
const MT_RELAY_BIND = 0x0b;
|
|
26
|
+
const MT_RELAY_ACK = 0x0c;
|
|
27
|
+
function _enc(obj) {
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
29
|
+
const cbor = require("cbor-x");
|
|
30
|
+
return cbor.encode(obj);
|
|
31
|
+
}
|
|
32
|
+
function _dec(buf) {
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
34
|
+
const cbor = require("cbor-x");
|
|
35
|
+
return cbor.decode(buf);
|
|
36
|
+
}
|
|
37
|
+
function makeFrame(msgType, payload) {
|
|
38
|
+
const header = Buffer.alloc(FRAME_HEADER_LEN);
|
|
39
|
+
IICP_MAGIC.copy(header, 0);
|
|
40
|
+
header.writeUInt8(FRAMING_VERSION, 4);
|
|
41
|
+
header.writeUInt8(msgType, 5);
|
|
42
|
+
header.writeUInt8(0, 6); // flags
|
|
43
|
+
header.writeUInt8(0, 7); // reserved
|
|
44
|
+
header.writeUInt32BE(payload.length, 8);
|
|
45
|
+
return Buffer.concat([header, payload]);
|
|
46
|
+
}
|
|
47
|
+
// ── RelayWorkerSession ────────────────────────────────────────────────────────
|
|
48
|
+
class RelayWorkerSession {
|
|
49
|
+
workerId;
|
|
50
|
+
_socket;
|
|
51
|
+
_pending = new Map();
|
|
52
|
+
_writeLocked = false;
|
|
53
|
+
constructor(workerId, socket) {
|
|
54
|
+
this.workerId = workerId;
|
|
55
|
+
this._socket = socket;
|
|
56
|
+
}
|
|
57
|
+
/** Push a task CALL to the worker and await the RESPONSE (via Promise). */
|
|
58
|
+
async forwardTask(task, timeoutMs = 120_000) {
|
|
59
|
+
const callId = crypto.randomUUID();
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const timer = setTimeout(() => {
|
|
62
|
+
this._pending.delete(callId);
|
|
63
|
+
reject(new Error(`relay forward timeout for call ${callId}`));
|
|
64
|
+
}, timeoutMs);
|
|
65
|
+
this._pending.set(callId, (result) => {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
resolve(result);
|
|
68
|
+
});
|
|
69
|
+
try {
|
|
70
|
+
const payload = _enc({ 15: callId, 5: Buffer.from(JSON.stringify(task)) });
|
|
71
|
+
const frame = makeFrame(MT_CALL, payload);
|
|
72
|
+
this._socket.write(frame);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
this._pending.delete(callId);
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
reject(err);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** Called by relay accept server when a RESPONSE arrives from the worker. */
|
|
82
|
+
onResponse(callId, result) {
|
|
83
|
+
const cb = this._pending.get(callId);
|
|
84
|
+
if (cb) {
|
|
85
|
+
this._pending.delete(callId);
|
|
86
|
+
cb(result);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.RelayWorkerSession = RelayWorkerSession;
|
|
91
|
+
// ── RelaySessionRegistry ─────────────────────────────────────────────────────
|
|
92
|
+
class RelaySessionRegistry {
|
|
93
|
+
_sessions = new Map();
|
|
94
|
+
bind(workerId, session) {
|
|
95
|
+
this._sessions.set(workerId, session);
|
|
96
|
+
}
|
|
97
|
+
unbind(workerId) {
|
|
98
|
+
this._sessions.delete(workerId);
|
|
99
|
+
}
|
|
100
|
+
get(workerId) {
|
|
101
|
+
return this._sessions.get(workerId);
|
|
102
|
+
}
|
|
103
|
+
isBound(workerId) {
|
|
104
|
+
return this._sessions.has(workerId);
|
|
105
|
+
}
|
|
106
|
+
boundWorkerIds() {
|
|
107
|
+
return [...this._sessions.keys()];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.RelaySessionRegistry = RelaySessionRegistry;
|
|
111
|
+
// ── RelayAcceptServer ─────────────────────────────────────────────────────────
|
|
112
|
+
class RelayAcceptServer {
|
|
113
|
+
_registry;
|
|
114
|
+
_host;
|
|
115
|
+
_port;
|
|
116
|
+
_server;
|
|
117
|
+
constructor(registry, opts = {}) {
|
|
118
|
+
this._registry = registry;
|
|
119
|
+
this._host = opts.host ?? "0.0.0.0";
|
|
120
|
+
this._port = opts.port ?? 9485;
|
|
121
|
+
}
|
|
122
|
+
start() {
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
this._server = net.createServer((socket) => {
|
|
125
|
+
this._handleConnection(socket).catch((err) => {
|
|
126
|
+
console.error(`[relay-accept] session error: ${err instanceof Error ? err.message : err}`);
|
|
127
|
+
socket.destroy();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
this._server.listen(this._port, this._host, () => {
|
|
131
|
+
console.log(`[relay-accept] listening on ${this._host}:${this._port}`);
|
|
132
|
+
resolve();
|
|
133
|
+
});
|
|
134
|
+
this._server.on("error", reject);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
stop() {
|
|
138
|
+
return new Promise((resolve) => {
|
|
139
|
+
if (this._server) {
|
|
140
|
+
this._server.close(() => resolve());
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
resolve();
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async _handleConnection(socket) {
|
|
148
|
+
// Accumulate data into a buffer for synchronous frame parsing
|
|
149
|
+
const chunks = [];
|
|
150
|
+
let resolveData = null;
|
|
151
|
+
socket.on("data", (d) => {
|
|
152
|
+
chunks.push(d);
|
|
153
|
+
if (resolveData) {
|
|
154
|
+
resolveData();
|
|
155
|
+
resolveData = null;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
socket.on("end", () => { if (resolveData) {
|
|
159
|
+
resolveData();
|
|
160
|
+
resolveData = null;
|
|
161
|
+
} });
|
|
162
|
+
socket.on("error", () => { if (resolveData) {
|
|
163
|
+
resolveData();
|
|
164
|
+
resolveData = null;
|
|
165
|
+
} });
|
|
166
|
+
const waitForData = () => new Promise((r) => { resolveData = r; });
|
|
167
|
+
const readExactly = async (n) => {
|
|
168
|
+
while (true) {
|
|
169
|
+
let total = chunks.reduce((s, c) => s + c.length, 0);
|
|
170
|
+
if (total >= n) {
|
|
171
|
+
const merged = Buffer.concat(chunks);
|
|
172
|
+
chunks.length = 0;
|
|
173
|
+
chunks.push(merged.subarray(n));
|
|
174
|
+
return merged.subarray(0, n);
|
|
175
|
+
}
|
|
176
|
+
if (socket.destroyed)
|
|
177
|
+
return null;
|
|
178
|
+
await waitForData();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
// Step 1: INIT
|
|
182
|
+
const magic = await readExactly(4);
|
|
183
|
+
if (!magic || !magic.equals(IICP_MAGIC))
|
|
184
|
+
return;
|
|
185
|
+
const rest = await readExactly(FRAME_HEADER_LEN - 4);
|
|
186
|
+
if (!rest)
|
|
187
|
+
return;
|
|
188
|
+
const header = Buffer.concat([magic, rest]);
|
|
189
|
+
const msgType = header.readUInt8(5);
|
|
190
|
+
const payloadLen = header.readUInt32BE(8);
|
|
191
|
+
if (msgType !== MT_INIT)
|
|
192
|
+
return;
|
|
193
|
+
if (payloadLen > 0) {
|
|
194
|
+
const _ = await readExactly(payloadLen);
|
|
195
|
+
if (!_)
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
socket.write(makeFrame(MT_ACK, _enc({ 1: FRAMING_VERSION })));
|
|
199
|
+
// Step 2: RELAY_BIND
|
|
200
|
+
const rh = await readExactly(FRAME_HEADER_LEN);
|
|
201
|
+
if (!rh)
|
|
202
|
+
return;
|
|
203
|
+
const rmt = rh.readUInt8(5);
|
|
204
|
+
const rlen = rh.readUInt32BE(8);
|
|
205
|
+
if (rmt !== MT_RELAY_BIND)
|
|
206
|
+
return;
|
|
207
|
+
const rbuf = rlen > 0 ? await readExactly(rlen) : Buffer.alloc(0);
|
|
208
|
+
if (!rbuf)
|
|
209
|
+
return;
|
|
210
|
+
let workerId, intent, models;
|
|
211
|
+
try {
|
|
212
|
+
const body = _dec(rbuf);
|
|
213
|
+
workerId = String(body[1] ?? "");
|
|
214
|
+
intent = String(body[2] ?? "");
|
|
215
|
+
models = Array.isArray(body[3]) ? body[3].map(String) : [];
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (!workerId)
|
|
221
|
+
return;
|
|
222
|
+
const session = new RelayWorkerSession(workerId, socket);
|
|
223
|
+
this._registry.bind(workerId, session);
|
|
224
|
+
console.log(`[relay-accept] worker=${workerId} bound (intent=${intent} models=${models.slice(0, 3).join(",")})`);
|
|
225
|
+
socket.write(makeFrame(MT_RELAY_ACK, _enc({ 1: "ok", 2: workerId })));
|
|
226
|
+
// Step 3: relay-worker frame loop
|
|
227
|
+
try {
|
|
228
|
+
while (!socket.destroyed) {
|
|
229
|
+
const fh = await readExactly(FRAME_HEADER_LEN);
|
|
230
|
+
if (!fh)
|
|
231
|
+
break;
|
|
232
|
+
const ft = fh.readUInt8(5);
|
|
233
|
+
const fl = fh.readUInt32BE(8);
|
|
234
|
+
const fp = fl > 0 ? await readExactly(fl) : Buffer.alloc(0);
|
|
235
|
+
if (!fp)
|
|
236
|
+
break;
|
|
237
|
+
if (ft === MT_PING) {
|
|
238
|
+
let echo = Buffer.alloc(0);
|
|
239
|
+
try {
|
|
240
|
+
const pb = _dec(fp);
|
|
241
|
+
const e = pb[1];
|
|
242
|
+
echo = Buffer.isBuffer(e) ? Buffer.from(e) : Buffer.alloc(0);
|
|
243
|
+
}
|
|
244
|
+
catch { /* ok */ }
|
|
245
|
+
socket.write(makeFrame(MT_PONG, _enc({ 1: echo })));
|
|
246
|
+
}
|
|
247
|
+
else if (ft === MT_RESPONSE) {
|
|
248
|
+
try {
|
|
249
|
+
const rb = _dec(fp);
|
|
250
|
+
const callId = String(rb[15] ?? "");
|
|
251
|
+
const raw5 = rb[5];
|
|
252
|
+
let result = {};
|
|
253
|
+
if (Buffer.isBuffer(raw5))
|
|
254
|
+
result = JSON.parse(raw5.toString());
|
|
255
|
+
else if (typeof raw5 === "string")
|
|
256
|
+
result = JSON.parse(raw5);
|
|
257
|
+
session.onResponse(callId, result);
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
console.warn(`[relay-accept] RESPONSE decode error: ${err}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else if (ft === MT_CLOSE) {
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
finally {
|
|
269
|
+
this._registry.unbind(workerId);
|
|
270
|
+
console.log(`[relay-accept] session ended for worker=${workerId}`);
|
|
271
|
+
socket.destroy();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
exports.RelayAcceptServer = RelayAcceptServer;
|
|
276
|
+
//# sourceMappingURL=relay_session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay_session.js","sourceRoot":"","sources":["../src/relay_session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relay worker client — ADR-041 tier-3, Part 3 R2 (#341).
|
|
3
|
+
*
|
|
4
|
+
* TypeScript port of relay_worker_client.py.
|
|
5
|
+
* A CGNAT-unreachable node connects outbound to a relay node here.
|
|
6
|
+
* The relay pushes CALL frames down the persistent session; the worker
|
|
7
|
+
* handles them and sends RESPONSE back. PING/PONG keepalive with auto-
|
|
8
|
+
* reconnect (exponential backoff, cap 60 s).
|
|
9
|
+
*/
|
|
10
|
+
export type RelayTaskHandler = (task: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
11
|
+
export declare class RelayWorkerClient {
|
|
12
|
+
private readonly _workerId;
|
|
13
|
+
private readonly _intent;
|
|
14
|
+
private readonly _relayHost;
|
|
15
|
+
private readonly _relayPort;
|
|
16
|
+
private readonly _handler;
|
|
17
|
+
private readonly _models;
|
|
18
|
+
private readonly _onBind?;
|
|
19
|
+
private _stopped;
|
|
20
|
+
constructor(opts: {
|
|
21
|
+
workerId: string;
|
|
22
|
+
intent: string;
|
|
23
|
+
relayHost: string;
|
|
24
|
+
relayPort: number;
|
|
25
|
+
handler: RelayTaskHandler;
|
|
26
|
+
models?: string[];
|
|
27
|
+
/** Called after a successful RELAY_ACK — use to re-register with the directory (#358). */
|
|
28
|
+
onBind?: (relayHost: string, relayPort: number, workerId: string) => Promise<void>;
|
|
29
|
+
});
|
|
30
|
+
/** Start the reconnect loop. Returns a stop() function. */
|
|
31
|
+
start(): () => void;
|
|
32
|
+
private _run;
|
|
33
|
+
private _session;
|
|
34
|
+
private _handshake;
|
|
35
|
+
private _handleCall;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=relay_worker_client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay_worker_client.d.ts","sourceRoot":"","sources":["../src/relay_worker_client.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AAwCH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEnG,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA4E;IACrG,OAAO,CAAC,QAAQ,CAAS;gBAEb,IAAI,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,gBAAgB,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,0FAA0F;QAC1F,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACpF;IAUD,2DAA2D;IAC3D,KAAK,IAAI,MAAM,IAAI;YAML,IAAI;IAelB,OAAO,CAAC,QAAQ;YAaF,UAAU;YAoFV,WAAW;CAoB1B"}
|