everymap_providers_google/domain/imaging/
mod.rs1use crate::client::GoogleClient;
2use async_trait::async_trait;
3use everymap_core::domains::imaging::{ImageOptions, ImageResponse, MapImageProvider};
4use everymap_core::error::EveryMapResult;
5use everymap_core::types::Coordinate;
6use std::sync::Arc;
7
8const STATIC_MAPS_BASE_URL: &str = "https://maps.googleapis.com/maps/api/staticmap";
9
10pub struct GoogleMapImageProvider {
12 pub(crate) client: Arc<GoogleClient>,
13 pub(crate) base_url: String,
14}
15
16impl GoogleMapImageProvider {
17 pub fn new(client: Arc<GoogleClient>) -> Self {
18 Self {
19 client,
20 base_url: STATIC_MAPS_BASE_URL.to_string(),
21 }
22 }
23
24 pub fn with_base_url(client: Arc<GoogleClient>, base_url: String) -> Self {
25 Self { client, base_url }
26 }
27}
28
29#[async_trait]
30impl MapImageProvider for GoogleMapImageProvider {
31 async fn get_image(
32 &self,
33 center: &Coordinate,
34 zoom: u32,
35 size: (u32, u32),
36 options: &ImageOptions,
37 ) -> EveryMapResult<ImageResponse> {
38 let mut params: Vec<(String, String)> = vec![
39 (
40 "center".to_string(),
41 format!("{},{}", center.lat, center.lng),
42 ),
43 ("zoom".to_string(), zoom.to_string()),
44 ("size".to_string(), format!("{}x{}", size.0, size.1)),
45 ];
46
47 if let Some(fmt) = &options.format {
49 let format_val = match fmt.as_str() {
50 "jpg" | "jpeg" => "jpg",
51 "gif" => "gif",
52 _ => "png",
53 };
54 params.push(("format".to_string(), format_val.to_string()));
55 }
56
57 if let Some(lang) = &options.language {
58 params.push(("language".to_string(), lang.clone()));
59 }
60
61 if let Some(extra) = &options.provider_extra {
63 if let Some(obj) = extra.as_object() {
64 if let Some(v) = obj.get("maptype").and_then(|v| v.as_str()) {
65 params.push(("maptype".to_string(), v.to_string()));
66 }
67 if let Some(v) = obj.get("scale").and_then(|v| v.as_u64()) {
68 params.push(("scale".to_string(), v.to_string()));
69 }
70 if let Some(v) = obj.get("markers").and_then(|v| v.as_str()) {
71 params.push(("markers".to_string(), v.to_string()));
72 }
73 if let Some(v) = obj.get("path").and_then(|v| v.as_str()) {
74 params.push(("path".to_string(), v.to_string()));
75 }
76 if let Some(v) = obj.get("visible").and_then(|v| v.as_str()) {
77 params.push(("visible".to_string(), v.to_string()));
78 }
79 if let Some(v) = obj.get("style").and_then(|v| v.as_str()) {
80 params.push(("style".to_string(), v.to_string()));
81 }
82 }
83 }
84
85 let url = self.base_url.clone();
86 let builder = self
87 .client
88 .build_request(reqwest::Method::GET, &url)
89 .query(¶ms);
90
91 let response = self.client.request(builder).await?;
92
93 let content_type = response
94 .headers()
95 .get("content-type")
96 .and_then(|v| v.to_str().ok())
97 .map(|s| s.split(';').next().unwrap_or(s).trim().to_string());
98
99 let data = response.bytes().await?.to_vec();
100
101 Ok(ImageResponse { data, content_type })
102 }
103}