Files
YANPM/apps/container/src/util.rs
2025-12-22 14:32:57 +08:00

135 lines
4.4 KiB
Rust

use path_clean::PathClean;
use std::path::{Path, PathBuf};
use tokio::signal::unix::{SignalKind, signal};
use crate::{
API_CONFIG_PATH, DB_CONFIG_PATH,
containers::{
AgentConfigInfoType, ConfigInfoType, DBConfigInfoType, WithContainer, WithoutContainer,
agent::SOCK_NAME,
},
env::{self, EnvFile},
};
// 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, agent_config: &Option<AgentConfigInfoType>) {
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);
api_env.write_line("DATABASE__TYPE", db_type.to_string().as_str());
api_env.write_line("DATABASE__URL", db_url.as_str());
let mut db_env = api_env.clone();
db_env.file_type = env::EnvFileType::DotEnv;
// agent related env vars
if let Some(agent) = agent_config
&& let ConfigInfoType::Containerized(agent) = agent
{
api_env.write_line(
"AGENT__SOCK__PATH",
format!("{}/{}", &agent.config.agent_config.sock_folder, SOCK_NAME).as_str(),
);
api_env.write_line(
"AGENT__NGINX__CONFIG__DIR",
&agent.config.agent_config.nginx_config_dir,
);
}
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<impl WithContainer, impl WithoutContainer>,
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;
}
} => {}
}
}