Files
CjTui/src/core/config.rs
2026-02-16 22:05:54 -06:00

116 lines
3.0 KiB
Rust

use std::{fs, io, path::PathBuf};
use super::paths;
#[derive(Debug, Clone)]
pub struct Config {
pub base_url: String,
pub access_token: Option<String>,
pub user_id: Option<String>,
pub transcode_mbps: f32,
}
#[derive(Debug)]
pub enum ConfigError {
NotFound(PathBuf),
Io(io::Error),
Parse(String),
}
impl From<io::Error> for ConfigError {
fn from(e: io::Error) -> Self {
Self::Io(e)
}
}
pub fn config_path() -> Option<PathBuf> {
paths::app_config_dir().map(|d| d.join("config.toml"))
}
// Very small TOML-ish parser for now (no deps).
// Format:
// base_url = "http://..."
// access_token = "..."
pub fn load_config() -> Result<Config, ConfigError> {
let path = config_path().ok_or_else(|| ConfigError::Parse("No HOME/XDG dirs".into()))?;
if !path.exists() {
return Err(ConfigError::NotFound(path));
}
let s = fs::read_to_string(&path)?;
parse_config(&s).map_err(ConfigError::Parse)
}
fn parse_config(s: &str) -> Result<Config, String> {
let mut base_url: Option<String> = None;
let mut access_token: Option<String> = None;
let mut user_id: Option<String> = None;
let mut transcode_mbps: Option<f32> = None;
for (i, line) in s.lines().enumerate() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let (k, v) = line
.split_once('=')
.ok_or_else(|| format!("Line {}: expected key = value", i + 1))?;
let key = k.trim();
let mut val = v.trim().to_string();
// strip quotes if present
if val.starts_with('"') && val.ends_with('"') && val.len() >= 2 {
val = val[1..val.len() - 1].to_string();
}
match key {
"base_url" => base_url = Some(val),
"access_token" => access_token = Some(val),
"user_id" => user_id = Some(val),
"transcode_mbps" => {
// allow raw numbers or quoted numbers
if let Ok(n) = val.parse::<f32>() {
transcode_mbps = Some(n);
}
}
_ => {}
}
}
let base_url = base_url.ok_or_else(|| "Missing base_url".to_string())?;
Ok(Config {
base_url,
access_token,
user_id,
transcode_mbps: transcode_mbps.unwrap_or(5.0),
})
}
pub fn save_config(cfg: &Config) -> Result<(), ConfigError> {
let dir = paths::app_config_dir()
.ok_or_else(|| ConfigError::Parse("No HOME/XDG dirs".into()))?;
std::fs::create_dir_all(&dir)?;
let path = dir.join("config.toml");
let mut out = String::new();
out.push_str(&format!("base_url = \"{}\"\n", cfg.base_url));
if let Some(t) = &cfg.access_token {
out.push_str(&format!("access_token = \"{}\"\n", t));
}
if let Some(u) = &cfg.user_id {
out.push_str(&format!("user_id = \"{}\"\n", u));
}
out.push_str(&format!("transcode_mbps = {}\n", cfg.transcode_mbps));
std::fs::write(path, out)?;
Ok(())
}