1use crate::extract::FromContext;
8use std::cell::RefCell;
9use std::convert::Infallible;
10use std::rc::Rc;
11
12const PDK_AGENT: &str = "PDK-HttpClient";
13const PDK_VERSION: &str = env!("CARGO_PKG_VERSION");
14
15thread_local! {
16 static USER_AGENT: RefCell<Option<Rc<UserAgent>>> = const { RefCell::new(None) };
19}
20
21impl<C> FromContext<C> for Rc<UserAgent> {
22 type Error = Infallible;
23
24 fn from_context(_context: &C) -> Result<Self, Self::Error> {
25 let agent = USER_AGENT
26 .with(|cell| cell.borrow().clone())
27 .unwrap_or_default();
28
29 Ok(Rc::clone(&agent))
30 }
31}
32
33pub fn set_user_agent(user_agent: UserAgent) {
36 USER_AGENT.with(|cell| cell.replace(Some(Rc::new(user_agent))));
37}
38
39pub struct UserAgent {
41 value: String,
42}
43
44impl Default for UserAgent {
45 fn default() -> Self {
46 UserAgent::new(PDK_AGENT, PDK_VERSION)
47 }
48}
49
50impl UserAgent {
51 pub fn new(key: &str, version: &str) -> Self {
53 UserAgent {
54 value: format!("{key}/{version}"),
55 }
56 }
57
58 pub fn value(&self) -> &str {
60 self.value.as_str()
61 }
62}
63
64#[cfg(test)]
65mod test {
66 use crate::user_agent::UserAgent;
67
68 #[test]
69 fn default() {
70 assert_eq!(
71 UserAgent::default().value(),
72 &format!("PDK-HttpClient/{}", env!("CARGO_PKG_VERSION"))
73 );
74 }
75}