feat(bridge): establish local pi status bridge
Deliver the initial local bridge, Noctalia v4/v5 adapters, desktop client, service unit, tests, and implementation documentation for persistent Pi status and control.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtemp, stat } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { createConnection } from "node:net";
|
||||
import test from "node:test";
|
||||
import { startUnixSocketServer } from "../src/bridge/unix-server.js";
|
||||
|
||||
function connect(socketPath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const socket = createConnection(socketPath);
|
||||
socket.once("connect", () => resolve(socket));
|
||||
socket.once("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
function readFrame(socket) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let buffer = "";
|
||||
const onData = (chunk) => {
|
||||
buffer += chunk;
|
||||
const newline = buffer.indexOf("\n");
|
||||
if (newline === -1) return;
|
||||
socket.off("data", onData);
|
||||
try {
|
||||
resolve(JSON.parse(buffer.slice(0, newline)));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
socket.on("data", onData);
|
||||
socket.once("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
test("serves validated JSONL requests over an owner-only Unix socket", async () => {
|
||||
const directory = await mkdtemp(join(tmpdir(), "pi-status-bridge-"));
|
||||
const socketPath = join(directory, "bridge.sock");
|
||||
const bridge = await startUnixSocketServer({
|
||||
socketPath,
|
||||
handleRequest: async (request) => ({ echoedOperation: request.op }),
|
||||
});
|
||||
const socket = await connect(socketPath);
|
||||
|
||||
try {
|
||||
const socketStats = await stat(socketPath);
|
||||
const mode = socketStats.mode & 0o777;
|
||||
assert.equal(mode, 0o600);
|
||||
|
||||
const response = readFrame(socket);
|
||||
socket.write(
|
||||
`${JSON.stringify({ version: "v1", id: "request-2", op: "list_agents" })}\r\n`,
|
||||
);
|
||||
assert.deepEqual(await response, {
|
||||
version: "v1",
|
||||
id: "request-2",
|
||||
ok: true,
|
||||
result: { echoedOperation: "list_agents" },
|
||||
});
|
||||
} finally {
|
||||
socket.destroy();
|
||||
await bridge.close();
|
||||
}
|
||||
});
|
||||
|
||||
test("returns protocol errors without routing invalid input", async () => {
|
||||
const directory = await mkdtemp(join(tmpdir(), "pi-status-bridge-"));
|
||||
const socketPath = join(directory, "bridge.sock");
|
||||
const bridge = await startUnixSocketServer({
|
||||
socketPath,
|
||||
handleRequest: async () => ({}),
|
||||
});
|
||||
const socket = await connect(socketPath);
|
||||
|
||||
try {
|
||||
const response = readFrame(socket);
|
||||
socket.write('{"version":"v1","id":"request-3","op":"unknown"}\n');
|
||||
assert.deepEqual(await response, {
|
||||
version: "v1",
|
||||
id: "request-3",
|
||||
ok: false,
|
||||
error: {
|
||||
code: "unsupported_operation",
|
||||
message: "operation unknown is not supported",
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
socket.destroy();
|
||||
await bridge.close();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user