BetterFrame/kiosk/src/main.rs

72 lines
2 KiB
Rust
Raw Normal View History

mod at_rest;
mod axiom;
mod bundle;
mod cec;
mod firmware;
mod gpio;
mod hwmon;
mod local_server;
mod onvif_events;
mod os_update;
mod pipeline;
feat(remote-debug): journal streaming + secure terminal via WebSocket Kiosk side (remote_debug.rs + ws_client.rs refactor): - Journal streaming: server sends journal-start → kiosk spawns journalctl -f, pipes lines back as journal-line messages via WS. journal-stop kills the process. On-demand, not always-on. - Terminal: server sends terminal-request → kiosk checks lockout + firmware_channel == "dev" → generates 8-char code displayed on screen as fullscreen overlay (NOT logged) → server relays admin's code via terminal-auth → kiosk validates with constant-time compare → on success spawns bash, relays I/O as base64 terminal-data. - Lockout: 3 failed codes per boot → lockout_count++. 3 lockouts (9 total failures) → permanent (reflash only). Reboot resets attempt counter, not lockout counter. Successful pairing resets all. - ws_client.rs rewritten with split reader/writer + tokio::select! for multiplexing incoming WS messages with outbound journal/terminal data from sync threads. Server side (coordinator-ws + routes-admin): - New admin debug WS endpoint: /ws/admin/debug/:kioskId. Authenticated via admin API key (query param) or session cookie. Relays messages bidirectionally between admin browser ↔ kiosk. - Admin pages: /admin/kiosks/:id/logs (journal viewer with start/ stop/clear) and /admin/kiosks/:id/terminal (code entry + terminal area). Both open in new tabs from the kiosk detail page. - Angie proxy config updated with /ws/admin/debug/ location block. Security: - Terminal only on dev channel - Code displayed physically on screen, never logged or stored server-side - Lockout: 3/boot, 3 lockouts = permanent, pairing resets - Kiosk responds "locked" without specifying which lockout triggered
2026-05-22 18:13:39 +00:00
mod remote_debug;
mod server;
mod ui;
mod ws_client;
pub use ui::WorkerMsg;
pub enum ServerMsg {
ReloadBundle,
Standby(Option<u32>),
Wake(Option<u32>),
/// Some(0..=255) = manual PWM. None = restore auto.
Fan(Option<u32>),
/// Switch to a specific layout by ID, optionally scoped to one display.
SwitchLayout {
display_id: Option<u32>,
layout_id: u32,
},
/// Server-pushed "go check for a firmware update now".
FirmwareCheck,
/// Server-pushed "go check for an OS update now".
OsCheck,
feat(remote-debug): journal streaming + secure terminal via WebSocket Kiosk side (remote_debug.rs + ws_client.rs refactor): - Journal streaming: server sends journal-start → kiosk spawns journalctl -f, pipes lines back as journal-line messages via WS. journal-stop kills the process. On-demand, not always-on. - Terminal: server sends terminal-request → kiosk checks lockout + firmware_channel == "dev" → generates 8-char code displayed on screen as fullscreen overlay (NOT logged) → server relays admin's code via terminal-auth → kiosk validates with constant-time compare → on success spawns bash, relays I/O as base64 terminal-data. - Lockout: 3 failed codes per boot → lockout_count++. 3 lockouts (9 total failures) → permanent (reflash only). Reboot resets attempt counter, not lockout counter. Successful pairing resets all. - ws_client.rs rewritten with split reader/writer + tokio::select! for multiplexing incoming WS messages with outbound journal/terminal data from sync threads. Server side (coordinator-ws + routes-admin): - New admin debug WS endpoint: /ws/admin/debug/:kioskId. Authenticated via admin API key (query param) or session cookie. Relays messages bidirectionally between admin browser ↔ kiosk. - Admin pages: /admin/kiosks/:id/logs (journal viewer with start/ stop/clear) and /admin/kiosks/:id/terminal (code entry + terminal area). Both open in new tabs from the kiosk detail page. - Angie proxy config updated with /ws/admin/debug/ location block. Security: - Terminal only on dev channel - Code displayed physically on screen, never logged or stored server-side - Lockout: 3/boot, 3 lockouts = permanent, pairing resets - Kiosk responds "locked" without specifying which lockout triggered
2026-05-22 18:13:39 +00:00
/// Show terminal auth code on screen (overlay).
ShowTerminalCode(String),
/// Dismiss the terminal code overlay.
DismissTerminalCode,
}
use gstreamer::prelude::PluginFeatureExtManual;
use gtk4::prelude::{ApplicationExt, ApplicationExtManual};
use tracing::info;
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
fn main() {
let env_filter = EnvFilter::from_default_env()
.add_directive("betterframe_kiosk=info".parse().unwrap());
let registry = tracing_subscriber::registry()
.with(env_filter)
.with(tracing_subscriber::fmt::layer());
if let Some(axiom_layer) = axiom::AxiomLayer::new() {
info!("axiom logging enabled");
registry.with(axiom_layer).init();
} else {
registry.init();
}
gstreamer::init().expect("Failed to init GStreamer");
// Demote Pi5 hw H265 decoder — rejects non-standard resolutions like 960x1080
if let Some(factory) = gstreamer::ElementFactory::find("v4l2slh265dec") {
factory.set_rank(gstreamer::Rank::NONE);
info!("demoted v4l2slh265dec to NONE (sw fallback)");
}
let app = ui::build_app();
// Pass empty args to GTK — server URL handled via env or argv directly
2026-05-10 18:13:01 +00:00
app.set_flags(gtk4::gio::ApplicationFlags::NON_UNIQUE);
std::process::exit(app.run_with_args::<&str>(&[]).into());
}