2026-01-24 22:59:20 +00:00

140 lines
4.2 KiB
Rust

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use tokio::fs;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ContainerRuntime {
Podman,
Docker,
Auto,
}
impl ContainerRuntime {
pub fn from_str(s: &str) -> Self {
match s.to_lowercase().as_str() {
"podman" => ContainerRuntime::Podman,
"docker" => ContainerRuntime::Docker,
"auto" | _ => ContainerRuntime::Auto,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BitcoinSimulation {
Mock,
Testnet,
Mainnet,
None,
}
impl BitcoinSimulation {
pub fn from_str(s: &str) -> Self {
match s.to_lowercase().as_str() {
"mock" => BitcoinSimulation::Mock,
"testnet" => BitcoinSimulation::Testnet,
"mainnet" => BitcoinSimulation::Mainnet,
"none" | _ => BitcoinSimulation::None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub data_dir: PathBuf,
pub bind_host: String,
pub bind_port: u16,
pub log_level: String,
// Dev mode configuration
pub dev_mode: bool,
pub container_runtime: ContainerRuntime,
pub port_offset: u16,
pub bitcoin_simulation: BitcoinSimulation,
pub dev_data_dir: PathBuf,
}
impl Config {
pub async fn load() -> Result<Self> {
// Default configuration
let mut config = Self::default();
// Try to load from config file
let config_path = Path::new("/etc/archipelago/config.toml");
if config_path.exists() {
let content = fs::read_to_string(config_path).await
.context("Failed to read config file")?;
let file_config: Config = toml::de::from_str(&content)
.context("Failed to parse config file")?;
config = file_config;
}
// Override with environment variables
if let Ok(data_dir) = std::env::var("ARCHIPELAGO_DATA_DIR") {
config.data_dir = PathBuf::from(data_dir);
}
if let Ok(bind) = std::env::var("ARCHIPELAGO_BIND") {
let parts: Vec<&str> = bind.split(':').collect();
if parts.len() == 2 {
config.bind_host = parts[0].to_string();
config.bind_port = parts[1].parse()
.context("Invalid port in ARCHIPELAGO_BIND")?;
}
}
if let Ok(level) = std::env::var("ARCHIPELAGO_LOG_LEVEL") {
config.log_level = level;
}
// Dev mode configuration
if let Ok(dev_mode) = std::env::var("ARCHIPELAGO_DEV_MODE") {
config.dev_mode = dev_mode.parse().unwrap_or(false);
}
if let Ok(runtime) = std::env::var("ARCHIPELAGO_CONTAINER_RUNTIME") {
config.container_runtime = ContainerRuntime::from_str(&runtime);
}
if let Ok(offset) = std::env::var("ARCHIPELAGO_PORT_OFFSET") {
config.port_offset = offset.parse()
.context("Invalid port offset in ARCHIPELAGO_PORT_OFFSET")?;
}
if let Ok(sim) = std::env::var("ARCHIPELAGO_BITCOIN_SIMULATION") {
config.bitcoin_simulation = BitcoinSimulation::from_str(&sim);
}
if let Ok(dev_data_dir) = std::env::var("ARCHIPELAGO_DEV_DATA_DIR") {
config.dev_data_dir = PathBuf::from(dev_data_dir);
}
// Ensure data directory exists
fs::create_dir_all(&config.data_dir).await
.context("Failed to create data directory")?;
// Ensure dev data directory exists if in dev mode
if config.dev_mode {
fs::create_dir_all(&config.dev_data_dir).await
.context("Failed to create dev data directory")?;
}
Ok(config)
}
}
impl Default for Config {
fn default() -> Self {
Self {
data_dir: PathBuf::from("/var/lib/archipelago"),
bind_host: "127.0.0.1".to_string(),
bind_port: 5959,
log_level: "info".to_string(),
dev_mode: false,
container_runtime: ContainerRuntime::Auto,
port_offset: 10000,
bitcoin_simulation: BitcoinSimulation::Mock,
dev_data_dir: PathBuf::from("/tmp/archipelago-dev"),
}
}
}