mod auth; mod chat; mod config; mod db; mod entity; mod handlers; mod migration; mod models; mod voice; use std::{net::SocketAddr, sync::Arc}; use anyhow::Context; use axum::{Router, routing::get}; use sea_orm::Database; use sea_orm_migration::MigratorTrait; use tower_http::{services::ServeDir, trace::TraceLayer}; use tracing::info; use crate::{config::Settings, handlers::routes, migration::Migrator, voice::VoiceHub}; #[derive(Clone)] pub struct AppState { pub db: sea_orm::DatabaseConnection, pub settings: Arc, pub http: reqwest::Client, pub voice: Arc, pub chat: Arc, } #[tokio::main] async fn main() -> anyhow::Result<()> { dotenvy::dotenv().ok(); init_tracing(); let settings = Arc::new(Settings::from_env()?); let db = Database::connect(&settings.database_url) .await .with_context(|| "failed to connect to postgres")?; Migrator::up(&db, None) .await .with_context(|| "failed to run migrations")?; let state = AppState { db, settings, http: reqwest::Client::new(), voice: Arc::new(VoiceHub::default()), chat: Arc::new(chat::ChatHub::default()), }; let port = state.settings.port; let app = Router::new() .route("/health", get(handlers::health)) .nest_service("/static", ServeDir::new("static")) .merge(routes()) .with_state(state) .layer(TraceLayer::new_for_http()); let addr = SocketAddr::from(([0, 0, 0, 0], port)); info!(%addr, "server started"); let listener = tokio::net::TcpListener::bind(addr).await?; axum::serve(listener, app).await?; Ok(()) } fn init_tracing() { let filter = tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "chattz=info,tower_http=info".into()); tracing_subscriber::fmt().with_env_filter(filter).init(); }