use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
#[serde(default)]
pub web: WebConfig,
#[serde(default)]
pub dbus: DbusConfig,
#[serde(default = "default_state_dir")]
pub state_dir: String,
#[serde(default = "default_refresh_interval")]
pub refresh_interval: u64,
#[serde(default = "default_heartbeat")]
pub heartbeat: u64,
#[serde(default)]
pub devices: DevicesConfig,
#[serde(default)]
pub canvas: CanvasConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebConfig {
#[serde(default)]
pub enable: bool,
#[serde(default = "default_listen")]
pub listen: String,
}
impl Default for WebConfig {
fn default() -> Self {
Self {
enable: false,
listen: default_listen(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum DbusBusType {
#[default]
Auto,
Session,
System,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DbusConfig {
#[serde(default)]
pub bus: DbusBusType,
}
impl Default for DbusConfig {
fn default() -> Self {
Self {
bus: DbusBusType::Auto,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DevicesConfig {
#[serde(default = "default_lcd_device")]
pub lcd: String,
#[serde(default = "default_led_device")]
pub led: String,
}
impl Default for DevicesConfig {
fn default() -> Self {
Self {
lcd: default_lcd_device(),
led: default_led_device(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CanvasConfig {
#[serde(default = "default_width")]
pub width: u32,
#[serde(default = "default_height")]
pub height: u32,
}
impl Default for CanvasConfig {
fn default() -> Self {
Self {
width: default_width(),
height: default_height(),
}
}
}
fn default_listen() -> String {
"[::1]:8686".to_string()
}
fn default_state_dir() -> String {
if let Ok(state_dir) = std::env::var("STATE_DIRECTORY") {
state_dir
} else if let Ok(state_home) = std::env::var("XDG_STATE_HOME") {
format!("{}/ht32-panel", state_home)
} else if let Ok(home) = std::env::var("HOME") {
format!("{}/.local/state/ht32-panel", home)
} else {
"/var/lib/ht32-panel".to_string()
}
}
fn default_refresh_interval() -> u64 {
2500
}
fn default_heartbeat() -> u64 {
1000
}
fn default_lcd_device() -> String {
"auto".to_string()
}
fn default_led_device() -> String {
"/dev/ttyUSB0".to_string()
}
fn default_width() -> u32 {
320
}
fn default_height() -> u32 {
170
}
impl Config {
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
let content =
std::fs::read_to_string(path.as_ref()).context("Failed to read configuration file")?;
let config: Config = toml::from_str(&content).context("Failed to parse configuration")?;
Ok(config)
}
}
impl Default for Config {
fn default() -> Self {
Self {
web: WebConfig::default(),
dbus: DbusConfig::default(),
state_dir: default_state_dir(),
refresh_interval: default_refresh_interval(),
heartbeat: default_heartbeat(),
devices: DevicesConfig::default(),
canvas: CanvasConfig::default(),
}
}
}