49 lines
2.6 KiB
JavaScript
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 }));
|
|
});
|
|
}
|