use serde::{Deserialize, Serialize};
use std::sync::LazyLock;
use std::time::Duration;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
#[derive(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 actor_shutdown: u64,
pub system_shutdown: u64,
pub read_only_handler_flush: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LimitsConfig {
pub concurrent_handlers_high_water_mark: usize,
pub actor_inbox_capacity: usize,
pub dummy_channel_size: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DefaultsConfig {
pub actor_name: String,
pub root_ern: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TracingConfig {
pub debug: String,
pub trace: String,
pub info: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathsConfig {
pub logs: String,
pub cache: String,
pub data: String,
pub config: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BehaviorConfig {
pub enable_tracing: bool,
pub enable_metrics: bool,
}
impl Default for TimeoutConfig {
fn default() -> Self {
Self {
actor_shutdown: 10_000,
system_shutdown: 30_000,
read_only_handler_flush: 10,
}
}
}
impl Default for LimitsConfig {
fn default() -> Self {
Self {
concurrent_handlers_high_water_mark: 100,
actor_inbox_capacity: 512,
dummy_channel_size: 1,
}
}
}
impl Default for DefaultsConfig {
fn default() -> Self {
Self {
actor_name: "actor".to_string(),
root_ern: "default".to_string(),
}
}
}
impl Default for TracingConfig {
fn default() -> Self {
Self {
debug: "debug".to_string(),
trace: "trace".to_string(),
info: "info".to_string(),
}
}
}
impl Default for PathsConfig {
fn default() -> Self {
Self {
logs: "~/.local/share/acton/logs".to_string(),
cache: "~/.cache/acton".to_string(),
data: "~/.local/share/acton".to_string(),
config: "~/.config/acton".to_string(),
}
}
}
impl Default for BehaviorConfig {
fn default() -> Self {
Self {
enable_tracing: true,
enable_metrics: false,
}
}
}
impl ActonConfig {
pub const fn system_shutdown_timeout(&self) -> Duration {
Duration::from_millis(self.timeouts.system_shutdown)
}
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();
}
};
xdg_dirs.find_config_file("config.toml").map_or_else(
|| {
info!("No configuration file found, using defaults");
Self::default()
},
|path| {
info!("Loading configuration from: {}", path.display());
match std::fs::read_to_string(&path) {
Ok(config_str) => match toml::from_str::<Self>(&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()
}
}
},
)
}
}
pub static CONFIG: LazyLock<ActonConfig> = LazyLock::new(ActonConfig::load);