use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use tracing::info;
use crate::security::SecurityConfig;
use crate::streaming::StreamingConfig;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub app_name: String,
pub version: String,
pub data_dir: PathBuf,
pub log_level: String,
pub demo_mode: bool,
pub sensors: SensorConfig,
pub analysis: AnalysisConfig,
pub detection: DetectionConfig,
pub security: SecurityConfig,
pub streaming: StreamingConfig,
pub gui: GuiConfig,
pub database: DatabaseConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
app_name: "GlowBarn".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
data_dir: PathBuf::from("./data"),
log_level: "info".to_string(),
demo_mode: true,
sensors: SensorConfig::default(),
analysis: AnalysisConfig::default(),
detection: DetectionConfig::default(),
security: SecurityConfig::default(),
streaming: StreamingConfig::default(),
gui: GuiConfig::default(),
database: DatabaseConfig::default(),
}
}
}
impl Config {
pub fn load(path: &Path) -> Result<Self> {
let content = std::fs::read_to_string(path)?;
let config: Config = toml::from_str(&content)?;
info!("Loaded configuration from {:?}", path);
Ok(config)
}
pub fn save(&self, path: &Path) -> Result<()> {
let content = toml::to_string_pretty(self)?;
std::fs::write(path, content)?;
info!("Saved configuration to {:?}", path);
Ok(())
}
pub fn load_or_create(path: &Path) -> Result<Self> {
if path.exists() {
Self::load(path)
} else {
let config = Self::default();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
config.save(path)?;
Ok(config)
}
}
pub fn config_dir() -> PathBuf {
dirs::config_dir()
.map(|d| d.join("glowbarn"))
.unwrap_or_else(|| PathBuf::from("./config"))
}
pub fn default_path() -> PathBuf {
Self::config_dir().join("config.toml")
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SensorConfig {
pub sample_rate: f64,
pub buffer_size: usize,
pub calibration_interval_secs: u64,
pub auto_discover: bool,
pub serial_port: Option<String>,
pub i2c_bus: Option<u8>,
pub spi_device: Option<String>,
}
impl Default for SensorConfig {
fn default() -> Self {
Self {
sample_rate: 100.0,
buffer_size: 10000,
calibration_interval_secs: 3600,
auto_discover: true,
serial_port: None,
i2c_bus: Some(1),
spi_device: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalysisConfig {
pub entropy_window: usize,
pub anomaly_threshold: f64,
pub fft_size: usize,
pub gpu_enabled: bool,
pub worker_threads: usize,
pub multiscale_entropy: bool,
pub entropy_scales: usize,
}
impl Default for AnalysisConfig {
fn default() -> Self {
Self {
entropy_window: 1000,
anomaly_threshold: 0.7,
fft_size: 2048,
gpu_enabled: false,
worker_threads: 4,
multiscale_entropy: true,
entropy_scales: 10,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DetectionConfig {
pub min_confidence: f64,
pub fusion_enabled: bool,
pub fusion_method: FusionMethod,
pub correlation_window_ms: u64,
pub min_correlated_sensors: usize,
pub classification_enabled: bool,
pub alert_threshold: Severity,
}
impl Default for DetectionConfig {
fn default() -> Self {
Self {
min_confidence: 0.5,
fusion_enabled: true,
fusion_method: FusionMethod::DempsterShafer,
correlation_window_ms: 2000,
min_correlated_sensors: 2,
classification_enabled: true,
alert_threshold: Severity::Medium,
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum FusionMethod {
Bayesian,
DempsterShafer,
WeightedAverage,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum Severity {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GuiConfig {
pub width: u32,
pub height: u32,
pub vsync: bool,
pub theme: Theme,
pub font_size: f32,
pub show_fps: bool,
pub waveform_history: usize,
pub thermal_colormap: Colormap,
pub alert_sound: bool,
}
impl Default for GuiConfig {
fn default() -> Self {
Self {
width: 1400,
height: 900,
vsync: true,
theme: Theme::Dark,
font_size: 14.0,
show_fps: false,
waveform_history: 500,
thermal_colormap: Colormap::Inferno,
alert_sound: true,
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum Theme {
Dark,
Light,
System,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum Colormap {
Inferno,
Viridis,
Plasma,
Magma,
Turbo,
Grayscale,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
pub enabled: bool,
pub path: PathBuf,
pub max_size_mb: u64,
pub retention_days: u32,
pub flush_interval_secs: u64,
pub compression: bool,
}
impl Default for DatabaseConfig {
fn default() -> Self {
Self {
enabled: true,
path: PathBuf::from("./data/glowbarn.db"),
max_size_mb: 1024,
retention_days: 30,
flush_interval_secs: 10,
compression: true,
}
}
}