Files
yourpart-daemon/src/main.rs
Torsten Schulz (local) d0ec363f09 Initial commit: Rust YpDaemon
2025-11-21 23:05:34 +01:00

187 lines
5.2 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, UndergroundWorker, UserCharacterWorker,
ValueRecalculationWorker, 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(|| {
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(UndergroundWorker::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,
) {
// 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)
websocket_server.stop();
// 3) MessageBroker-Hook aktuell noch Stub, aber hier zentral ergänzt
// für eine spätere interne Queue/Thread-Implementierung.
broker.stop();
}
fn run_main_loop() {
while KEEP_RUNNING.load(Ordering::Relaxed) {
thread::sleep(Duration::from_millis(100));
}
}