huskies: merge 648_story_migrate_discord_transport_to_status_broadcaster

This commit is contained in:
dave
2026-04-27 13:57:19 +00:00
parent 9040d18f50
commit 6c8043d866
3 changed files with 58 additions and 0 deletions
+15
View File
@@ -63,6 +63,13 @@ pub struct ProjectConfig {
/// Default: `true`.
#[serde(default = "default_slack_status_consumer")]
pub slack_status_consumer: bool,
/// Whether the Discord bot subscribes to the status broadcaster and forwards
/// pipeline events to its configured channels.
/// Set to `false` to silence Discord status notifications without affecting
/// other consumers (web UI, Matrix, Slack, WhatsApp, agent context).
/// Default: `true`.
#[serde(default = "default_discord_status_consumer")]
pub discord_status_consumer: bool,
/// IANA timezone name (e.g. `"Europe/London"`, `"America/New_York"`).
/// When set, timer HH:MM inputs are interpreted in this timezone instead
/// of the container/host local time. Falls back to `chrono::Local` when absent.
@@ -155,6 +162,10 @@ fn default_slack_status_consumer() -> bool {
true
}
fn default_discord_status_consumer() -> bool {
true
}
fn default_max_mesh_peers() -> usize {
3
}
@@ -287,6 +298,7 @@ impl Default for ProjectConfig {
web_ui_status_consumer: default_web_ui_status_consumer(),
matrix_status_consumer: default_matrix_status_consumer(),
slack_status_consumer: default_slack_status_consumer(),
discord_status_consumer: default_discord_status_consumer(),
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -371,6 +383,7 @@ impl ProjectConfig {
web_ui_status_consumer: default_web_ui_status_consumer(),
matrix_status_consumer: default_matrix_status_consumer(),
slack_status_consumer: default_slack_status_consumer(),
discord_status_consumer: default_discord_status_consumer(),
timezone: legacy.timezone,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -406,6 +419,7 @@ impl ProjectConfig {
web_ui_status_consumer: default_web_ui_status_consumer(),
matrix_status_consumer: default_matrix_status_consumer(),
slack_status_consumer: default_slack_status_consumer(),
discord_status_consumer: default_discord_status_consumer(),
timezone: legacy.timezone,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -429,6 +443,7 @@ impl ProjectConfig {
web_ui_status_consumer: default_web_ui_status_consumer(),
matrix_status_consumer: default_matrix_status_consumer(),
slack_status_consumer: default_slack_status_consumer(),
discord_status_consumer: default_discord_status_consumer(),
timezone: legacy.timezone,
rendezvous: None,
trusted_keys: Vec::new(),
+31
View File
@@ -809,6 +809,37 @@ async fn main() -> Result<(), std::io::Error> {
watcher_rx_for_discord,
root.clone(),
);
// Subscribe to the status broadcaster if the discord_status_consumer toggle
// is enabled (default: true). Formats each StatusEvent via the common
// formatter and sends the resulting text to all configured Discord channels.
// The task exits automatically when the broadcaster is dropped on shutdown.
{
use crate::service::status::format::format_status_event;
let status_enabled = config::ProjectConfig::load(root)
.map(|c| c.discord_status_consumer)
.unwrap_or(true);
if status_enabled {
let mut sub = ctx.services.status.subscribe();
let transport = Arc::clone(&ctx.transport) as Arc<dyn crate::chat::ChatTransport>;
let channels: Vec<String> = ctx.channel_ids.iter().cloned().collect();
tokio::spawn(async move {
while let Some(event) = sub.recv().await {
let plain = format_status_event(&event);
for channel in &channels {
if let Err(e) = transport.send_message(channel, &plain, "").await {
crate::slog!(
"[discord] Failed to send status event to {channel}: {e}"
);
}
}
}
crate::slog!("[discord] Status subscriber task exiting — broadcaster dropped");
});
}
}
} else {
drop(watcher_rx_for_discord);
}
+12
View File
@@ -531,6 +531,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -563,6 +564,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -595,6 +597,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -627,6 +630,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -658,6 +662,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -696,6 +701,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -775,6 +781,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -812,6 +819,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -896,6 +904,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -936,6 +945,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -966,6 +976,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),
@@ -1002,6 +1013,7 @@ mod tests {
web_ui_status_consumer: true,
matrix_status_consumer: true,
slack_status_consumer: true,
discord_status_consumer: true,
timezone: None,
rendezvous: None,
trusted_keys: Vec::new(),