peerman 0.2.0

DN42 peer manager with WireGuard, BIRD, and cluster support
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use sqlx::SqlitePool;
use tokio_util::sync::CancellationToken;

use crate::app_state::PeerState;

/// Spawn the debounced WG+BIRD config apply task.
///
/// Checks the dirty flag every 5 seconds. When set, applies WG and BIRD
/// configurations and clears the flag.
pub fn spawn_config_apply(
    config_dirty: Arc<AtomicBool>,
    peer_state: PeerState,
    listen_addr: String,
    pool: SqlitePool,
    shutdown: CancellationToken,
) {
    tokio::spawn(async move {
        let mut interval = tokio::time::interval(Duration::from_secs(5));
        interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
        loop {
            tokio::select! {
                _ = shutdown.cancelled() => {
                    tracing::info!("Config apply task shutting down");
                    return;
                }
                _ = interval.tick() => {}
            }
            if config_dirty.swap(false, Ordering::Relaxed) {
                tracing::info!("Config dirty flag set, applying WG+BIRD configs...");
                if let Err(e) =
                    crate::grpc::peer_service::apply_wg_bird(&peer_state, &listen_addr, &pool).await
                {
                    tracing::warn!("Auto-apply WG+BIRD failed: {e}");
                }
            }
        }
    });
}