guanghu-ice-heart/runtime/public-personal-language-os/server.mjs

49 lines
2.6 KiB
JavaScript

#!/usr/bin/env node
import http from 'node:http';
import fs from 'node:fs';
import { pathToFileURL } from 'node:url';
import { PublicPersonalOS, DOMAINS } from './engine.mjs';
export function createLocalServer({ engine, executionHost }) {
return http.createServer(async (request, response) => {
const send = (status, value) => {
response.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
response.end(JSON.stringify(value));
};
if (request.method === 'GET' && request.url === '/health') {
return send(200, { service: 'hololake-public-personal-os', mode: 'LOCAL_DEVELOPMENT',
domains: Object.keys(DOMAINS), executionAdapterConnected: Boolean(executionHost), liveRegistration: false });
}
if (request.method !== 'POST' || !['/events', '/execute'].includes(request.url)) return send(404, { error: 'NOT_FOUND' });
let size = 0, chunks = [];
try {
for await (const chunk of request) {
size += chunk.length;
if (size > 65536) return send(413, { error: 'REQUEST_TOO_LARGE' });
chunks.push(chunk);
}
const envelope = JSON.parse(Buffer.concat(chunks).toString('utf8'));
if (request.url === '/execute') {
if (!executionHost) return send(409, { error: 'EXECUTION_HOST_NOT_CONNECTED' });
return send(200, await engine.executeAction(envelope, executionHost));
}
if (envelope.action === 'START_ACTION') return send(409, { error: 'USE_EXECUTE_ENDPOINT' });
return send(200, engine.handle(envelope));
} catch (error) {
const code = /^[A-Z_]+$/.test(error.message) ? error.message : 'INVALID_REQUEST_OR_STATE';
const status = /SIGN|SIGNER|AUTHORITY|OWNER|CONSENT|SEED_ONLY/.test(code) ? 403 : 400;
return send(status, { error: code });
}
});
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
const options = Object.fromEntries(process.argv.slice(2).reduce((pairs, v, i, a) => i % 2 ? pairs : [...pairs, [v, a[i + 1]]], []));
if (!options['--state'] || !options['--trust']) throw Error('USAGE: --state <absolute-directory> --trust <trusted-public-keys.json> [--port 3940]');
const trust = JSON.parse(fs.readFileSync(options['--trust'], 'utf8'));
const engine = new PublicPersonalOS({ directory: options['--state'], trust });
const server = createLocalServer({ engine });
server.listen(Number(options['--port'] ?? 3940), '127.0.0.1', () => {
console.log(JSON.stringify({ address: server.address(), mode: 'LOCAL_DEVELOPMENT', liveRegistration: false }));
});
}