server.rs
1 mod metrics_layer; 2 mod metrics_service; 3 4 use std::net::SocketAddr; 5 6 use axum::{ 7 Router, 8 routing::{MethodFilter, on_service}, 9 }; 10 use axum_tracing_opentelemetry::middleware::{OtelAxumLayer, OtelInResponseLayer}; 11 use prometheus_client::metrics::{counter::Counter, family::Family}; 12 13 use crate::{ 14 Args, Metrics, Root, 15 ambient_weather::AmbientWeatherService, 16 metrics::{MetricsService, RequestLabels}, 17 server::metrics_layer::MetricsLayer, 18 }; 19 20 pub struct Server { 21 address: SocketAddr, 22 ambient_weather: AmbientWeatherService, 23 metrics: MetricsService, 24 requests: Family<RequestLabels, Counter>, 25 } 26 27 impl Server { 28 pub fn new(args: &Args, metrics: &Metrics) -> Self { 29 let ambient_weather = AmbientWeatherService::new(args, metrics); 30 let requests = metrics.requests.clone(); 31 32 Self { 33 address: args.address, 34 ambient_weather, 35 metrics: metrics.service(), 36 requests, 37 } 38 } 39 40 pub async fn start(self) -> Result<(), std::io::Error> { 41 self.start_conditions(); 42 self.start_http().await 43 } 44 45 fn start_conditions(&self) { 46 self.ambient_weather.conditions().start(); 47 } 48 49 pub async fn start_http(self) -> Result<(), std::io::Error> { 50 let get_or_head = MethodFilter::GET.or(MethodFilter::HEAD); 51 52 let app = Router::new() 53 .route("/", on_service(get_or_head, Root::default())) 54 .route( 55 "/ambient-weather/current", 56 on_service(get_or_head, self.ambient_weather.clone()), 57 ) 58 .route( 59 "/ambient-weather/upload", 60 on_service(get_or_head, self.ambient_weather), 61 ) 62 .route("/metrics", on_service(get_or_head, self.metrics)) 63 .layer(OtelInResponseLayer) 64 .layer(OtelAxumLayer::default()) 65 .layer(MetricsLayer::new(self.requests)); 66 67 let listener = tokio::net::TcpListener::bind(self.address).await?; 68 69 axum::serve(listener, app).await?; 70 71 Ok(()) 72 } 73 }