fyrer 0.1.6

A lightweight tool to run multiple dev servers concurrently
use crate::config::Service;
use crate::kill_process::kill_process;
use crate::spawn_service::spawn_service;
use colored::Colorize;
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use std::path::Path;
use tokio::process::Child;
use tokio::{
    sync::mpsc,
    time::{Duration, sleep},
};

pub async fn run_with_watch(service: Service, color: colored::Color) {
    let (tx, mut rx) = mpsc::channel(1);
    let watch_dir = Path::new(&service.dir);

    let tx_clone = tx.clone();
    let _watcher = {
        let mut watcher = RecommendedWatcher::new(
            move |res: Result<notify::Event, notify::Error>| {
                if res.is_ok() {
                    let _ = tx_clone.try_send(());
                }
            },
            Config::default(),
        )
        .unwrap_or_else(|e| {
            eprintln!("Failed to create file watcher: {}", e);
            std::process::exit(1);
        });

        watcher
            .watch(watch_dir, RecursiveMode::Recursive)
            .unwrap_or_else(|e| {
                eprintln!("Failed to watch directory {}: {}", service.dir, e);
                std::process::exit(1);
            });
        watcher
    };

    println!(
        "{}",
        format!("[{}] Watching {} for changes...", service.name, service.dir)
            .color(color)
            .bold()
    );

    let mut child: Option<Child> = spawn_service(&service, color, false).await;

    loop {
        tokio::select! {
            _ = rx.recv() => {
                if let Some(mut c) = child.take() {
                    println!(
                        "{}",
                        format!("[{}] File changed, restarting service...", service.name)
                            .color(color)
                            .bold()
                    );
                    kill_process(&mut c).await;
                    sleep(Duration::from_millis(500)).await;
                }
                child = spawn_service(&service, color, false).await;

                sleep(Duration::from_millis(500)).await;
                while rx.try_recv().is_ok() {}
            }
            _ = async {
                if let Some(ref mut c) = child {
                    c.wait().await
                } else {
                    std::future::pending().await
                }
            } => {
                println!(
                    "{}",
                    format!("[{}] Service exited, restarting...", service.name)
                        .color(color)
                        .bold()
                );
                sleep(Duration::from_millis(1000)).await;
                child = spawn_service(&service, color, false).await;
            }
        }
    }
}