/ src / server.rs
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  }