use serde::{Deserialize, Serialize};
use std::time::Duration;
use lazy_static::lazy_static;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ActonConfig {
pub timeouts: TimeoutConfig,
pub limits: LimitsConfig,
pub defaults: DefaultsConfig,
pub tracing: TracingConfig,
pub paths: PathsConfig,
pub behavior: BehaviorConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeoutConfig {
pub agent_shutdown_timeout_ms: u64,
pub system_shutdown_timeout_ms: u64,
pub read_only_handler_flush_ms: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LimitsConfig {
pub concurrent_handlers_high_water_mark: usize,
pub agent_inbox_capacity: usize,
pub dummy_channel_size: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DefaultsConfig {
pub agent_name: String,
pub root_ern: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TracingConfig {
pub debug_level: String,
pub trace_level: String,
pub info_level: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathsConfig {
pub log_directory: String,
pub cache_directory: String,
pub data_directory: String,
pub config_directory: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BehaviorConfig {
pub enable_tracing: bool,
pub enable_metrics: bool,
}
impl Default for ActonConfig {
fn default() -> Self {
Self {
timeouts: TimeoutConfig::default(),
limits: LimitsConfig::default(),
defaults: DefaultsConfig::default(),
tracing: TracingConfig::default(),
paths: PathsConfig::default(),
behavior: BehaviorConfig::default(),
}
}
}
impl Default for TimeoutConfig {
fn default() -> Self {
Self {
agent_shutdown_timeout_ms: 10_000,
system_shutdown_timeout_ms: 30_000,
read_only_handler_flush_ms: 10,
}
}
}
impl Default for LimitsConfig {
fn default() -> Self {
Self {
concurrent_handlers_high_water_mark: 100,
agent_inbox_capacity: 255,
dummy_channel_size: 1,
}
}
}
impl Default for DefaultsConfig {
fn default() -> Self {
Self {
agent_name: "agent".to_string(),
root_ern: "default".to_string(),
}
}
}
impl Default for TracingConfig {
fn default() -> Self {
Self {
debug_level: "debug".to_string(),
trace_level: "trace".to_string(),
info_level: "info".to_string(),
}
}
}
impl Default for PathsConfig {
fn default() -> Self {
Self {
log_directory: "~/.local/share/acton/logs".to_string(),
cache_directory: "~/.cache/acton".to_string(),
data_directory: "~/.local/share/acton".to_string(),
config_directory: "~/.config/acton".to_string(),
}
}
}
impl Default for BehaviorConfig {
fn default() -> Self {
Self {
enable_tracing: true,
enable_metrics: false,
}
}
}
impl ActonConfig {
pub fn agent_shutdown_timeout(&self) -> Duration {
Duration::from_millis(self.timeouts.agent_shutdown_timeout_ms)
}
pub fn system_shutdown_timeout(&self) -> Duration {
Duration::from_millis(self.timeouts.system_shutdown_timeout_ms)
}
pub fn read_only_handler_flush(&self) -> Duration {
Duration::from_millis(self.timeouts.read_only_handler_flush_ms)
}
pub fn load() -> Self {
use tracing::{error, info};
let xdg_dirs = match xdg::BaseDirectories::with_prefix("acton") {
Ok(dirs) => dirs,
Err(e) => {
error!("Failed to initialize XDG directories: {}", e);
return Self::default();
}
};
let config_path = xdg_dirs.find_config_file("config.toml");
match config_path {
Some(path) => {
info!("Loading configuration from: {}", path.display());
match std::fs::read_to_string(&path) {
Ok(config_str) => {
match toml::from_str::<ActonConfig>(&config_str) {
Ok(config) => {
info!("Successfully loaded configuration");
config
}
Err(e) => {
error!("Failed to parse configuration file {}: {}", path.display(), e);
Self::default()
}
}
}
Err(e) => {
error!("Failed to read configuration file {}: {}", path.display(), e);
Self::default()
}
}
}
None => {
info!("No configuration file found, using defaults");
Self::default()
}
}
}
pub fn config_directory() -> std::path::PathBuf {
match xdg::BaseDirectories::with_prefix("acton") {
Ok(dirs) => dirs.get_config_home(),
Err(_) => std::path::PathBuf::from("~/.config/acton"),
}
}
}
lazy_static! {
pub static ref CONFIG: ActonConfig = ActonConfig::load();
}