use path_clean::PathClean; use std::path::{Path, PathBuf}; use tokio::signal::unix::{SignalKind, signal}; use crate::{ API_CONFIG_PATH, DB_CONFIG_PATH, db::DBConfigInfoType, env::{self, EnvFile}, types::{ConfigInfoType, WithContainer, WithoutContainer}, }; // relative to the current working directory pub fn to_absolute_path(path: &str) -> PathBuf { if Path::new(path).is_absolute() { return PathBuf::from(path); } std::env::current_dir() .map(|cwd| cwd.join(path)) .unwrap_or_else(|_| PathBuf::from(path)) .clean() } pub fn write_env_files(db_config: &DBConfigInfoType) { let api_config_path_absolute = to_absolute_path(API_CONFIG_PATH); let db_config_path_absolute = to_absolute_path(DB_CONFIG_PATH); let (db_type, db_url) = match db_config { DBConfigInfoType::Containerized(config) => (config.db_type.clone(), config.url.clone()), DBConfigInfoType::PreExisting(config) => (config.db_type.clone(), config.url.clone()), }; let mut api_env = EnvFile::new(env::EnvFileType::Yaml, db_type, db_url); let mut db_env = api_env.clone(); db_env.file_type = env::EnvFileType::DotEnv; let mut api_file = std::fs::File::create(&api_config_path_absolute).expect("Failed to create API config file"); let mut db_file = std::fs::File::create(&db_config_path_absolute).expect("Failed to create DB config file"); api_env.write(&mut api_file, true); db_env.write(&mut db_file, false); } pub async fn stop_container( config: &ConfigInfoType, config_name: String, ) { match config { ConfigInfoType::Containerized(container_info) => { let container = container_info.container(); if let Err(e) = container.stop().await { eprintln!( "Failed to stop container: {}. With error: {}", config_name, e ); } else { println!("Container {} stopped successfully.", config_name); } } ConfigInfoType::PreExisting(pre_existing_info) => { pre_existing_info.on_delete(); println!( "Pre-existing resource for {} cleaned up successfully.", config_name ); } } } pub fn remove_file_if_exists(path: &str) { let path = std::path::Path::new(path); if path.exists() { if let Err(e) = std::fs::remove_file(path) { eprintln!("Failed to remove file {}: {}", path.display(), e); } else { println!("Removed existing file: {}", path.display()); } } } pub async fn await_termination_signal() { tokio::select! { _ = tokio::signal::ctrl_c() => { println!("\nReceived Ctrl+C, stopping container..."); } _ = async { #[cfg(unix)] { let mut sigterm = signal(SignalKind::terminate()).expect("Failed to register SIGTERM handler"); sigterm.recv().await; println!("\nReceived SIGTERM, stopping container..."); } #[cfg(not(unix))] { // On non-Unix systems, just wait indefinitely std::future::pending::<()>().await; } } => {} _ = async { #[cfg(unix)] { let mut sigquit = signal(SignalKind::quit()).expect("Failed to register SIGQUIT handler"); sigquit.recv().await; println!("\nReceived SIGQUIT, stopping container..."); } #[cfg(not(unix))] { // On non-Unix systems, just wait indefinitely std::future::pending::<()>().await; } } => {} } }