pub mod host { pub const PORT: i64 = 9081; pub fn get_full() -> String { let address: &str = "0.0.0.0"; format!("{}:{}", address, PORT) } } pub mod init { use std::time::Duration; use axum::routing::{delete, get, patch, post}; use tower_http::timeout::TimeoutLayer; use utoipa::OpenApi; use crate::callers::coverart as coverart_caller; use crate::callers::queue::coverart as coverart_queue_callers; use crate::callers::queue::metadata as metadata_queue_caller; use crate::callers::queue::song as song_queue_callers; use crate::callers::song as song_caller; use coverart_caller::endpoint as coverart_endpoints; use coverart_caller::response as coverart_responses; use coverart_queue_callers::endpoint as coverart_queue_endpoints; use coverart_queue_callers::response as coverart_queue_responses; use metadata_queue_caller::endpoint as metadata_queue_endpoints; use metadata_queue_caller::response as metadata_queue_responses; use song_caller::endpoint as song_endpoints; use song_caller::response as song_responses; use song_queue_callers::endpoint as song_queue_endpoints; use song_queue_callers::response as song_queue_responses; mod cors { pub async fn configure_cors() -> tower_http::cors::CorsLayer { let cors = tower_http::cors::CorsLayer::new() .allow_methods([ axum::http::Method::GET, axum::http::Method::POST, axum::http::Method::PUT, axum::http::Method::DELETE, ]) // Specify allowed methods:cite[2] .allow_headers([ axum::http::header::CONTENT_TYPE, axum::http::header::AUTHORIZATION, ]) // Specify allowed headers:cite[2] .allow_credentials(true) // If you need to send cookies or authentication headers:cite[2] .max_age(std::time::Duration::from_secs(3600)); // Cache the preflight response for 1 hour:cite[2] // Dynamically set the allowed origin based on the environment match std::env::var(textsender_models::envy::keys::APP_ENV).as_deref() { Ok("production") => { // In production, allow only your specific, trusted origins let allowed_origins_env = textsender_models::envy::environment::get_allowed_origins().await; match textsender_models::envy::utility::delimitize(&allowed_origins_env) { Ok(alwd) => { let allowed_origins: Vec = alwd .into_iter() .map(|a| a.parse::().unwrap()) .collect(); cors.allow_origin(allowed_origins) } Err(err) => { eprintln!("Error getting allowed origins: Error: {err:?}"); std::process::exit(-1); } } } _ => { // Development (default): Allow localhost origins cors.allow_origin(vec![ "http://localhost:8000".parse().unwrap(), "http://127.0.0.1:8000".parse().unwrap(), "http://localhost:4200".parse().unwrap(), "http://127.0.0.1:4200".parse().unwrap(), ]) } } } } #[derive(utoipa::OpenApi)] #[openapi( paths(song_queue_endpoints::queue_song,), components(schemas(song_queue_callers::response::song_queue::Response)), tags( (name = "textsender API", description = "Web API to manage texting") ) )] struct ApiDoc; pub async fn routes() -> axum::Router { axum::Router::new() .route( crate::callers::queue::endpoints::QUEUESONG, post(crate::callers::queue::song::endpoint::queue_song).route_layer( axum::middleware::from_fn(crate::auth::auth::), ), ) .layer(cors::configure_cors().await) } pub async fn app() -> axum::Router { let pool = crate::db::create_pool() .await .expect("Failed to create pool"); crate::db::migrations(&pool).await; let cors = cors::configure_cors().await; routes() .await .merge( utoipa_swagger_ui::SwaggerUi::new("/swagger-ui") .url("/api-docs/openapi.json", ApiDoc::openapi()), ) .layer(axum::Extension(pool)) .layer(axum::extract::DefaultBodyLimit::max(1024 * 1024 * 1024)) .layer(TimeoutLayer::with_status_code( axum::http::StatusCode::OK, Duration::from_secs(300), )) .layer(cors) } }