pub mod api { pub mod auth; pub mod catchers; pub mod mcp; } pub mod core { pub mod config; pub mod db; pub mod validation; } pub mod transport { pub mod execute; pub mod protocol; pub mod socket; } use core::config::Config; use dashmap::DashMap; use log::info; use rocket::routes; use serde::Serialize; use sqlx::SqlitePool; use sqlx::sqlite::SqliteConnectOptions; use std::sync::{Arc, atomic::AtomicUsize}; use tokio::sync::{mpsc, oneshot}; const DATABASE_PATH: &str = "server.db"; pub type Database = SqlitePool; pub type DeviceCounts = DashMap>; pub type Registry = DashMap<(String, String), RegistryEntry>; pub struct RegistryEntry { pub sender: mpsc::Sender, pub in_flight: Arc, } #[derive(Debug, Serialize)] pub struct ExecResult { pub exit_code: i32, pub stdout: String, pub stderr: String, } pub struct PendingExec { pub exec_id: String, pub command: String, pub reply: oneshot::Sender, } pub struct AppState { pub database: Database, pub registry: Arc, pub device_counts: Arc, pub config: Arc, } #[rocket::main] async fn main() -> Result<(), Box> { env_logger::init(); let database = connect_database().await?; apply_schema(&database).await?; info!("Launching server"); build_rocket(database).launch().await?; Ok(()) } async fn connect_database() -> Result { let options = SqliteConnectOptions::new() .filename(DATABASE_PATH) .create_if_missing(true); SqlitePool::connect_with(options).await } async fn apply_schema(database: &Database) -> Result<(), sqlx::Error> { for statement in include_str!("../schema.sql") .split(';') .map(str::trim) .filter(|statement| !statement.is_empty()) { sqlx::query(statement).execute(database).await?; } Ok(()) } fn build_rocket(database: Database) -> rocket::Rocket { rocket::build() .manage(AppState { database, registry: Arc::new(DashMap::new()), device_counts: Arc::new(DashMap::new()), config: Arc::new(Config::from_env()), }) .mount("/", routes![transport::socket::connect, api::mcp::route]) .register("/", rocket::catchers![api::catchers::default_catcher]) }