statsig_rust/evaluation/user_agent_parsing/
ua_parser.rs

1use std::env;
2
3use crate::evaluation::dynamic_string::DynamicString;
4use crate::user::StatsigUserInternal;
5use crate::{log_w, DynamicValue};
6
7use super::experimental_ua_parser::ExperimentalUserAgentParser;
8use super::third_party_ua_parser::ThirdPartyUserAgentParser;
9
10lazy_static::lazy_static! {
11    static ref USE_EXPERIMENTAL_PARSER: bool = env::var("STATSIG_USE_EXPERIMENTAL_UAPARSER").is_ok_and(|v| v == "true" || v == "1");
12    static ref USER_AGENT_STRING: Option<DynamicString> = Some(DynamicString::from("userAgent".to_string()));
13}
14
15const TAG: &str = "UserAgentParser";
16const UNINITIALIZED_REASON: &str = "UAParserNotLoaded";
17
18pub struct UserAgentParser;
19
20impl UserAgentParser {
21    pub fn get_value_from_user_agent(
22        user: &StatsigUserInternal,
23        field: &Option<DynamicString>,
24        override_reason: &mut Option<&str>,
25    ) -> Option<DynamicValue> {
26        let field_lowered = match field {
27            Some(f) => f.lowercased_value.as_str(),
28            _ => return None,
29        };
30
31        let user_agent = match user.get_user_value(&USER_AGENT_STRING) {
32            Some(v) => match &v.string_value {
33                Some(s) => &s.value,
34                _ => return None,
35            },
36            None => return None,
37        };
38
39        if user_agent.len() > 1000 {
40            return None;
41        }
42
43        if *USE_EXPERIMENTAL_PARSER {
44            ExperimentalUserAgentParser::get_value_from_user_agent(field_lowered, user_agent)
45        } else {
46            let result =
47                ThirdPartyUserAgentParser::get_value_from_user_agent(field_lowered, user_agent);
48
49            match result {
50                Ok(v) => v,
51                Err(_) => {
52                    *override_reason = Some(UNINITIALIZED_REASON);
53                    log_w!(TAG, "Failed to load UA Parser. Check StatsigOptions.disable_user_agent_parsing and or wait_for_user_agent_init");
54                    None
55                }
56            }
57        }
58    }
59
60    pub fn load_parser() {
61        if *USE_EXPERIMENTAL_PARSER {
62            // noop
63        } else {
64            ThirdPartyUserAgentParser::load_parser();
65        }
66    }
67}