/** * UI Server * * HTTP server for the management UI on port 3006 */ import type { EcoDaemon } from '../daemon/index.ts'; export class UIServer { private port: number; private daemon: EcoDaemon; private clients: Set = new Set(); constructor(port: number, daemon: EcoDaemon) { this.port = port; this.daemon = daemon; } async start(): Promise { Deno.serve({ port: this.port, hostname: '0.0.0.0' }, (req) => this.handleRequest(req) ); console.log(`Management UI running on http://0.0.0.0:${this.port}`); } private async handleRequest(req: Request): Promise { const url = new URL(req.url); const path = url.pathname; // Handle WebSocket upgrade if (path === '/ws') { return this.handleWebSocket(req); } // API routes if (path.startsWith('/api/')) { return this.handleApi(req, path); } // Static files / UI if (path === '/' || path === '/index.html') { return this.serveHtml(); } return new Response('Not Found', { status: 404 }); } private handleWebSocket(req: Request): Response { const { socket, response } = Deno.upgradeWebSocket(req); socket.onopen = () => { this.clients.add(socket); console.log('WebSocket client connected'); }; socket.onclose = () => { this.clients.delete(socket); console.log('WebSocket client disconnected'); }; socket.onerror = (e) => { console.error('WebSocket error:', e); this.clients.delete(socket); }; return response; } broadcast(data: unknown): void { const message = JSON.stringify(data); for (const client of this.clients) { try { client.send(message); } catch { this.clients.delete(client); } } } private async handleApi(req: Request, path: string): Promise { const headers = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', }; if (path === '/api/status') { const status = await this.daemon.getStatus(); return new Response(JSON.stringify(status), { headers }); } if (path === '/api/logs') { const logs = this.daemon.getLogs(); return new Response(JSON.stringify({ logs }), { headers }); } if (path === '/api/reboot' && req.method === 'POST') { const result = await this.daemon.rebootSystem(); return new Response(JSON.stringify(result), { headers }); } if (path === '/api/restart-chromium' && req.method === 'POST') { const result = await this.daemon.restartChromium(); return new Response(JSON.stringify(result), { headers }); } return new Response(JSON.stringify({ error: 'Not Found' }), { status: 404, headers, }); } private serveHtml(): Response { const html = ` EcoOS Management

EcoOS Management

Services

Sway Compositor
Chromium Browser

CPU

Model
-
Cores
-
Usage
-

Memory

Used / Total
-

Network

Disks

System

Hostname
-
Uptime
-
GPU
-

Controls

Input Devices

Speakers

Microphones

Logs

`; return new Response(html, { headers: { 'Content-Type': 'text/html; charset=utf-8' }, }); } }