mod config;
mod routing;
mod auth;
mod proxy;
mod middleware;
mod state;
mod error;
use axum::{
middleware as axum_middleware,
routing::{any, get, post},
Router,
};
use lmrc_http_common::middleware::cors_with_origins;
use sea_orm::Database;
use state::AppState;
use std::net::SocketAddr;
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "gateway=debug,tower_http=debug".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
dotenvy::dotenv().ok();
let config = config::Config::from_env()?;
tracing::info!("Starting gateway on {}:{}", config.server.host, config.server.port);
tracing::info!("Infrastructure database: connected");
tracing::info!("User routes configured: {}", config.routing.user_routes.len());
tracing::info!("Connecting to infrastructure database...");
let infra_db = Database::connect(&config.database.infra_url).await?;
tracing::info!("Infrastructure database connected");
let state = AppState::new(config.clone(), infra_db);
let app = create_router(state);
let addr = SocketAddr::from(([0, 0, 0, 0], config.server.port));
tracing::info!("Listening on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await?;
axum::serve(listener, app).await?;
Ok(())
}
fn create_router(state: AppState) -> Router {
let infra_routes = Router::new()
.route("/auth/login", post(auth::handlers::infra_login))
.route("/auth/logout", post(auth::handlers::infra_logout))
.route("/auth/me", get(auth::handlers::infra_me))
.route("/api/*path", any(proxy::handlers::proxy_to_infra_api))
.layer(axum_middleware::from_fn_with_state(
state.clone(),
middleware::infra_auth::infra_auth_middleware,
))
.route("/*path", any(proxy::handlers::proxy_to_infra_front));
let user_routes = Router::new()
.route("/*path", any(routing::handlers::route_user_service));
Router::new()
.nest("/", Router::new()
.fallback(routing::handlers::subdomain_router))
.layer(TraceLayer::new_for_http())
.layer(axum_middleware::from_fn(middleware::subdomain::extract_subdomain))
.layer(cors_with_origins(state.config.server.cors_origins.clone()))
.with_state(state)
}