huskies: merge 760

This commit is contained in:
dave
2026-04-28 00:17:44 +00:00
parent 63ce7b9ec3
commit d1a2393b32
4 changed files with 221 additions and 3 deletions
+47
View File
@@ -26,6 +26,21 @@ use std::sync::Arc;
use tokio::sync::Mutex as TokioMutex;
use tokio::sync::RwLock;
// ── Status event broadcaster ────────────────────────────────────────────────
/// Capacity of the gateway status event broadcast channel.
const EVENT_CHANNEL_CAPACITY: usize = 64;
/// A status event pushed by a project node and fanned out to all local
/// subscribers (e.g. the Web UI, notification forwarders).
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct GatewayStatusEvent {
/// The project name that emitted this event.
pub project: String,
/// The pipeline event payload.
pub event: crate::service::events::StoredEvent,
}
// ── Error type ──────────────────────────────────────────────────────────────
/// Typed errors returned by `service::gateway` functions.
@@ -93,6 +108,10 @@ pub struct GatewayState {
pub port: u16,
/// Abort handle for the running Matrix bot task (if any).
pub bot_handle: Arc<TokioMutex<Option<tokio::task::AbortHandle>>>,
/// Broadcast sender for [`GatewayStatusEvent`]s pushed by project nodes.
///
/// Call `event_tx.subscribe()` to obtain a receiver for outbound fan-out.
pub event_tx: tokio::sync::broadcast::Sender<GatewayStatusEvent>,
}
impl GatewayState {
@@ -107,6 +126,7 @@ impl GatewayState {
) -> Result<Self, String> {
let first = config::validate_config(&gateway_config)?;
let agents = io::load_agents(&config_dir);
let (event_tx, _) = tokio::sync::broadcast::channel(EVENT_CHANNEL_CAPACITY);
Ok(Self {
projects: Arc::new(RwLock::new(gateway_config.projects)),
active_project: Arc::new(RwLock::new(first)),
@@ -116,6 +136,7 @@ impl GatewayState {
config_dir,
port,
bot_handle: Arc::new(TokioMutex::new(None)),
event_tx,
})
}
@@ -380,6 +401,32 @@ pub async fn health_check_all(state: &GatewayState) -> (bool, BTreeMap<String, &
(all_healthy, statuses)
}
/// Broadcast a status event received from a project node to all local subscribers.
///
/// Returns the number of active receivers that received the event.
/// A return value of zero means no subscribers are currently connected.
pub fn broadcast_status_event(
state: &GatewayState,
project: String,
event: crate::service::events::StoredEvent,
) -> usize {
let msg = GatewayStatusEvent { project, event };
state.event_tx.send(msg).unwrap_or(0)
}
/// Subscribe to the gateway's status event stream.
///
/// Returns a broadcast receiver that will yield [`GatewayStatusEvent`]s as
/// project nodes push them. If the receiver falls behind (more than
/// [`EVENT_CHANNEL_CAPACITY`] events are queued), it will receive a
/// [`tokio::sync::broadcast::error::RecvError::Lagged`] error; callers
/// should discard lagged events and continue.
pub fn subscribe_status_events(
state: &GatewayState,
) -> tokio::sync::broadcast::Receiver<GatewayStatusEvent> {
state.event_tx.subscribe()
}
/// Save bot config and restart the bot.
pub async fn save_bot_config_and_restart(state: &GatewayState, content: &str) -> Result<(), Error> {
io::write_bot_config(&state.config_dir, content).map_err(Error::Config)?;