Files
k-frame/crates/bootstrap/src/main.rs
Gabriel Kaszewski adda731dc6 add auth system: users, login, JWT, protected routes
Domain: User entity, AuthPort/PasswordHashPort/SecretStore ports.
Adapters: auth (argon2 hashing, JWT tokens), secret-store (env-based),
config-sqlite user repository, http-api auth routes + extractors.
Application: auth_service. SPA: login page, auth client, protected router.
2026-06-19 01:39:42 +02:00

91 lines
2.8 KiB
Rust

mod config;
mod event_handler;
mod polling;
use anyhow::Result;
use application::DataProjection;
use config_sqlite::SqliteConfigStore;
use http_api::AppState;
use kframe_auth::{Argon2Hasher, AuthConfig, JwtAuthService};
use secret_store::AesSecretStore;
use std::sync::Arc;
use tcp_server::{ClientTracker, TcpBroadcaster, TcpEventBus, run_tcp_server};
use tracing::{error, info};
#[tokio::main]
async fn main() -> Result<()> {
dotenvy::dotenv().ok();
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "info,sqlx=warn".into()),
)
.init();
let cfg = config::ServerConfig::from_env();
let auth_config = AuthConfig::from_env().map_err(|e| anyhow::anyhow!(e))?;
let secrets = AesSecretStore::from_env().map_err(|e| anyhow::anyhow!(e))?;
info!(db = %cfg.database_url, "connecting to database");
let secrets = Arc::new(secrets);
let config_store =
Arc::new(SqliteConfigStore::with_secrets(&cfg.database_url, Some(secrets.clone())).await?);
let event_bus = Arc::new(TcpEventBus::new(64));
let broadcaster = Arc::new(TcpBroadcaster::new(64));
let projection = Arc::new(DataProjection::new());
let tracker = Arc::new(ClientTracker::new());
let auth = Arc::new(JwtAuthService::new(auth_config));
let hasher = Arc::new(Argon2Hasher);
let tcp_addr = cfg.tcp_addr.clone();
let tcp_bc = broadcaster.clone();
let tcp_tracker = tracker.clone();
let tcp_config = config_store.clone();
let tcp_proj = projection.clone();
tokio::spawn(async move {
if let Err(e) = run_tcp_server(&tcp_addr, tcp_bc, tcp_tracker, tcp_config, tcp_proj).await {
error!(error = %e, "tcp server failed");
}
});
info!(addr = %cfg.tcp_addr, "TCP server started");
let http_addr = cfg.http_addr.clone();
let http_state = AppState {
config: config_store.clone(),
events: event_bus.clone(),
widget_states: projection.clone(),
broadcaster: broadcaster.clone(),
clients: tracker.clone(),
auth: auth.clone(),
hasher: hasher.clone(),
spa_dir: cfg.spa_dir,
};
tokio::spawn(async move {
if let Err(e) = http_api::serve(&http_addr, http_state).await {
error!(error = %e, "HTTP API failed");
}
});
info!(addr = %cfg.http_addr, "HTTP API started");
info!("K-Frame server running");
let ev_bus = event_bus.clone();
let ev_config = config_store.clone();
let ev_bc = broadcaster.clone();
let ev_proj = projection.clone();
tokio::spawn(async move {
event_handler::run(ev_bus, ev_config, ev_bc, ev_proj).await;
});
polling::run(
config_store,
broadcaster,
projection,
cfg.poll_interval_secs,
)
.await
}