use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Config {
#[serde(default)]
pub general: GeneralConfig,
#[serde(default)]
pub theme: ThemeConfig,
#[serde(default)]
pub providers: ProvidersConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeneralConfig {
#[serde(default = "default_provider")]
pub default_provider: String,
#[serde(default = "default_true")]
pub auto_save_results: bool,
#[serde(default = "default_duration")]
pub test_duration_seconds: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThemeConfig {
#[serde(default = "default_theme")]
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ProvidersConfig {
#[serde(default)]
pub custom: CustomProviderConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomProviderConfig {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_download_url")]
pub download_url: String,
#[serde(default = "default_upload_url")]
pub upload_url: String,
}
fn default_provider() -> String {
"cloudflare".to_string()
}
fn default_true() -> bool {
true
}
fn default_duration() -> u64 {
15
}
fn default_theme() -> String {
"dark".to_string()
}
fn default_download_url() -> String {
"http://localhost:8080/download".to_string()
}
fn default_upload_url() -> String {
"http://localhost:8080/upload".to_string()
}
impl Default for GeneralConfig {
fn default() -> Self {
Self {
default_provider: default_provider(),
auto_save_results: default_true(),
test_duration_seconds: default_duration(),
}
}
}
impl Default for ThemeConfig {
fn default() -> Self {
Self {
name: default_theme(),
}
}
}
impl Default for CustomProviderConfig {
fn default() -> Self {
Self {
enabled: false,
download_url: default_download_url(),
upload_url: default_upload_url(),
}
}
}
impl Config {
pub fn config_dir() -> Result<PathBuf> {
let dir = dirs::home_dir()
.ok_or_else(|| anyhow::anyhow!("Could not find home directory"))?
.join(".speedtest-tui");
if !dir.exists() {
std::fs::create_dir_all(&dir)?;
}
Ok(dir)
}
pub fn config_path() -> Result<PathBuf> {
Ok(Self::config_dir()?.join("config.toml"))
}
pub fn load() -> Result<Self> {
let path = Self::config_path()?;
if path.exists() {
let content = std::fs::read_to_string(&path)?;
let config: Config = toml::from_str(&content)?;
Ok(config)
} else {
let config = Config::default();
config.save()?;
Ok(config)
}
}
pub fn save(&self) -> Result<()> {
let path = Self::config_path()?;
let content = toml::to_string_pretty(self)?;
std::fs::write(path, content)?;
Ok(())
}
}