diff --git a/kiosk/src/ui.rs b/kiosk/src/ui.rs index 12fda3a..94d7dc5 100644 --- a/kiosk/src/ui.rs +++ b/kiosk/src/ui.rs @@ -306,6 +306,7 @@ fn activate(app: &Application) { firmware::mark_firmware_applied(); mark_kiosk_healthy(); mark_rauc_slot_good(); + cleanup_stale_files(); first_iter = false; } maybe_apply_os_update(&server, &key, &tx_progress); @@ -496,10 +497,37 @@ fn mark_rauc_slot_good() { .status(); } +fn cleanup_stale_files() { + // Stale OS update downloads in staging dir. + let staging = std::path::Path::new("/var/lib/betterframe/tmp"); + if staging.is_dir() { + if let Ok(entries) = fs::read_dir(staging) { + let cutoff = std::time::SystemTime::now() - Duration::from_secs(24 * 3600); + for entry in entries.flatten() { + let Ok(meta) = entry.metadata() else { continue }; + let old = meta.modified().map(|m| m < cutoff).unwrap_or(false); + if old { + info!("cleanup: removing stale staging file {}", entry.path().display()); + let _ = fs::remove_file(entry.path()); + } + } + } + } + // Old firmware .prev binary (only keep if < 7 days old as rollback safety). + let prev = std::path::Path::new("/opt/betterframe/kiosk/betterframe-kiosk.prev"); + if prev.exists() { + let cutoff = std::time::SystemTime::now() - Duration::from_secs(7 * 24 * 3600); + if let Ok(meta) = prev.metadata() { + if meta.modified().map(|m| m < cutoff).unwrap_or(false) { + info!("cleanup: removing old firmware .prev"); + let _ = fs::remove_file(prev); + } + } + } +} + /// Ask the server whether a full-OS RAUC bundle is available for this -/// kiosk. On hit, download + sha256 + `rauc install` + reboot. On miss or -/// error: log + keep running. Gated by BF_ENABLE_OS_OTA=1 (default OFF -/// for dev kiosks running a non-A/B image). +/// kiosk. fn maybe_apply_os_update(server_url: &str, kiosk_key: &str, tx: &mpsc::Sender) { if std::env::var("BF_ENABLE_OS_OTA").as_deref() != Ok("1") { return; diff --git a/server/src/plugins/service-api-http/index.ts b/server/src/plugins/service-api-http/index.ts index 039560e..36f2e95 100644 --- a/server/src/plugins/service-api-http/index.ts +++ b/server/src/plugins/service-api-http/index.ts @@ -695,15 +695,32 @@ function registerKioskRoutes( } } - const eventId = await repo.insertEvent({ - source_kiosk_id: kiosk.id, - source_camera_id: body.camera_id ?? null, - source_type: (body.source_type as any) ?? "system", - topic: body.topic, - property_op: body.property_op ?? null, - payload: body.payload ?? {}, - forwarded_to_nodered: false, - }); + let eventId: string; + try { + eventId = await repo.insertEvent({ + source_kiosk_id: kiosk.id, + source_camera_id: body.camera_id ?? null, + source_type: (body.source_type as any) ?? "system", + topic: body.topic, + property_op: body.property_op ?? null, + payload: body.payload ?? {}, + forwarded_to_nodered: false, + }); + } catch (err: any) { + if (err?.code === "23503") { + eventId = await repo.insertEvent({ + source_kiosk_id: kiosk.id, + source_camera_id: null, + source_type: (body.source_type as any) ?? "system", + topic: body.topic, + property_op: body.property_op ?? null, + payload: body.payload ?? {}, + forwarded_to_nodered: false, + }); + } else { + throw err; + } + } // Side-effect: persist active layout per display so the admin UI can // surface "currently showing X" without having to query event_log.