use rama_core::extensions::{Extension, Extensions};
use rama_utils::str::arcstr::ArcStr;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use crate::{
PlatformKind, UserAgentKind,
profile::{UserAgentDatabase, UserAgentProfile, UserAgentRuntimeProfile},
};
#[derive(Debug, Clone, Serialize, Deserialize, Extension)]
#[extension(tags(ua))]
pub struct SelectedUserAgentProfile {
pub user_agent_header: Option<ArcStr>,
pub ua_kind: UserAgentKind,
pub ua_version: Option<usize>,
pub platform: Option<PlatformKind>,
pub runtime: Option<Arc<UserAgentRuntimeProfile>>,
}
impl From<&UserAgentProfile> for SelectedUserAgentProfile {
fn from(profile: &UserAgentProfile) -> Self {
Self {
user_agent_header: profile.ua_str().map(Into::into),
ua_kind: profile.ua_kind,
ua_version: profile.ua_version,
platform: profile.platform,
runtime: profile.runtime.clone(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Extension)]
#[extension(tags(ua))]
pub enum UserAgentSelectFallback {
#[default]
Abort,
Random,
}
pub trait UserAgentProvider: Send + Sync + 'static {
fn select_user_agent_profile(&self, extensions: &Extensions) -> Option<&UserAgentProfile>;
}
impl UserAgentProvider for () {
#[inline]
fn select_user_agent_profile(&self, _extensions: &Extensions) -> Option<&UserAgentProfile> {
None
}
}
impl UserAgentProvider for UserAgentProfile {
#[inline]
fn select_user_agent_profile(&self, _extensions: &Extensions) -> Option<&UserAgentProfile> {
Some(self)
}
}
impl UserAgentProvider for UserAgentDatabase {
#[inline]
fn select_user_agent_profile(&self, extensions: &Extensions) -> Option<&UserAgentProfile> {
match (extensions.get_ref(), extensions.get_ref()) {
(Some(agent), _) => self.get(agent),
(None, Some(UserAgentSelectFallback::Random)) => self.rnd(),
(None, None | Some(UserAgentSelectFallback::Abort)) => None,
}
}
}
impl<P> UserAgentProvider for Option<P>
where
P: UserAgentProvider,
{
#[inline]
fn select_user_agent_profile(&self, extensions: &Extensions) -> Option<&UserAgentProfile> {
self.as_ref()
.and_then(|p| p.select_user_agent_profile(extensions))
}
}
impl<P> UserAgentProvider for Arc<P>
where
P: UserAgentProvider,
{
#[inline]
fn select_user_agent_profile(&self, extensions: &Extensions) -> Option<&UserAgentProfile> {
self.as_ref().select_user_agent_profile(extensions)
}
}
impl<P> UserAgentProvider for Box<P>
where
P: UserAgentProvider,
{
#[inline]
fn select_user_agent_profile(&self, extensions: &Extensions) -> Option<&UserAgentProfile> {
self.as_ref().select_user_agent_profile(extensions)
}
}
macro_rules! impl_user_agent_provider_either {
($id:ident, $($param:ident),+ $(,)?) => {
impl< $($param),+> UserAgentProvider for ::rama_core::combinators::$id<$($param),+>
where
$(
$param: UserAgentProvider,
)+
{
fn select_user_agent_profile(
&self,
extensions: &Extensions,
) -> Option<&UserAgentProfile> {
match self {
$(
::rama_core::combinators::$id::$param(s) => s.select_user_agent_profile(extensions),
)+
}
}
}
};
}
::rama_core::combinators::impl_either!(impl_user_agent_provider_either);