Initial commit: Rust YpDaemon

This commit is contained in:
Torsten Schulz (local)
2025-11-21 23:05:34 +01:00
commit d0ec363f09
21 changed files with 8067 additions and 0 deletions

186
src/main.rs Normal file
View File

@@ -0,0 +1,186 @@
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));
}
}