leyline-http 0.1.0

HTTP client that mimics browsers on the wire
Documentation
use std::collections::HashMap;
use std::sync::LazyLock;

use serde::Deserialize;

use crate::tcp::TcpProfile;

#[derive(Deserialize)]
struct PlatformData {
    tcp: TcpProfile,
}

static PLATFORMS: LazyLock<HashMap<String, PlatformData>> = LazyLock::new(|| {
    toml::from_str(include_str!("../../profiles/platforms.toml"))
        .expect("built-in platform table is statically valid")
});

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[derive(Default)]
pub enum Platform {
    #[default]
    Windows,
    MacOS,
    Linux,
    Android,
    IOS,
    Host,
}

impl Platform {
    pub(crate) fn detect_host() -> Self {
        #[cfg(target_os = "windows")]
        {
            Self::Windows
        }
        #[cfg(target_os = "macos")]
        {
            Self::MacOS
        }
        #[cfg(target_os = "linux")]
        {
            Self::Linux
        }
        #[cfg(target_os = "android")]
        {
            Self::Android
        }
        #[cfg(target_os = "ios")]
        {
            Self::IOS
        }
        #[cfg(not(any(
            target_os = "windows",
            target_os = "macos",
            target_os = "linux",
            target_os = "android",
            target_os = "ios"
        )))]
        {
            Self::Windows
        }
    }

    #[must_use]
    pub(crate) fn resolve(self) -> Self {
        match self {
            Self::Host => Self::detect_host(),
            other => other,
        }
    }

    pub(crate) fn sec_ch_platform(&self) -> &'static str {
        match self {
            Self::Windows => "Windows",
            Self::MacOS => "macOS",
            Self::Linux => "Linux",
            Self::Android => "Android",
            Self::IOS => "iOS",
            Self::Host => Self::detect_host().sec_ch_platform(),
        }
    }

    pub(crate) fn mobile_flag(&self) -> &'static str {
        match self {
            Self::Android | Self::IOS => "?1",
            Self::Host => Self::detect_host().mobile_flag(),
            _ => "?0",
        }
    }

    #[must_use]
    pub fn tcp_profile(&self) -> TcpProfile {
        PLATFORMS
            .get(self.identity_key())
            .map(|data| data.tcp.clone())
            .unwrap_or_default()
    }

    bench_pub! {
        fn identity_key(&self) -> &'static str {
            match self {
                Self::Windows => "windows",
                Self::MacOS => "macos",
                Self::Linux => "linux",
                Self::Android => "android",
                Self::IOS => "ios",
                Self::Host => Self::detect_host().identity_key(),
            }
        }
    }
}

impl std::fmt::Display for Platform {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.sec_ch_platform())
    }
}