rama_ua/emulate/
provider.rs1use std::sync::Arc;
2
3use rama_core::Context;
4
5use crate::{
6 PlatformKind, UserAgentKind,
7 profile::{UserAgentDatabase, UserAgentProfile, UserAgentRuntimeProfile},
8};
9
10#[derive(Debug, Clone)]
11pub struct SelectedUserAgentProfile {
15 pub user_agent_header: Option<Arc<str>>,
17
18 pub ua_kind: UserAgentKind,
20 pub ua_version: Option<usize>,
22 pub platform: Option<PlatformKind>,
24
25 pub runtime: Option<Arc<UserAgentRuntimeProfile>>,
27}
28
29impl From<&UserAgentProfile> for SelectedUserAgentProfile {
30 fn from(profile: &UserAgentProfile) -> Self {
31 Self {
32 user_agent_header: profile.ua_str().map(Into::into),
33 ua_kind: profile.ua_kind,
34 ua_version: profile.ua_version,
35 platform: profile.platform,
36 runtime: profile.runtime.clone(),
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
42pub enum UserAgentSelectFallback {
53 #[default]
54 Abort,
56 Random,
58}
59
60pub trait UserAgentProvider<State>: Send + Sync + 'static {
82 fn select_user_agent_profile(&self, ctx: &Context<State>) -> Option<&UserAgentProfile>;
84}
85
86impl<State> UserAgentProvider<State> for () {
87 #[inline]
88 fn select_user_agent_profile(&self, _ctx: &Context<State>) -> Option<&UserAgentProfile> {
89 None
90 }
91}
92
93impl<State> UserAgentProvider<State> for UserAgentProfile {
94 #[inline]
95 fn select_user_agent_profile(&self, _ctx: &Context<State>) -> Option<&UserAgentProfile> {
96 Some(self)
97 }
98}
99
100impl<State> UserAgentProvider<State> for UserAgentDatabase {
101 #[inline]
102 fn select_user_agent_profile(&self, ctx: &Context<State>) -> Option<&UserAgentProfile> {
103 match (ctx.get(), ctx.get()) {
104 (Some(agent), _) => self.get(agent),
105 (None, Some(UserAgentSelectFallback::Random)) => self.rnd(),
106 (None, None | Some(UserAgentSelectFallback::Abort)) => None,
107 }
108 }
109}
110
111impl<State, P> UserAgentProvider<State> for Option<P>
112where
113 P: UserAgentProvider<State>,
114{
115 #[inline]
116 fn select_user_agent_profile(&self, ctx: &Context<State>) -> Option<&UserAgentProfile> {
117 self.as_ref().and_then(|p| p.select_user_agent_profile(ctx))
118 }
119}
120
121impl<State, P> UserAgentProvider<State> for Arc<P>
122where
123 P: UserAgentProvider<State>,
124{
125 #[inline]
126 fn select_user_agent_profile(&self, ctx: &Context<State>) -> Option<&UserAgentProfile> {
127 self.as_ref().select_user_agent_profile(ctx)
128 }
129}
130
131impl<State, P> UserAgentProvider<State> for Box<P>
132where
133 P: UserAgentProvider<State>,
134{
135 #[inline]
136 fn select_user_agent_profile(&self, ctx: &Context<State>) -> Option<&UserAgentProfile> {
137 self.as_ref().select_user_agent_profile(ctx)
138 }
139}
140
141macro_rules! impl_user_agent_provider_either {
142 ($id:ident, $($param:ident),+ $(,)?) => {
143 impl<State, $($param),+> UserAgentProvider<State> for ::rama_core::combinators::$id<$($param),+>
144 where
145 $(
146 $param: UserAgentProvider<State>,
147 )+
148 {
149 fn select_user_agent_profile(
150 &self,
151 ctx: &Context<State>,
152 ) -> Option<&UserAgentProfile> {
153 match self {
154 $(
155 ::rama_core::combinators::$id::$param(s) => s.select_user_agent_profile(ctx),
156 )+
157 }
158 }
159 }
160 };
161}
162
163::rama_core::combinators::impl_either!(impl_user_agent_provider_either);