Add sn-node daemon: supervise yggdrasil sidecar + in-process exit
sn-node daemon [--config node.toml] [--check] runs one household node from a validated TOML config: generates the yggdrasil config with a persistent node key in the state dir (PrivateKeyPath takes precedence per the yggdrasil config reference, so the identity survives restarts), waits for the overlay address via the admin socket, then serves the sn-exit proxy in-process (or runs overlay-only in leech mode). SIGINT/SIGTERM stop the accept loop, SIGTERM the sidecar (5s grace, then SIGKILL); unexpected sidecar death shuts the daemon down with an error. sn-exit gains an additive serve_until() with a shutdown future; serve() keeps its behavior. Workspace: tokio gains process+signal, serde/toml added. 73 tests green, clippy clean.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
//! the exit only sees which host is contacted and how many bytes flow.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant};
|
||||
@@ -128,17 +129,38 @@ fn roll_window(
|
||||
|
||||
/// Accept loop. Runs until the listener errors fatally.
|
||||
pub async fn serve(config: ExitConfig, listener: TcpListener) -> Result<(), ExitError> {
|
||||
serve_until(config, listener, std::future::pending()).await
|
||||
}
|
||||
|
||||
/// Like [`serve`], but stops accepting when `shutdown` completes (used
|
||||
/// by the node daemon for kill-switch semantics). Connections already
|
||||
/// accepted keep running in the background; the caller or process exit
|
||||
/// owns them.
|
||||
pub async fn serve_until(
|
||||
config: ExitConfig,
|
||||
listener: TcpListener,
|
||||
shutdown: impl Future<Output = ()>,
|
||||
) -> Result<(), ExitError> {
|
||||
let config = Arc::new(config);
|
||||
let ledger = Arc::new(QuotaLedger::new());
|
||||
tokio::pin!(shutdown);
|
||||
loop {
|
||||
let (stream, peer) = listener.accept().await?;
|
||||
let config = Arc::clone(&config);
|
||||
let ledger = Arc::clone(&ledger);
|
||||
tokio::spawn(async move {
|
||||
if let Err(error) = handle_connection(stream, peer.ip(), config, ledger).await {
|
||||
tracing::debug!(%peer, "connection ended: {error}");
|
||||
tokio::select! {
|
||||
() = &mut shutdown => {
|
||||
tracing::info!("exit: accept loop stopped (shutdown)");
|
||||
return Ok(());
|
||||
}
|
||||
});
|
||||
accepted = listener.accept() => {
|
||||
let (stream, peer) = accepted?;
|
||||
let config = Arc::clone(&config);
|
||||
let ledger = Arc::clone(&ledger);
|
||||
tokio::spawn(async move {
|
||||
if let Err(error) = handle_connection(stream, peer.ip(), config, ledger).await {
|
||||
tracing::debug!(%peer, "connection ended: {error}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user