Add container simulation with PostgreSQL and SQLite support

This commit is contained in:
GW_MC
2025-11-11 20:53:20 +08:00
parent 54080eb0c9
commit 6b3172d88b
14 changed files with 2818 additions and 0 deletions

95
apps/container/src/lib.rs Normal file
View File

@@ -0,0 +1,95 @@
pub mod db;
mod env;
pub mod types;
mod util;
use crate::{
db::DBConfigInfoType,
types::{ConfigInfoType, 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,
}
// 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) {
let db_config = &config.database;
//
// write the config files for the api server and database client
println!("Writing config files...");
write_env_files(&db_config);
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) {
let db_config = &config.database;
// stop the container
println!("Stopping container...");
stop_container(db_config, "database".to_string()).await;
// 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!("Container stopped.");
}
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)
}