diff --git a/Cargo.lock b/Cargo.lock index 3b83ae6..e370d4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10904,6 +10904,7 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" name = "tahuantinsuyu" version = "0.1.0" dependencies = [ + "brahman-sidecar", "directories", "gpui", "serde_json", diff --git a/crates/apps/tahuantinsuyu/Cargo.toml b/crates/apps/tahuantinsuyu/Cargo.toml index 3732241..f6e2994 100644 --- a/crates/apps/tahuantinsuyu/Cargo.toml +++ b/crates/apps/tahuantinsuyu/Cargo.toml @@ -15,6 +15,7 @@ tahuantinsuyu-panel = { path = "../../modules/tahuantinsuyu/tahuantinsuyu-panel" tahuantinsuyu-store = { path = "../../modules/tahuantinsuyu/tahuantinsuyu-store" } tahuantinsuyu-theme = { path = "../../modules/tahuantinsuyu/tahuantinsuyu-theme" } tahuantinsuyu-tree = { path = "../../modules/tahuantinsuyu/tahuantinsuyu-tree" } +brahman-sidecar = { path = "../../shared/brahman-sidecar" } yahweh-bus = { workspace = true } yahweh-core = { workspace = true } diff --git a/crates/apps/tahuantinsuyu/src/shell.rs b/crates/apps/tahuantinsuyu/src/shell.rs index c6cdea4..2a680c0 100644 --- a/crates/apps/tahuantinsuyu/src/shell.rs +++ b/crates/apps/tahuantinsuyu/src/shell.rs @@ -49,6 +49,18 @@ use yahweh_widget_theme_switcher::theme_switcher; const TREE_WIDTH: f32 = 280.0; const PANEL_HEIGHT: f32 = 180.0; +/// Status del broker brahman tal como lo vimos en el último ping. +/// Se refresca cada 30 segundos desde un background task. +#[derive(Clone, Debug)] +pub enum BrahmanStatus { + /// Aún no probamos (boot, primer ciclo). + Pending, + /// Connect OK al broker, devolvió la lista de sessions activas. + Connected { session_count: usize }, + /// Connect falló — broker no escucha en el socket o tomó timeout. + Offline { reason: String }, +} + pub struct Shell { store: Store, #[allow(dead_code)] @@ -63,6 +75,9 @@ pub struct Shell { /// Splitter vertical entre el main_row (arriba) y el panel de /// control (abajo). outer_split: Entity, + /// Último estado conocido del broker brahman — refrescado cada + /// 30s desde el background task. + brahman_status: BrahmanStatus, current_chart: Option, current_offset_minutes: i64, /// Estado de los módulos overlay (transit, progression, …) por @@ -162,15 +177,52 @@ impl Shell { panel, main_split, outer_split, + brahman_status: BrahmanStatus::Pending, current_chart: None, current_offset_minutes: 0, module_configs: HashMap::new(), render_seq: 0, }; shell.refresh_chart_options(cx); + shell.spawn_brahman_status_loop(cx); shell } + /// Loop que cada 30s pregunta al broker la lista de sessions + /// activas y actualiza `brahman_status`. El cómputo bloqueante + /// (list_sessions_blocking abre su propio tokio runtime) corre en + /// el background_executor — no bloquea el UI thread. Cuando llega + /// el resultado, el `this.update` dispara cx.notify para repintar + /// el badge del header. + fn spawn_brahman_status_loop(&self, cx: &mut Context) { + cx.spawn(async move |this, cx| { + loop { + let result = cx + .background_executor() + .spawn(async { + brahman_sidecar::list_sessions_blocking("tahuantinsuyu-observer") + }) + .await; + let _ = this.update(cx, |this, cx| { + this.brahman_status = match result { + Ok(list) => BrahmanStatus::Connected { + session_count: list.entries.len(), + }, + Err(e) => BrahmanStatus::Offline { + reason: format!("{:?}", e), + }, + }; + cx.notify(); + }); + let timer = cx + .background_executor() + .timer(std::time::Duration::from_secs(30)); + timer.await; + } + }) + .detach(); + } + /// Recarga la lista de opciones para los `Control::ChartPicker` y /// la pushea al panel. Llamado al boot + tras cada /// `TreeEvent::HierarchyChanged`. @@ -844,6 +896,29 @@ impl Render for Shell { fn render(&mut self, _w: &mut Window, cx: &mut Context) -> impl IntoElement { let theme = Theme::global(cx).clone(); + // Badge del estado del broker brahman — pequeña pill con + // color según el estado actual del ping cada-30s. + let (badge_text, badge_color) = match &self.brahman_status { + BrahmanStatus::Pending => ("Brahman · …".to_string(), theme.fg_muted), + BrahmanStatus::Connected { session_count } => ( + format!("Brahman ✓ {} sessions", session_count), + theme.accent, + ), + BrahmanStatus::Offline { .. } => { + ("Brahman · offline".to_string(), theme.fg_disabled) + } + }; + let brahman_badge = div() + .px(px(8.0)) + .py(px(2.0)) + .rounded(px(8.0)) + .bg(theme.bg_panel_alt.clone()) + .border_1() + .border_color(theme.border) + .text_size(px(10.0)) + .text_color(badge_color) + .child(SharedString::from(badge_text)); + let header = div() .h(px(34.0)) .px(px(12.0)) @@ -866,6 +941,7 @@ impl Render for Shell { .child("estudio de astrología profesional"), ) .child(div().flex_grow()) + .child(brahman_badge) .child(theme_switcher(cx)); let body = div()