pub mod api;
pub mod app;
pub mod config;
pub mod dto;
mod handlers;
mod middleware;
use app::AppState;
use config::ServerConfig;
use geoprox_core::models::GeoShardConfig;
use axum::routing::{IntoMakeService, Router};
use axum::{body::Bytes, extract::Request};
use std::time::Duration;
use tower::Layer;
use tower_http::compression::CompressionLayer;
use tower_http::decompression::DecompressionLayer;
use tower_http::normalize_path::NormalizePath;
use tower_http::timeout::TimeoutLayer;
use tower_http::trace::{DefaultMakeSpan, DefaultOnResponse};
use tower_http::{normalize_path::NormalizePathLayer, trace::TraceLayer};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
fn api_service(
server_config: ServerConfig,
shard_config: GeoShardConfig,
) -> IntoMakeService<NormalizePath<Router>> {
let state = AppState::new(server_config.clone(), shard_config);
let router = Router::new()
.nest("/api/v1/", api::routes(state))
.merge(api::docs::router())
.layer(
tower::ServiceBuilder::new()
.layer(
TraceLayer::new_for_http()
.on_body_chunk(|chunk: &Bytes, latency: Duration, _: &tracing::Span| {
tracing::trace!(size_bytes = chunk.len(), latency = ?latency, "sending body chunk")
})
.make_span_with(DefaultMakeSpan::new().include_headers(true))
.on_response(DefaultOnResponse::new()
.include_headers(true).
latency_unit(tower_http::LatencyUnit::Micros)
),
)
.layer(TimeoutLayer::new(
server_config.timeout.unwrap().into())
)
.layer(CompressionLayer::new())
.layer(DecompressionLayer::new())
);
let router = NormalizePathLayer::trim_trailing_slash().layer(router);
axum::ServiceExt::<Request>::into_make_service(router)
}
#[tokio::main]
pub async fn run(server_config: ServerConfig, shard_config: GeoShardConfig) {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "geoprox=debug".into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let socket: std::net::SocketAddr = server_config.clone().into();
dbg!("binding to:", socket);
let listener = tokio::net::TcpListener::bind(socket).await.unwrap();
println!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, api_service(server_config, shard_config))
.await
.unwrap();
}