speedtest-tui 0.1.1

A terminal-based network speed test tool with real-time gauges and graphs
use async_trait::async_trait;

use super::{Provider, ServerInfo};

pub struct CloudflareProvider {
    base_url: String,
}

impl CloudflareProvider {
    pub fn new() -> Self {
        Self {
            base_url: "https://speed.cloudflare.com".to_string(),
        }
    }
}

impl Default for CloudflareProvider {
    fn default() -> Self {
        Self::new()
    }
}

#[async_trait]
impl Provider for CloudflareProvider {
    fn name(&self) -> &str {
        "Cloudflare"
    }

    fn get_download_url(&self) -> String {
        format!("{}/__down", self.base_url)
    }

    fn get_upload_url(&self) -> String {
        format!("{}/__up", self.base_url)
    }

    fn get_ping_url(&self) -> String {
        self.base_url.clone()
    }

    async fn get_servers(&self) -> anyhow::Result<Vec<ServerInfo>> {
        // Cloudflare uses anycast, so there's effectively one "server"
        // that routes to the nearest edge
        Ok(vec![ServerInfo {
            id: "cloudflare".to_string(),
            name: "Cloudflare Edge".to_string(),
            location: "Anycast".to_string(),
            country: "Global".to_string(),
            host: self.base_url.clone(),
            latency_ms: None,
        }])
    }

    async fn select_best_server(&self) -> anyhow::Result<Option<ServerInfo>> {
        // Cloudflare automatically routes to the best server
        let mut server = ServerInfo {
            id: "cloudflare".to_string(),
            name: "Cloudflare Edge".to_string(),
            location: "Anycast".to_string(),
            country: "Global".to_string(),
            host: self.base_url.clone(),
            latency_ms: None,
        };

        // Measure latency
        if let Ok(ping) = crate::network::ping::single_ping(&self.base_url).await {
            server.latency_ms = Some(ping);
        }

        Ok(Some(server))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_cloudflare_urls() {
        let provider = CloudflareProvider::new();
        assert_eq!(
            provider.get_download_url(),
            "https://speed.cloudflare.com/__down"
        );
        assert_eq!(
            provider.get_upload_url(),
            "https://speed.cloudflare.com/__up"
        );
    }

    #[tokio::test]
    async fn test_cloudflare_servers() {
        let provider = CloudflareProvider::new();
        let servers = provider.get_servers().await.unwrap();
        assert_eq!(servers.len(), 1);
    }
}