consortium
Version:
Remote control and session sharing CLI for AI coding agents
125 lines (121 loc) • 3.22 kB
JavaScript
;
var net = require('net');
var writable = require('./writable-CMUWv_PX.cjs');
var consumable = require('./consumable-jpudCE9S.cjs');
require('./utils-vmOBBBS0.cjs');
function nodeSocketToConnection(socket) {
socket.setNoDelay(true);
const closed = new Promise((resolve) => {
socket.on("close", resolve);
});
return {
readable: new consumable.PushReadableStream((controller) => {
socket.on("data", async (data) => {
if (controller.abortSignal.aborted) {
return;
}
socket.pause();
await controller.enqueue(data);
socket.resume();
});
socket.on("end", () => {
consumable.tryClose(controller);
});
}),
writable: new writable.MaybeConsumableWritableStream({
write: (chunk) => {
return new Promise((resolve, reject) => {
socket.write(chunk, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
}),
get closed() {
return closed;
},
close() {
socket.end();
}
};
}
class AdbServerNodeTcpConnector {
spec;
#listeners = /* @__PURE__ */ new Map();
constructor(spec) {
this.spec = spec;
}
async connect({ unref, signal } = { unref: false }) {
const socket = new net.Socket({ signal });
if (unref) {
socket.unref();
}
socket.connect(this.spec);
await new Promise((resolve, reject) => {
socket.once("connect", resolve);
socket.once("error", reject);
});
return nodeSocketToConnection(socket);
}
async addReverseTunnel(handler, address) {
const server = new net.Server(async (socket) => {
const connection = nodeSocketToConnection(socket);
try {
await handler({
service: address,
readable: connection.readable,
writable: connection.writable,
get closed() {
return connection.closed;
},
async close() {
await connection.close();
}
});
} catch {
socket.end();
}
});
if (address) {
const url = new URL(address);
if (url.protocol === "tcp:") {
server.listen(Number.parseInt(url.port, 10), url.hostname);
} else if (url.protocol === "unix:") {
server.listen(url.pathname);
} else {
throw new TypeError(`Unsupported protocol ${url.protocol}`);
}
} else {
server.listen();
}
await new Promise((resolve, reject) => {
server.on("listening", () => resolve());
server.on("error", (e) => reject(e));
});
if (!address) {
const info = server.address();
address = `tcp:${info.port}`;
}
this.#listeners.set(address, server);
return address;
}
removeReverseTunnel(address) {
const server = this.#listeners.get(address);
if (!server) {
return;
}
server.close();
this.#listeners.delete(address);
}
clearReverseTunnels() {
for (const server of this.#listeners.values()) {
server.close();
}
this.#listeners.clear();
}
}
exports.AdbServerNodeTcpConnector = AdbServerNodeTcpConnector;