everymap_providers_mapbox/domain/imaging/
mod.rs1use crate::client::MapBoxClient;
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 MAP_BASE_URL: &str = "https://api.mapbox.com";
9
10pub struct MapBoxMapImageProvider {
12 pub(crate) client: Arc<MapBoxClient>,
13 pub(crate) base_url: String,
14}
15
16impl MapBoxMapImageProvider {
17 pub fn new(client: Arc<MapBoxClient>) -> Self {
18 Self {
19 client,
20 base_url: MAP_BASE_URL.to_string(),
21 }
22 }
23
24 pub fn with_base_url(client: Arc<MapBoxClient>, base_url: String) -> Self {
25 Self { client, base_url }
26 }
27}
28
29#[async_trait]
30impl MapImageProvider for MapBoxMapImageProvider {
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 style = options
39 .provider_extra
40 .as_ref()
41 .and_then(|e| e.get("style"))
42 .and_then(|v| v.as_str())
43 .unwrap_or("mapbox/streets-v12");
44
45 let width = options.width.unwrap_or(size.0);
47 let height = options.height.unwrap_or(size.1);
48
49 let url = format!(
51 "{}/styles/v1/{}/static/{},{},{}/{}x{}@2x",
52 self.base_url, style, center.lng, center.lat, zoom, width, height
53 );
54
55 let mut params: Vec<(&str, String)> = Vec::new();
56 if let Some(lang) = &options.language {
57 params.push(("language", lang.clone()));
58 }
59 if options.format.is_some() {
60 log::warn!(
61 "MapBox Static Images API does not support a format parameter; \
62 format will be ignored (MapBox always returns PNG)"
63 );
64 }
65
66 let builder = self
67 .client
68 .build_request(reqwest::Method::GET, &url)
69 .query(¶ms);
70
71 let response = self.client.request(builder).await?;
72
73 let content_type = response
74 .headers()
75 .get("content-type")
76 .and_then(|v| v.to_str().ok())
77 .map(|s| s.split(';').next().unwrap_or(s).trim().to_string());
78
79 let data = response.bytes().await?.to_vec();
80
81 Ok(ImageResponse { data, content_type })
82 }
83}