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