Skip to content

Commit e24b0d8

Browse files
authored
Merge pull request #6 from Demali-876/codex/manual-release-versioning
Serve raw tunnel streams from node
2 parents 83747c6 + 35e2d37 commit e24b0d8

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@canister-software/consensus-node",
3-
"version": "0.1.0-alpha.2",
3+
"version": "0.1.0-alpha.3",
44
"description": "Verifiable Consensus worker node runtime",
55
"type": "module",
66
"main": "src/instance.ts",

src/clients/control-client.ts

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { loadOrCreateIdentity } from "../crypto/identity";
2+
import net from "node:net";
23
import { releaseManifest } from "../node/manifest";
34
import { loadConfig } from "../node/state";
45
import { capabilitiesRecord } from "../runtime/capabilities";
@@ -34,6 +35,7 @@ export async function startControlClient(options: ControlClientOptions) {
3435
const heartbeatIntervalMs = options.heartbeatIntervalMs ?? 30_000;
3536
let activeRequests = 0;
3637
const activeStreams = new Set<string>();
38+
const rawStreams = new Map<string, net.Socket>();
3739
let preparedUpdate: {
3840
updateId: string;
3941
manifest: ReleaseManifest;
@@ -82,17 +84,69 @@ export async function startControlClient(options: ControlClientOptions) {
8284
}
8385

8486
if (message.type === MESSAGE_TYPE.STREAM_OPEN) {
85-
if (message.target !== "proxy-session") {
87+
if (message.target === "proxy-session") {
88+
activeStreams.add(message.stream_id);
89+
return;
90+
}
91+
92+
const target = parseRawTunnelTarget(message.target);
93+
if (!target) {
8694
await client.send(createErrorMessage({
8795
code: "unsupported_stream_target",
8896
message: `Unsupported stream target: ${message.target ?? ""}`,
8997
}));
98+
return;
9099
}
100+
91101
activeStreams.add(message.stream_id);
102+
const socket = net.createConnection({ host: target.host, port: target.port });
103+
rawStreams.set(message.stream_id, socket);
104+
105+
socket.on("data", (data) => {
106+
void client.send({
107+
type: MESSAGE_TYPE.STREAM_DATA,
108+
timestamp: nowSeconds(),
109+
stream_id: message.stream_id,
110+
data: data.toString("base64"),
111+
encoding: "base64",
112+
}).catch(() => undefined);
113+
});
114+
115+
socket.on("close", () => {
116+
rawStreams.delete(message.stream_id);
117+
activeStreams.delete(message.stream_id);
118+
void client.send({
119+
type: MESSAGE_TYPE.STREAM_CLOSE,
120+
timestamp: nowSeconds(),
121+
stream_id: message.stream_id,
122+
reason: "target closed",
123+
}).catch(() => undefined);
124+
});
125+
126+
socket.on("error", (error) => {
127+
rawStreams.delete(message.stream_id);
128+
activeStreams.delete(message.stream_id);
129+
void client.send(createErrorMessage({
130+
code: "raw_tunnel_failed",
131+
message: error.message,
132+
})).catch(() => undefined);
133+
void client.send({
134+
type: MESSAGE_TYPE.STREAM_CLOSE,
135+
timestamp: nowSeconds(),
136+
stream_id: message.stream_id,
137+
reason: error.message,
138+
}).catch(() => undefined);
139+
});
92140
return;
93141
}
94142

95143
if (message.type === MESSAGE_TYPE.STREAM_DATA) {
144+
const rawSocket = rawStreams.get(message.stream_id);
145+
if (rawSocket) {
146+
rawSocket.write(Buffer.from(message.data, "base64"));
147+
return;
148+
}
149+
96150
activeRequests += 1;
97151
try {
98152
const output = await executeProxySessionMessage(Buffer.from(message.data, "base64"));
@@ -110,6 +164,11 @@ export async function startControlClient(options: ControlClientOptions) {
110164
}
111165

112166
if (message.type === MESSAGE_TYPE.STREAM_CLOSE) {
167+
const rawSocket = rawStreams.get(message.stream_id);
168+
if (rawSocket) {
169+
rawStreams.delete(message.stream_id);
170+
rawSocket.destroy();
171+
}
113172
activeStreams.delete(message.stream_id);
114173
return;
115174
}
@@ -207,3 +266,17 @@ export async function startControlClient(options: ControlClientOptions) {
207266
},
208267
};
209268
}
269+
270+
function parseRawTunnelTarget(value: string | undefined): { host: string; port: number } | null {
271+
if (!value) return null;
272+
try {
273+
const parsed = JSON.parse(value) as { kind?: string; host?: string; port?: number };
274+
if (parsed.kind !== "raw-tunnel" || !parsed.host) return null;
275+
if (typeof parsed.port !== "number" || !Number.isInteger(parsed.port) || parsed.port < 1 || parsed.port > 65535) {
276+
return null;
277+
}
278+
return { host: parsed.host, port: parsed.port };
279+
} catch {
280+
return null;
281+
}
282+
}

0 commit comments

Comments
 (0)