feat: wire all tasks together in main with signal handling
Made-with: Cursor
This commit is contained in:
@@ -12,7 +12,7 @@ pub struct BridgeConfig {
|
||||
pub control: ControlConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct IrcConfig {
|
||||
pub server: String,
|
||||
#[serde(default = "default_irc_port")]
|
||||
|
||||
126
src/main.rs
126
src/main.rs
@@ -9,6 +9,128 @@ mod router;
|
||||
mod webhook;
|
||||
mod websocket;
|
||||
|
||||
fn main() {
|
||||
println!("owncast-irc-bridge");
|
||||
use std::path::PathBuf;
|
||||
use std::time::Instant;
|
||||
|
||||
use clap::Parser;
|
||||
use tokio::sync::{mpsc, watch};
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "owncast-irc-bridge")]
|
||||
#[command(about = "Bidirectional chat bridge between Owncast and IRC")]
|
||||
struct Cli {
|
||||
/// Path to config file
|
||||
#[arg(short, long, default_value = "config.toml")]
|
||||
config: PathBuf,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
|
||||
)
|
||||
.init();
|
||||
|
||||
let cli = Cli::parse();
|
||||
let config = config::BridgeConfig::load(&cli.config)?;
|
||||
let access_token = config.owncast_access_token()?;
|
||||
|
||||
info!("Starting owncast-irc-bridge");
|
||||
|
||||
let start_time = Instant::now();
|
||||
let (shutdown_tx, shutdown_rx) = watch::channel(false);
|
||||
|
||||
let (event_tx, event_rx) = mpsc::channel(256);
|
||||
let (irc_outbound_tx, irc_outbound_rx) = mpsc::channel(256);
|
||||
let (state_tx, state_rx) = mpsc::channel(32);
|
||||
let (control_tx, control_rx) = mpsc::channel(32);
|
||||
|
||||
let api_client = owncast_api::OwncastApiClient::new(
|
||||
config.owncast.url.clone(),
|
||||
access_token,
|
||||
);
|
||||
|
||||
let irc_config = config.irc.clone();
|
||||
let irc_event_tx = event_tx.clone();
|
||||
let irc_shutdown = shutdown_rx.clone();
|
||||
let _irc_handle = tokio::spawn(async move {
|
||||
irc_task::run_irc_task(irc_config, irc_event_tx, irc_outbound_rx, irc_shutdown).await;
|
||||
});
|
||||
|
||||
let webhook_port = config.owncast.webhook_port;
|
||||
let webhook_event_tx = event_tx.clone();
|
||||
let _webhook_handle = tokio::spawn(async move {
|
||||
if let Err(e) = webhook::run_webhook_server(webhook_port, webhook_event_tx).await {
|
||||
tracing::error!(error = %e, "Webhook server failed");
|
||||
}
|
||||
});
|
||||
|
||||
let _ws_handle = if config.owncast.websocket_enabled {
|
||||
let ws_url = config.owncast.url.clone();
|
||||
let ws_event_tx = event_tx.clone();
|
||||
let ws_shutdown = shutdown_rx.clone();
|
||||
Some(tokio::spawn(async move {
|
||||
websocket::run_websocket_task(ws_url, ws_event_tx, ws_shutdown).await;
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let health_api = owncast_api::OwncastApiClient::new(
|
||||
config.owncast.url.clone(),
|
||||
String::new(),
|
||||
);
|
||||
let health_interval = std::time::Duration::from_secs(config.owncast.health_poll_interval_secs);
|
||||
let health_shutdown = shutdown_rx.clone();
|
||||
let _health_handle = tokio::spawn(async move {
|
||||
health::run_health_poller(&health_api, state_tx, health_interval, health_shutdown).await;
|
||||
});
|
||||
|
||||
let control_socket_path = config.control.socket_path.clone();
|
||||
let _control_handle = tokio::spawn(async move {
|
||||
if let Err(e) = control::run_control_socket(&control_socket_path, control_tx).await {
|
||||
tracing::error!(error = %e, "Control socket failed");
|
||||
}
|
||||
});
|
||||
|
||||
let sig_shutdown_tx = shutdown_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut sigterm = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
|
||||
.expect("Failed to register SIGTERM handler");
|
||||
let mut sighup = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::hangup())
|
||||
.expect("Failed to register SIGHUP handler");
|
||||
|
||||
tokio::select! {
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
info!("SIGINT received, shutting down");
|
||||
let _ = sig_shutdown_tx.send(true);
|
||||
}
|
||||
_ = sigterm.recv() => {
|
||||
info!("SIGTERM received, shutting down");
|
||||
let _ = sig_shutdown_tx.send(true);
|
||||
}
|
||||
_ = sighup.recv() => {
|
||||
info!("SIGHUP received (reconnect not yet wired)");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router::run_router(
|
||||
config.bridge,
|
||||
config.owncast.url,
|
||||
api_client,
|
||||
event_rx,
|
||||
irc_outbound_tx,
|
||||
state_rx,
|
||||
control_rx,
|
||||
shutdown_tx,
|
||||
start_time,
|
||||
)
|
||||
.await;
|
||||
|
||||
info!("Bridge shutting down");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user