Files
yourpart-daemon/src/main.rs

196 lines
5.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
mod config;
mod db;
mod message_broker;
mod worker;
mod websocket_server;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;
use config::Config;
use libsystemd::daemon::{self, NotifyState};
use message_broker::MessageBroker;
use websocket_server::WebSocketServer;
use worker::{
CharacterCreationWorker, ConnectionPool, DirectorWorker, HouseWorker, PoliticsWorker,
ProduceWorker, StockageManager, TransportWorker, UndergroundWorker, UserCharacterWorker,
ValueRecalculationWorker, WeatherWorker, Worker,
};
static KEEP_RUNNING: AtomicBool = AtomicBool::new(true);
fn main() {
if let Err(err) = run_daemon() {
eprintln!("Fehler im Daemon: {err}");
std::process::exit(1);
}
}
fn run_daemon() -> Result<(), Box<dyn std::error::Error>> {
install_signal_handler()?;
let config = load_config()?;
let pool = create_connection_pool(&config)?;
let websocket_config = load_websocket_config(&config)?;
let broker = MessageBroker::new();
let mut websocket_server = WebSocketServer::new(
websocket_config.port,
pool.clone(),
broker.clone(),
websocket_config.ssl_enabled,
websocket_config.cert_path,
websocket_config.key_path,
);
let mut workers = create_workers(pool, broker.clone());
websocket_server.set_workers(&workers);
start_system(&mut websocket_server, &mut workers, &broker);
// systemd: melden, dass der Dienst jetzt "bereit" ist
let _ = daemon::notify(false, &[NotifyState::Ready]);
run_main_loop();
shutdown_system(&mut websocket_server, &mut workers, &broker);
Ok(())
}
fn install_signal_handler() -> Result<(), Box<dyn std::error::Error>> {
// Behandle SIGINT/SIGTERM (z.B. Strg+C) und leite auf das globale Flag um.
ctrlc::set_handler(|| {
eprintln!("[Daemon] SIGINT/SIGTERM empfangen, fahre kontrolliert herunter...");
KEEP_RUNNING.store(false, Ordering::SeqCst);
})?;
Ok(())
}
struct WebSocketConfig {
port: u16,
ssl_enabled: bool,
cert_path: Option<String>,
key_path: Option<String>,
}
fn load_config() -> Result<Config, Box<dyn std::error::Error>> {
// Pfad später ggf. konfigurierbar machen
let config = Config::from_file("/etc/yourpart/daemon.conf")?;
Ok(config)
}
fn create_connection_pool(config: &Config) -> Result<ConnectionPool, Box<dyn std::error::Error>> {
let host = config.get("DB_HOST")?;
let port = config.get("DB_PORT")?;
let name = config.get("DB_NAME")?;
let user = config.get("DB_USER")?;
let password = config.get("DB_PASSWORD")?;
let conn_str = format!(
"host={} port={} dbname={} user={} password={}",
host, port, name, user, password
);
// Pool-Größe analog zur C++-Implementierung
let pool = db::ConnectionPool::new(conn_str, 10)?;
Ok(pool)
}
fn load_websocket_config(config: &Config) -> Result<WebSocketConfig, Box<dyn std::error::Error>> {
let port: u16 = config.get("WEBSOCKET_PORT")?.parse()?;
let ssl_enabled =
config.get("WEBSOCKET_SSL_ENABLED").unwrap_or_else(|_| "false".into()) == "true";
let cert_path = if ssl_enabled {
Some(config.get("WEBSOCKET_SSL_CERT_PATH")?)
} else {
None
};
let key_path = if ssl_enabled {
Some(config.get("WEBSOCKET_SSL_KEY_PATH")?)
} else {
None
};
Ok(WebSocketConfig {
port,
ssl_enabled,
cert_path,
key_path,
})
}
fn create_workers(pool: ConnectionPool, broker: MessageBroker) -> Vec<Box<dyn Worker>> {
vec![
Box::new(CharacterCreationWorker::new(pool.clone(), broker.clone())),
Box::new(ProduceWorker::new(pool.clone(), broker.clone())),
Box::new(StockageManager::new(pool.clone(), broker.clone())),
Box::new(DirectorWorker::new(pool.clone(), broker.clone())),
Box::new(ValueRecalculationWorker::new(
pool.clone(),
broker.clone(),
)),
Box::new(UserCharacterWorker::new(
pool.clone(),
broker.clone(),
)),
Box::new(HouseWorker::new(pool.clone(), broker.clone())),
Box::new(PoliticsWorker::new(pool.clone(), broker.clone())),
Box::new(TransportWorker::new(pool.clone(), broker.clone())),
Box::new(UndergroundWorker::new(pool.clone(), broker.clone())),
Box::new(WeatherWorker::new(pool, broker)),
]
}
fn start_system(
websocket_server: &mut WebSocketServer,
workers: &mut [Box<dyn Worker>],
broker: &MessageBroker,
) {
broker.start();
websocket_server.run();
for worker in workers {
worker.start_worker_thread();
worker.enable_watchdog();
}
}
fn shutdown_system(
websocket_server: &mut WebSocketServer,
workers: &mut [Box<dyn Worker>],
broker: &MessageBroker,
) {
eprintln!("[Daemon] Shutdown-System gestartet: stoppe Worker...");
// systemd: wir fahren nun kontrolliert herunter
let _ = daemon::notify(false, &[NotifyState::Stopping]);
// 1) Worker stoppen sie prüfen regelmäßig ihr `running_worker`-Flag und
// brechen daher auch bei längeren Work-Intervallen zügig ab.
for worker in workers {
worker.stop_worker_thread();
}
// 2) WebSocket-Server stoppen (Tokio-Runtime herunterfahren)
eprintln!("[Daemon] WebSocket-Server wird gestoppt...");
websocket_server.stop();
// 3) MessageBroker-Hook aktuell noch Stub, aber hier zentral ergänzt
// für eine spätere interne Queue/Thread-Implementierung.
eprintln!("[Daemon] Broker wird gestoppt...");
broker.stop();
eprintln!("[Daemon] Shutdown-System abgeschlossen.");
}
fn run_main_loop() {
eprintln!("[Daemon] Hauptloop gestartet.");
while KEEP_RUNNING.load(Ordering::Relaxed) {
thread::sleep(Duration::from_millis(100));
}
eprintln!("[Daemon] Hauptloop beendet, starte Shutdown-Sequenz...");
}