diff --git a/ecoos_daemon/ts/daemon/index.ts b/ecoos_daemon/ts/daemon/index.ts index 239f7b7..e2b051d 100644 --- a/ecoos_daemon/ts/daemon/index.ts +++ b/ecoos_daemon/ts/daemon/index.ts @@ -31,6 +31,7 @@ export class EcoDaemon { private logs: string[] = []; private swayStatus: ServiceStatus = { state: 'stopped' }; private chromiumStatus: ServiceStatus = { state: 'stopped' }; + private manualRestartUntil: number = 0; // Timestamp until which auto-restart is disabled constructor(config?: Partial) { this.config = { @@ -94,6 +95,9 @@ export class EcoDaemon { return { success: false, message: 'Cannot restart Chromium: Sway is not running' }; } + // Disable auto-restart for 15 seconds to prevent restart loop + this.manualRestartUntil = Date.now() + 15000; + try { // Stop existing Chromium await this.processManager.stopBrowser(); @@ -313,8 +317,9 @@ export class EcoDaemon { } // If Sway is running but Chromium died, restart Chromium + // Skip if manual restart is in progress (prevents restart loop) if (this.swayStatus.state === 'running' && this.chromiumStatus.state === 'running' - && !this.processManager.isBrowserRunning()) { + && !(await this.processManager.isBrowserRunning()) && Date.now() > this.manualRestartUntil) { this.log('Chromium process died, attempting restart...'); this.chromiumStatus = { state: 'starting', lastAttempt: new Date().toISOString() }; try { diff --git a/ecoos_daemon/ts/daemon/process-manager.ts b/ecoos_daemon/ts/daemon/process-manager.ts index dd59388..ba9b9bc 100644 --- a/ecoos_daemon/ts/daemon/process-manager.ts +++ b/ecoos_daemon/ts/daemon/process-manager.ts @@ -193,33 +193,23 @@ for_window [app_id="chromium-browser"] fullscreen enable }; // Chromium arguments for kiosk mode on Wayland + // Hardware acceleration is enabled where available but falls back gracefully const browserArgs = [ + // Wayland/Ozone configuration '--ozone-platform=wayland', '--enable-features=UseOzonePlatform', + // Kiosk mode settings '--kiosk', '--no-first-run', '--disable-infobars', '--disable-session-crashed-bubble', '--disable-restore-session-state', + '--noerrdialogs', + // Disable unnecessary features for kiosk '--disable-background-networking', '--disable-sync', '--disable-translate', - '--noerrdialogs', - // Required for VM/headless/sandboxed environments - '--no-sandbox', - '--disable-setuid-sandbox', - '--disable-dev-shm-usage', - // GPU/rendering flags for VM environments - '--disable-gpu', - '--disable-gpu-compositing', - '--disable-gpu-sandbox', - '--disable-software-rasterizer', - '--disable-accelerated-2d-canvas', - '--disable-accelerated-video-decode', - '--use-gl=swiftshader', - '--in-process-gpu', - // Disable features that may cause issues in kiosk mode - '--disable-features=TranslateUI,VizDisplayCompositor', + '--disable-features=TranslateUI', '--disable-hang-monitor', '--disable-breakpad', '--disable-component-update', @@ -281,8 +271,15 @@ for_window [app_id="chromium-browser"] fullscreen enable return this.swayProcess !== null; } - isBrowserRunning(): boolean { - return this.browserProcess !== null; + async isBrowserRunning(): Promise { + // Check if any chromium process is running (Chromium forks, so we can't just track the parent) + try { + const cmd = new Deno.Command('pgrep', { args: ['-f', 'chromium'], stdout: 'null', stderr: 'null' }); + const result = await cmd.output(); + return result.success; + } catch { + return false; + } } async stopSway(): Promise { @@ -335,12 +332,12 @@ for_window [app_id="chromium-browser"] fullscreen enable } })(); - // Monitor process exit + // Monitor process exit - only nullify if still the same process (prevents race condition on restart) process.status.then((status) => { console.log(`[${name}] Process exited with code ${status.code}`); - if (name === 'sway') { + if (name === 'sway' && this.swayProcess === process) { this.swayProcess = null; - } else if (name === 'chromium') { + } else if (name === 'chromium' && this.browserProcess === process) { this.browserProcess = null; } }); diff --git a/ecoos_daemon/ts/ui/server.ts b/ecoos_daemon/ts/ui/server.ts index bd1f576..468c206 100644 --- a/ecoos_daemon/ts/ui/server.ts +++ b/ecoos_daemon/ts/ui/server.ts @@ -5,6 +5,7 @@ */ import type { EcoDaemon } from '../daemon/index.ts'; +import { VERSION } from '../version.ts'; export class UIServer { private port: number; @@ -137,7 +138,19 @@ export class UIServer { padding: 20px; } .container { max-width: 1200px; margin: 0 auto; } - h1 { font-size: 24px; margin-bottom: 20px; } + .header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + } + h1 { font-size: 24px; margin: 0; } + .clock { + font-size: 18px; + font-weight: 500; + color: var(--text); + font-variant-numeric: tabular-nums; + } .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); @@ -240,7 +253,10 @@ export class UIServer {
-

EcoOS Management

+
+

EcoOS Management v${VERSION}

+
+

Services

@@ -528,6 +544,24 @@ export class UIServer { updateStatus(JSON.parse(e.data)); } catch {} }; + + // Clock update + function updateClock() { + const now = new Date(); + const options = { + weekday: 'short', + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: false + }; + document.getElementById('clock').textContent = now.toLocaleString('en-US', options); + } + updateClock(); + setInterval(updateClock, 1000); `; diff --git a/ecoos_daemon/ts/version.ts b/ecoos_daemon/ts/version.ts new file mode 100644 index 0000000..6fa18df --- /dev/null +++ b/ecoos_daemon/ts/version.ts @@ -0,0 +1 @@ +export const VERSION = "0.1.1"; diff --git a/isobuild/config/includes.chroot/opt/eco/bin/eco-daemon b/isobuild/config/includes.chroot/opt/eco/bin/eco-daemon index 7016f6e..ceb084a 100755 Binary files a/isobuild/config/includes.chroot/opt/eco/bin/eco-daemon and b/isobuild/config/includes.chroot/opt/eco/bin/eco-daemon differ diff --git a/isotest/run-test.sh b/isotest/run-test.sh index d564a20..d3c478f 100755 --- a/isotest/run-test.sh +++ b/isotest/run-test.sh @@ -48,28 +48,28 @@ else echo "KVM not available, using software emulation (slower)" fi -# Start QEMU headless with VNC and serial console +# Start QEMU with VirtIO-GPU (VirGL OpenGL acceleration) and serial console > "$SERIAL_LOG" # Clear old log qemu-system-x86_64 \ $KVM_OPTS \ -m 4G \ - -smp 2 \ + -smp 4 \ -bios /usr/share/qemu/OVMF.fd \ -drive file="$ISO_PATH",media=cdrom \ -drive file="$DISK_PATH",format=qcow2,if=virtio \ - -vga qxl \ + -device virtio-vga \ -display none \ - -vnc :0 \ + -spice port=5930,disable-ticketing=on \ -serial unix:"$SERIAL_SOCK",server,nowait \ -monitor unix:"$MONITOR_SOCK",server,nowait \ -nic user,model=virtio-net-pci,hostfwd=tcp::3006-:3006,hostfwd=tcp::2222-:22 \ - -daemonize \ - -pidfile "$PID_FILE" + -pidfile "$PID_FILE" & echo "" +sleep 1 echo "=== EcoOS Test VM Started ===" -echo "PID: $(cat $PID_FILE)" -echo "VNC: localhost:5900" +echo "PID: $(cat $PID_FILE 2>/dev/null || echo 'running')" +echo "SPICE: spicy -h localhost -p 5930" echo "Serial Log: $SERIAL_LOG" echo "Management UI: http://localhost:3006" echo "" diff --git a/package.json b/package.json index 28835a4..a9db80d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "@ecobridge/eco-os", + "version": "0.1.1", "private": true, "scripts": { - "build": "pnpm run daemon:bundle && cp ecoos_daemon/bundle/eco-daemon isobuild/config/includes.chroot/opt/eco/bin/ && mkdir -p .nogit/iso && docker build --no-cache -t ecoos-builder -f isobuild/Dockerfile . && docker run --rm --privileged -v $(pwd)/.nogit/iso:/output ecoos-builder", + "build": "npm version patch --no-git-tag-version && node -e \"const v=require('./package.json').version; require('fs').writeFileSync('ecoos_daemon/ts/version.ts', 'export const VERSION = \\\"'+v+'\\\";\\n');\" && pnpm run daemon:bundle && cp ecoos_daemon/bundle/eco-daemon isobuild/config/includes.chroot/opt/eco/bin/ && mkdir -p .nogit/iso && docker build --no-cache -t ecoos-builder -f isobuild/Dockerfile . && docker run --rm --privileged -v $(pwd)/.nogit/iso:/output ecoos-builder", "daemon:dev": "cd ecoos_daemon && deno run --allow-all --watch mod.ts", "daemon:start": "cd ecoos_daemon && deno run --allow-all mod.ts", "daemon:bundle": "cd ecoos_daemon && deno compile --allow-all --output bundle/eco-daemon mod.ts",