use serde::{Deserialize, Serialize}; use tracing::warn; #[derive(Serialize)] struct TravelTimeRequest { origins: Vec<[f64; 2]>, destination: [f64; 2], mode: String, } #[derive(Deserialize)] struct TravelTimeResponse { travel_times: Vec>, } /// Call the R5 service to compute many-to-one travel times. /// /// Returns a Vec of travel times in minutes (one per origin), with None for unreachable origins. pub async fn fetch_travel_times( client: &reqwest::Client, r5_url: &str, origins: Vec<[f64; 2]>, destination: [f64; 2], mode: &str, ) -> Result>, String> { let url = format!("{}/travel-times", r5_url); let request_body = TravelTimeRequest { origins, destination, mode: mode.to_string(), }; let resp = client .post(&url) .json(&request_body) .timeout(std::time::Duration::from_secs(60)) .send() .await .map_err(|e| { warn!("R5 request failed: {}", e); format!("R5 service error: {}", e) })?; if !resp.status().is_success() { let status = resp.status(); let body = resp.text().await.unwrap_or_default(); warn!("R5 returned {}: {}", status, body); return Err(format!("R5 service returned {}: {}", status, body)); } let body: TravelTimeResponse = resp.json().await.map_err(|e| { warn!("Failed to parse R5 response: {}", e); format!("Failed to parse R5 response: {}", e) })?; Ok(body.travel_times) }