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> { 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> { // 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, key_path: Option, } fn load_config() -> Result> { // Pfad später ggf. konfigurierbar machen let config = Config::from_file("/etc/yourpart/daemon.conf")?; Ok(config) } fn create_connection_pool(config: &Config) -> Result> { 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> { 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> { 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], 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], 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..."); }