mod custom;
mod fast;
mod librespeed;
mod ookla;
use std::sync::Arc;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use crate::errors::EngineResult;
use super::models::Server;
pub use custom::CustomProvider;
pub use fast::{parse_targets, FastProvider};
pub use librespeed::{builtin_servers, parse_server_list, LibreSpeedProvider};
pub use ookla::{parse_server_list as parse_ookla_server_list, OoklaProvider};
#[async_trait]
pub trait Provider: Send + Sync {
fn name(&self) -> &'static str;
async fn fetch_servers(&self) -> EngineResult<Vec<Server>>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ProviderKind {
#[default]
Librespeed,
Ookla,
Fast,
Custom,
}
impl ProviderKind {
#[must_use]
pub fn label(self) -> &'static str {
match self {
Self::Librespeed => "LibreSpeed",
Self::Ookla => "Ookla",
Self::Fast => "Fast.com",
Self::Custom => "Custom",
}
}
}
impl std::str::FromStr for ProviderKind {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.to_lowercase().as_str() {
"librespeed" => Ok(Self::Librespeed),
"ookla" | "speedtest" => Ok(Self::Ookla),
"fast" | "fast.com" => Ok(Self::Fast),
"custom" => Ok(Self::Custom),
other => Err(format!(
"unknown provider {other:?}; expected librespeed, ookla, fast or custom"
)),
}
}
}
pub fn create(kind: ProviderKind, custom_servers: Vec<Server>) -> EngineResult<Arc<dyn Provider>> {
match kind {
ProviderKind::Librespeed => Ok(Arc::new(LibreSpeedProvider::new(custom_servers)?)),
ProviderKind::Ookla => Ok(Arc::new(OoklaProvider::new()?)),
ProviderKind::Fast => Ok(Arc::new(FastProvider::new()?)),
ProviderKind::Custom => Ok(Arc::new(CustomProvider::new(custom_servers)?)),
}
}