use std::sync::Arc; use axum::extract::State; use axum::http::StatusCode; use axum::response::{IntoResponse, Json}; use serde::{Deserialize, Serialize}; use tracing::warn; use crate::state::SharedState; #[derive(Deserialize)] pub struct StreetViewQuery { lat: f64, lon: f64, } #[derive(Deserialize)] struct GoogleMetadataResponse { status: String, #[serde(default)] pano_id: String, } #[derive(Serialize)] struct StreetViewResponse { status: String, #[serde(skip_serializing_if = "Option::is_none")] pano_id: Option, } pub async fn get_streetview( State(shared): State>, query: axum::extract::Query, ) -> impl IntoResponse { let state = shared.load_state(); let url = format!( "https://maps.googleapis.com/maps/api/streetview/metadata?location={},{}&radius=1000&source=outdoor&key={}", query.lat, query.lon, state.google_maps_api_key ); let resp = match state.http_client.get(&url).send().await { Ok(r) => r, Err(e) => { warn!("Street View metadata request failed: {e}"); return ( StatusCode::BAD_GATEWAY, Json(StreetViewResponse { status: "ERROR".to_string(), pano_id: None, }), ); } }; let meta: GoogleMetadataResponse = match resp.json().await { Ok(m) => m, Err(e) => { warn!("Failed to parse Street View metadata: {e}"); return ( StatusCode::BAD_GATEWAY, Json(StreetViewResponse { status: "ERROR".to_string(), pano_id: None, }), ); } }; if meta.status == "OK" { ( StatusCode::OK, Json(StreetViewResponse { status: "OK".to_string(), pano_id: Some(meta.pano_id), }), ) } else { ( StatusCode::OK, Json(StreetViewResponse { status: meta.status, pano_id: None, }), ) } }