pub mod containers; mod env; mod util; use crate::{ containers::{ AgentConfigInfoType, ConfigInfoType, DBConfigInfoType, WithContainer, WithoutContainer, }, util::{ await_termination_signal, remove_file_if_exists, stop_container, to_absolute_path, write_env_files, }, }; #[derive(Clone)] pub struct Config { pub database: DBConfigInfoType, pub agent: Option, } // relative to the pwd const API_CONFIG_PATH: &str = "../api/generated-config.yaml"; const DB_CONFIG_PATH: &str = "../../public/database/.env.generated"; pub struct DetachedHandle<'a> { stopped: bool, pub config: &'a Config, } impl<'a> DetachedHandle<'a> { pub fn new(config: &'a Config) -> Self { DetachedHandle { stopped: false, config, } } pub async fn stop(&mut self) { if self.stopped { eprintln!("Attempted to stop an already stopped DetachedHandle."); return; } self.stopped = true; stop(self.config).await; } } impl<'a> Drop for DetachedHandle<'a> { fn drop(&mut self) { if self.stopped { return; } eprintln!( "Warning: DetachedHandle was dropped without calling stop(). The container may still be running." ); } } async fn start(config: &Config) { // write the config files for the api server and database client println!("Writing config files..."); write_env_files(&config.database, &config.agent); println!("Config files written to:"); println!(" - {}", to_absolute_path(API_CONFIG_PATH).display()); println!(" - {}", to_absolute_path(DB_CONFIG_PATH).display()); } async fn stop(config: &Config) { // stop the container println!("Stopping container..."); println!("Stopping database container..."); stop_container(&config.database, "database".to_string()).await; if let Some(agent) = &config.agent { println!("Stopping agent container..."); stop_container(agent, "agent".to_string()).await; } println!("Container stopped."); // remove the generated config file println!("Removing generated config file..."); remove_file_if_exists(DB_CONFIG_PATH); remove_file_if_exists(API_CONFIG_PATH); println!("Generated config files removed."); } pub async fn start_attached(config: &Config) { start(config).await; // wait for user input, ctrl+c, or other signals before exiting println!("Press Ctrl+C, or send SIGTERM to stop the container..."); await_termination_signal().await; stop(config).await; } #[must_use] pub async fn start_detached(config: &'_ Config) -> DetachedHandle<'_> { start(config).await; DetachedHandle::new(config) }