use crate::router::build_router; #[derive(Clone, Debug)] pub struct AppConfig { pub server_host: String, pub server_port: u16, } impl AppConfig { pub fn from_env() -> Self { Self { server_host: std::env::var("OPS_SERVER_HOST") .unwrap_or_else(|_| "127.0.0.1".to_string()), server_port: std::env::var("OPS_SERVER_PORT") .ok() .and_then(|value| value.parse().ok()) .unwrap_or(3100), } } } #[derive(Clone, Debug)] pub struct AppState { pub app_name: &'static str, pub config: AppConfig, } pub async fn run() { dotenv::dotenv().ok(); plc_platform_core::util::log::init_logger(); let _platform = plc_platform_core::bootstrap::bootstrap_platform(); let _single_instance = match plc_platform_core::util::single_instance::try_acquire("PLCControl.OperationSystem") { Ok(guard) => guard, Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => { tracing::warn!("Another operation-system instance is already running"); return; } Err(err) => { tracing::error!("Failed to initialize single instance guard: {}", err); return; } }; let state = AppState { app_name: "operation-system", config: AppConfig::from_env(), }; let app = build_router(state.clone()); let addr = format!("{}:{}", state.config.server_host, state.config.server_port); tracing::info!("Starting operation-system server at http://{}", addr); let listener = tokio::net::TcpListener::bind(&addr) .await .expect("operation-system listener should bind"); axum::serve(listener, app) .await .expect("operation-system server should run"); } pub fn test_state() -> AppState { AppState { app_name: "operation-system", config: AppConfig { server_host: "127.0.0.1".to_string(), server_port: 0, }, } }