unleash_api_client/
context.rs

1// Copyright 2020 Cognite AS
2//! <https://docs.getunleash.io/user_guide/unleash_context>
3use chrono::Utc;
4use std::{collections::HashMap, net::IpAddr};
5
6use chrono::DateTime;
7use serde::{de, Deserialize};
8
9// Custom IP Address newtype that can be deserialised from strings e.g. 127.0.0.1 for use with tests.
10#[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            // Deserialize from a human-readable string like "127.0.0.1".
20            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}