66 lines
1.8 KiB
Rust
66 lines
1.8 KiB
Rust
use anyhow::{Result, bail};
|
|
use regex::Regex;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
const MIN_MEMORY_MB: u64 = 512;
|
|
|
|
pub const DEFAULTS_MEMORY: &str = "16G";
|
|
pub const VALID_KEYS: &[&str] = &["memory"];
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
|
|
pub struct Config {
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub memory: Option<String>,
|
|
}
|
|
|
|
fn config_dir() -> std::path::PathBuf {
|
|
dirs::home_dir()
|
|
.expect("cannot find home directory")
|
|
.join(".config")
|
|
.join("sandlot")
|
|
}
|
|
|
|
fn config_path() -> std::path::PathBuf {
|
|
config_dir().join("config.json")
|
|
}
|
|
|
|
pub fn validate_memory(v: &str) -> Result<String> {
|
|
let re = Regex::new(r"^[1-9]\d*[GMgm]$").unwrap();
|
|
if !re.is_match(v) {
|
|
bail!("Invalid memory value: {v} (must be a number followed by G or M, e.g. 16G)");
|
|
}
|
|
let num: u64 = v[..v.len() - 1].parse().unwrap();
|
|
let unit = v.chars().last().unwrap().to_ascii_uppercase();
|
|
let mb = if unit == 'G' { num * 1024 } else { num };
|
|
if mb < MIN_MEMORY_MB {
|
|
bail!("Memory too low: {v} (minimum {MIN_MEMORY_MB}M)");
|
|
}
|
|
Ok(v.to_uppercase())
|
|
}
|
|
|
|
pub async fn load() -> Config {
|
|
let path = config_path();
|
|
match tokio::fs::read_to_string(&path).await {
|
|
Ok(content) => serde_json::from_str(&content).unwrap_or_default(),
|
|
Err(_) => Config::default(),
|
|
}
|
|
}
|
|
|
|
pub async fn save(config: &Config) -> Result<()> {
|
|
let dir = config_dir();
|
|
tokio::fs::create_dir_all(&dir).await?;
|
|
let json = serde_json::to_string_pretty(config)? + "\n";
|
|
tokio::fs::write(config_path(), json).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_memory() -> Option<String> {
|
|
load().await.memory
|
|
}
|
|
|
|
pub async fn set_memory(value: String) -> Result<()> {
|
|
let mut config = load().await;
|
|
config.memory = Some(value);
|
|
save(&config).await
|
|
}
|