uxar 0.1.3

Opinionated Rust web framework built on Axum for Postgres-backed JSON APIs
Documentation

use std::{path::PathBuf, sync::Arc};
use notify::{RecursiveMode, Watcher};
use tokio::signal;
use crate::{SiteError, notifiers::CancellationNotifier};
use tracing;


pub async fn watch_file(path: PathBuf) -> Result<(), SiteError> {
    let (tx, mut rx) = tokio::sync::mpsc::channel::<notify::Result<notify::Event>>(1024);
    let mut watcher = notify::recommended_watcher(move |res| {
        tx.try_send(res).ok();
    })
    .map_err(|e| SiteError::FileWatchError(format!("Failed to create watcher: {}", e)))?;
    watcher.watch(path.as_path(), RecursiveMode::NonRecursive)
        .map_err(|e| SiteError::FileWatchError(format!("Failed to watch file: {}", e)))?;
    rx.recv().await;
    Ok(())
}


async fn reload_signal(touch_reload: Option<String>) -> Result<(), SiteError> {
    if let Some(path) = touch_reload {
        let path = PathBuf::from(path);
        if path.exists() {
            return watch_file(path).await;
        }
    }
    return futures::future::pending().await;
}


async fn interrupt_signal() {
    signal::ctrl_c()
        .await
        .expect("failed to install Ctrl+C handler");
}


pub async fn shutdown_signal(touch_reload: Option<String>, notifier: CancellationNotifier) {
    tokio::select! {
        _ = notifier.notified() => {
            tracing::info!("Shutdown signal received, shutting down gracefully");
        },
        _ = interrupt_signal() => {
            tracing::info!("Ctrl+C received, shutting down gracefully");
            notifier.notify_waiters();
        },
        touch = reload_signal(touch_reload) => {
            if let Err(e) = touch {
                tracing::error!("Error during file watch: {}", e);
            }else{
                tracing::info!("File change detected, reloading...");
            }
            notifier.notify_waiters();
        },
    }
}