#![allow(clippy::all, unused_imports, dead_code)]
use crate::{Actor, ActorBehavior, Message, Port};
use anyhow::{Error, Result};
use reflow_actor::{message::EncodableValue, ActorContext};
use reflow_actor_macro::actor;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::time::Duration;
const BASE_URL: &str = "https://maps.googleapis.com/maps/api";
const ENV_KEY: &str = "GOOGLE_MAPS_API_KEY";
fn apply_auth(
config: &reflow_actor::ActorConfig,
mut builder: reqwest::RequestBuilder,
) -> Result<reqwest::RequestBuilder> {
let credential = config
.get_config_or_env(ENV_KEY)
.ok_or_else(|| anyhow::anyhow!("Missing env var: {}", ENV_KEY))?;
builder = builder.query(&[("key", &credential)]);
Ok(builder)
}
#[actor(
GoogleMapsSearchPlacesActor,
inports::<100>(query, key),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_search_places(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/place/textsearch/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("query") {
query_pairs.push(("query", super::message_to_str(val)));
}
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /place/textsearch/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsGeocodeAddressActor,
inports::<100>(address, key),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_geocode_address(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/geocode/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("address") {
query_pairs.push(("address", super::message_to_str(val)));
}
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /geocode/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadPlaceActor,
inports::<100>(key, place_id, fields, language),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_place(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/place/details/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("place_id") {
query_pairs.push(("place_id", super::message_to_str(val)));
}
if let Some(val) = inputs.get("fields") {
query_pairs.push(("fields", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /place/details/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsSearchGeocodeActor,
inports::<100>(key, address, latlng, place_id, components, language, region),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_search_geocode(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/geocode/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("address") {
query_pairs.push(("address", super::message_to_str(val)));
}
if let Some(val) = inputs.get("latlng") {
query_pairs.push(("latlng", super::message_to_str(val)));
}
if let Some(val) = inputs.get("place_id") {
query_pairs.push(("place_id", super::message_to_str(val)));
}
if let Some(val) = inputs.get("components") {
query_pairs.push(("components", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if let Some(val) = inputs.get("region") {
query_pairs.push(("region", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /geocode/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadDirectionsActor,
inports::<100>(key, origin, destination, mode, waypoints, avoid, language, units, departure_time, arrival_time),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_directions(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/directions/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("origin") {
query_pairs.push(("origin", super::message_to_str(val)));
}
if let Some(val) = inputs.get("destination") {
query_pairs.push(("destination", super::message_to_str(val)));
}
if let Some(val) = inputs.get("mode") {
query_pairs.push(("mode", super::message_to_str(val)));
}
if let Some(val) = inputs.get("waypoints") {
query_pairs.push(("waypoints", super::message_to_str(val)));
}
if let Some(val) = inputs.get("avoid") {
query_pairs.push(("avoid", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if let Some(val) = inputs.get("units") {
query_pairs.push(("units", super::message_to_str(val)));
}
if let Some(val) = inputs.get("departure_time") {
query_pairs.push(("departure_time", super::message_to_str(val)));
}
if let Some(val) = inputs.get("arrival_time") {
query_pairs.push(("arrival_time", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /directions/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadDistanceMatrixActor,
inports::<100>(key, origins, destinations, mode, language, avoid, units, departure_time),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_distance_matrix(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/distancematrix/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("origins") {
query_pairs.push(("origins", super::message_to_str(val)));
}
if let Some(val) = inputs.get("destinations") {
query_pairs.push(("destinations", super::message_to_str(val)));
}
if let Some(val) = inputs.get("mode") {
query_pairs.push(("mode", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if let Some(val) = inputs.get("avoid") {
query_pairs.push(("avoid", super::message_to_str(val)));
}
if let Some(val) = inputs.get("units") {
query_pairs.push(("units", super::message_to_str(val)));
}
if let Some(val) = inputs.get("departure_time") {
query_pairs.push(("departure_time", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /distancematrix/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadElevationActor,
inports::<100>(key, locations, path, samples),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_elevation(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/elevation/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("locations") {
query_pairs.push(("locations", super::message_to_str(val)));
}
if let Some(val) = inputs.get("path") {
query_pairs.push(("path", super::message_to_str(val)));
}
if let Some(val) = inputs.get("samples") {
query_pairs.push(("samples", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /elevation/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadTimezoneActor,
inports::<100>(key, location, timestamp, language),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_timezone(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/timezone/json".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("location") {
query_pairs.push(("location", super::message_to_str(val)));
}
if let Some(val) = inputs.get("timestamp") {
query_pairs.push(("timestamp", super::message_to_str(val)));
}
if let Some(val) = inputs.get("language") {
query_pairs.push(("language", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /timezone/json failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadPlacePhotoActor,
inports::<100>(key, photo_reference, maxwidth, maxheight),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_place_photo(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/place/photo".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("photo_reference") {
query_pairs.push(("photo_reference", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxwidth") {
query_pairs.push(("maxwidth", super::message_to_str(val)));
}
if let Some(val) = inputs.get("maxheight") {
query_pairs.push(("maxheight", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /place/photo failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadRoadsActor,
inports::<100>(key, path, interpolate),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_roads(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/roads/v1/snapToRoads".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("path") {
query_pairs.push(("path", super::message_to_str(val)));
}
if let Some(val) = inputs.get("interpolate") {
query_pairs.push(("interpolate", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /roads/v1/snapToRoads failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadSpeedLimitsActor,
inports::<100>(key, path, placeId, units),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_speed_limits(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/roads/v1/speedLimits".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if let Some(val) = inputs.get("path") {
query_pairs.push(("path", super::message_to_str(val)));
}
if let Some(val) = inputs.get("placeId") {
query_pairs.push(("placeId", super::message_to_str(val)));
}
if let Some(val) = inputs.get("units") {
query_pairs.push(("units", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /roads/v1/speedLimits failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
GoogleMapsReadGeolocationActor,
inports::<100>(key, homeMobileCountryCode, homeMobileNetworkCode, radioType, carrier, cellTowers, wifiAccessPoints),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn google_maps_read_geolocation(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/geolocation/v1/geolocate".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("key") {
query_pairs.push(("key", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("homeMobileCountryCode") {
body.insert("homeMobileCountryCode".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("homeMobileNetworkCode") {
body.insert("homeMobileNetworkCode".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("radioType") {
body.insert("radioType".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("carrier") {
body.insert("carrier".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("cellTowers") {
body.insert("cellTowers".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("wifiAccessPoints") {
body.insert("wifiAccessPoints".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /geolocation/v1/geolocate failed: {}", e).into()),
);
}
}
Ok(output)
}