perfect-postcode/server-rs/src/routes/streetview.rs
2026-03-17 21:08:32 +00:00

86 lines
2.1 KiB
Rust

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<String>,
}
pub async fn get_streetview(
State(shared): State<Arc<SharedState>>,
query: axum::extract::Query<StreetViewQuery>,
) -> 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,
}),
)
}
}