state.rs
1 use crate::{ 2 Args, Metrics, PushMetrics, Sun, ambient_weather::AmbientWeatherReport, metrics::PushError, 3 }; 4 use http::header::CONTENT_TYPE; 5 use reqwest_middleware::{Extension, RequestBuilder}; 6 use reqwest_tracing::{OtelName, TracingMiddleware}; 7 use std::{fmt::Debug, sync::RwLock, time::Duration}; 8 use tracing::{debug, error}; 9 10 const OPENMETRICS_TEXT: &str = "application/openmetrics-text"; 11 12 pub struct ServerState { 13 client: reqwest_middleware::ClientWithMiddleware, 14 conditions_interval: Duration, 15 latest: RwLock<Option<AmbientWeatherReport>>, 16 metrics: Metrics, 17 push_url: reqwest::Url, 18 sun: Sun, 19 } 20 21 impl ServerState { 22 pub fn new(args: &Args, metrics: Metrics) -> Self { 23 let push_url = args.push_url(); 24 let sun = args.into(); 25 26 let client = reqwest::ClientBuilder::new() 27 .user_agent("ambient-weather-local") 28 .build() 29 .expect("Unable to build HTTP client"); 30 31 let client = reqwest_middleware::ClientBuilder::new(client) 32 .with_init(Extension(OtelName("report push".into()))) 33 .with(TracingMiddleware::default()) 34 .build(); 35 36 Self { 37 client, 38 conditions_interval: Duration::from_secs(5 * 60), 39 latest: Default::default(), 40 metrics, 41 push_url, 42 sun, 43 } 44 } 45 46 pub fn conditions_interval(&self) -> Duration { 47 self.conditions_interval 48 } 49 50 pub fn latest(&self) -> Option<AmbientWeatherReport> { 51 let guard = self.latest.read().unwrap(); 52 53 (*guard).clone() 54 } 55 56 pub async fn push(&self, report: AmbientWeatherReport) { 57 { 58 let mut guard = self.latest.write().unwrap(); 59 60 *guard = Some(report.clone()); 61 } 62 63 let request_builder = self.client.post(self.push_url.clone()); 64 } 65 } 66 67 impl Debug for ServerState { 68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 69 f.debug_struct("ServerState") 70 .field("client", &"...") 71 .field("metrics", &"...") 72 .field("push_url", &self.push_url) 73 .finish() 74 } 75 }