187 lines
5.2 KiB
Rust
187 lines
5.2 KiB
Rust
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));
|
||
}
|
||
}
|
||
|