34 lines
1.9 KiB
JavaScript
34 lines
1.9 KiB
JavaScript
import http from 'node:http';
|
|
import { timingSafeEqual } from 'node:crypto';
|
|
import { WebSocketServer } from 'ws';
|
|
import { openStore } from './store.mjs';
|
|
import { handleAdmin } from './admin.mjs';
|
|
import { handleTurn } from './turns.mjs';
|
|
|
|
const { DEVICE_TOKEN, ELEVENLABS_API_KEY, LLM_MODE = 'openrouter', OPENROUTER_API_KEY, PORT = '3000', HOST = '127.0.0.1' } = process.env;
|
|
if (!DEVICE_TOKEN || !ELEVENLABS_API_KEY || !['openrouter', 'echo'].includes(LLM_MODE) || (LLM_MODE === 'openrouter' && !OPENROUTER_API_KEY)) {
|
|
console.error('Missing required configuration or invalid LLM_MODE'); process.exit(1);
|
|
}
|
|
const store = openStore();
|
|
const server = http.createServer(async (req, res) => {
|
|
try {
|
|
if (req.method === 'GET' && req.url === '/healthz') { res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' }); res.end('{"ok":true}'); return; }
|
|
if (await handleAdmin(req, res, store)) return;
|
|
res.writeHead(404); res.end();
|
|
} catch { if (!res.headersSent) res.writeHead(500); res.end(); }
|
|
});
|
|
const sockets = new WebSocketServer({ noServer: true, maxPayload: 128 * 1024, perMessageDeflate: false });
|
|
let active = false;
|
|
server.on('upgrade', (req, socket, head) => {
|
|
const token = req.headers.authorization?.startsWith('Bearer ') ? req.headers.authorization.slice(7) : '';
|
|
const a = Buffer.from(token), b = Buffer.from(DEVICE_TOKEN);
|
|
if (req.url !== '/v1/voice' || a.length !== b.length || !timingSafeEqual(a, b)) { socket.end('HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n'); return; }
|
|
if (active) { socket.end('HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n'); return; }
|
|
sockets.handleUpgrade(req, socket, head, ws => {
|
|
active = true;
|
|
ws.once('close', () => { active = false; });
|
|
handleTurn(ws, store);
|
|
});
|
|
});
|
|
server.listen(Number(PORT), HOST, () => console.log(`Voice server listening on ${HOST}:${PORT}`));
|