slige/web/runtime.ts
2024-12-13 13:16:03 +01:00

84 lines
2.2 KiB
TypeScript

export class Runtime {
private runtimeProcess?: Deno.ChildProcess;
constructor(private port: number) {}
async checkRuntimeRev() {
const currentRev = new TextDecoder().decode(
await new Deno.Command("git", { args: ["rev-parse", "HEAD"] })
.output()
.then((output) => output.stdout),
).trim();
const runtimeRev = (await Deno.readTextFile("../runtime/build/rev"))
.trim();
if (runtimeRev !== currentRev) {
console.error(
"runtime out-of-date; run 'make' inside runtime/ folder",
);
Deno.exit(1);
}
}
async start() {
await this.checkRuntimeRev();
this.runtimeProcess = new Deno.Command("../runtime/build/sliger", {
args: [],
stdout: "piped",
}).spawn();
}
stop() {
this.runtimeProcess?.kill();
this.runtimeProcess = undefined;
}
async connect(): Promise<RuntimeConnection> {
return await new Promise((resolve) => {
setTimeout(async () => {
resolve(
new RuntimeConnection(
await Deno.connect({
port: this.port,
}),
),
);
}, 1000);
});
}
}
export class RuntimeConnection {
constructor(private connection: Deno.Conn) {}
async write(text: string): Promise<void> {
const req = new TextEncoder().encode(text);
await this.connection.write(req);
}
async send<T>(value: T): Promise<void> {
await this.write(JSON.stringify(value));
}
async read(): Promise<string> {
let result = "";
while (true) {
const buf = new Uint8Array(256);
const readRes = await this.connection.read(buf);
if (readRes != null) {
result += new TextDecoder().decode(buf.slice(0, readRes));
} else {
break;
}
}
return result;
}
async receive<T>(): Promise<T> {
return JSON.parse(await this.read()) as T;
}
close() {
this.connection.close();
}
}