use actix_cors::Cors; use actix_web::{dev::Service, http::header, App, HttpServer}; use apidocs::ApiDocs; use clickhouse_pool::pool_manager::PoolManager; use config::Config; use poise::serenity_prelude::Http; use std::{net::Ipv4Addr, sync::Arc}; use tracing::{error, info}; use tracing_actix_web::{RequestId, TracingLogger}; use utoipa::OpenApi; use utoipa_actix_web::AppExt; use utoipa_scalar::{Scalar, Servable as ScalarServable}; pub mod apidocs; pub async fn init_api(config: Config, pool: Arc, http: Arc) -> Result<(), ()> { let port = config.port; HttpServer::new(move || { let cors = Cors::default() .allow_any_origin() .allow_any_method() .allow_any_header() .max_age(3600); App::new() .wrap(cors) .wrap_fn(|mut req, srv| { let request_id_asc = req.extract::(); let fut = srv.call(req); async move { let mut res = fut.await?; let request_id: RequestId = request_id_asc.await.unwrap(); let request_id_str = format!("{}", request_id); let headers = res.headers_mut(); headers.insert( header::HeaderName::from_static("x-request-id"), header::HeaderValue::from_str(request_id_str.as_str()).unwrap(), ); Ok(res) } }) .wrap(TracingLogger::default()) .into_utoipa_app() .openapi(ApiDocs::openapi()) .app_data(actix_web::web::Data::new(pool.clone())) .app_data(actix_web::web::Data::new(http.clone())) .app_data(actix_web::web::Data::new(config.clone())) .openapi_service(|api| Scalar::with_url("/api/docs", api)) .into_app() }) .bind((Ipv4Addr::UNSPECIFIED, port)) .map_err(|e| { error!("Failed to bind API server: {}", e); })? .run() .await .map_err(|e| { eprintln!("Failed to start API server: {}", e); })?; info!("Api server stopped"); Ok(()) }