CanMan/src/config.rs
Jason Tudisco 360ecbdad0 Initial commit: CAN Service + examples (can-sync v1, canfs, filemanager, paste)
CAN Service: content-addressable storage with HTTP API, SQLite metadata,
file-based blob storage, thumbnail generation, and integrity verification.

can-sync v1: P2P sync sidecar using iroh-docs for encrypted peer-to-peer
replication with library/filter-based selective sync. Fully builds but
being superseded by v2 (simplified full-mirror approach).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:32:04 -06:00

113 lines
3.2 KiB
Rust

use serde::Deserialize;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
pub storage_root: PathBuf,
#[serde(default = "default_admin_token")]
pub admin_token: String,
#[serde(default = "default_true")]
pub enable_thumbnail_cache: bool,
#[serde(default = "default_rebuild_threshold")]
pub rebuild_error_threshold: u32,
#[serde(default = "default_verify_interval")]
pub verify_interval_hours: u64,
}
fn default_admin_token() -> String {
"changeme".to_string()
}
fn default_true() -> bool {
true
}
fn default_rebuild_threshold() -> u32 {
50
}
fn default_verify_interval() -> u64 {
12
}
impl Config {
pub fn load(path: &Path) -> anyhow::Result<Self> {
let contents = std::fs::read_to_string(path)?;
let config: Config = serde_yaml::from_str(&contents)?;
Ok(config)
}
pub fn db_path(&self) -> PathBuf {
self.storage_root.join(".can.db")
}
pub fn trash_dir(&self) -> PathBuf {
self.storage_root.join(".trash")
}
pub fn thumbs_dir(&self) -> PathBuf {
self.storage_root.join(".thumbs")
}
pub fn ensure_dirs(&self) -> anyhow::Result<()> {
std::fs::create_dir_all(&self.storage_root)?;
std::fs::create_dir_all(self.trash_dir())?;
if self.enable_thumbnail_cache {
std::fs::create_dir_all(self.thumbs_dir())?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_load_config() {
let dir = TempDir::new().unwrap();
let config_path = dir.path().join("config.yaml");
std::fs::write(
&config_path,
r#"
storage_root: "/tmp/can_test"
admin_token: "test_token"
enable_thumbnail_cache: false
rebuild_error_threshold: 10
verify_interval_hours: 6
"#,
)
.unwrap();
let config = Config::load(&config_path).unwrap();
assert_eq!(config.storage_root, PathBuf::from("/tmp/can_test"));
assert_eq!(config.admin_token, "test_token");
assert!(!config.enable_thumbnail_cache);
assert_eq!(config.rebuild_error_threshold, 10);
assert_eq!(config.verify_interval_hours, 6);
}
#[test]
fn test_config_defaults() {
let dir = TempDir::new().unwrap();
let config_path = dir.path().join("config.yaml");
std::fs::write(&config_path, "storage_root: /tmp/test\n").unwrap();
let config = Config::load(&config_path).unwrap();
assert_eq!(config.admin_token, "changeme");
assert!(config.enable_thumbnail_cache);
assert_eq!(config.rebuild_error_threshold, 50);
assert_eq!(config.verify_interval_hours, 12);
}
#[test]
fn test_derived_paths() {
let dir = TempDir::new().unwrap();
let config_path = dir.path().join("config.yaml");
std::fs::write(&config_path, "storage_root: /data/can\n").unwrap();
let config = Config::load(&config_path).unwrap();
assert_eq!(config.db_path(), PathBuf::from("/data/can/.can.db"));
assert_eq!(config.trash_dir(), PathBuf::from("/data/can/.trash"));
assert_eq!(config.thumbs_dir(), PathBuf::from("/data/can/.thumbs"));
}
}