unleash_api_client/
context.rs1use chrono::Utc;
4use std::{collections::HashMap, net::IpAddr};
5
6use chrono::DateTime;
7use serde::{de, Deserialize};
8
9#[derive(Debug)]
11pub struct IPAddress(pub IpAddr);
12
13impl<'de> de::Deserialize<'de> for IPAddress {
14 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
15 where
16 D: de::Deserializer<'de>,
17 {
18 if deserializer.is_human_readable() {
19 let s = String::deserialize(deserializer)?;
21 s.parse::<IpAddr>()
22 .map_err(de::Error::custom)
23 .map(IPAddress)
24 } else {
25 unimplemented!();
26 }
27 }
28}
29
30#[derive(Debug, Default, Deserialize)]
31#[serde(deny_unknown_fields, rename_all = "camelCase")]
32pub struct Context {
33 pub user_id: Option<String>,
34 pub session_id: Option<String>,
35 pub remote_address: Option<IPAddress>,
36 #[serde(default, deserialize_with = "deserialize_context_properties")]
37 pub properties: HashMap<String, String>,
38 #[serde(default)]
39 pub app_name: String,
40 #[serde(default)]
41 pub environment: String,
42 pub current_time: Option<DateTime<Utc>>,
43}
44
45fn deserialize_context_properties<'de, D>(
46 deserializer: D,
47) -> Result<HashMap<String, String>, D::Error>
48where
49 D: serde::Deserializer<'de>,
50{
51 let map = HashMap::<String, Option<String>>::deserialize(deserializer)?;
52 let map: HashMap<String, String> = map
53 .into_iter()
54 .filter_map(|(key, value)| Some((key, value?)))
55 .collect();
56 Ok(map)
57}