use log::info;
use serde::{Deserialize, Serialize};
use std::fs;
use crate::serial::config::SerialConfig;
use crate::tftp::client::config::ClientConfig;
use crate::tftp::client::config::TftpcConfigFile;
use crate::tftp::server::config::Config as TftpdConfig;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AppConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tftpd: Option<TftpdConfig>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tftpc: Option<TftpcConfigFile>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub serial: Option<SerialConfig>,
}
impl AppConfig {
pub fn load_from_file(path: &str) -> anyhow::Result<Self> {
let content = fs::read_to_string(path)?;
let config: AppConfig = toml::from_str(&content)?;
Ok(config)
}
pub fn generate_config_file(force: bool) -> anyhow::Result<()> {
use std::io::Write;
let config_path = ".xtool.toml";
if std::path::Path::new(config_path).exists() && !force {
anyhow::bail!(
"Configuration file {} already exists. Use --force to overwrite.",
config_path
);
}
let config_content = Self::generate_full_config();
let mut file = fs::File::create(config_path)?;
file.write_all(config_content.as_bytes())?;
info!("Configuration file generated: {}", config_path);
info!("Contains full configuration (server + client)");
info!("Please edit this file to customize configuration");
Ok(())
}
pub fn generate_full_config() -> String {
let config = AppConfig {
tftpd: Some(TftpdConfig::with_defaults()),
tftpc: Some(TftpcConfigFile {
get: Some(ClientConfig::new("127.0.0.1".to_string(), 69)),
put: Some(ClientConfig::new("127.0.0.1".to_string(), 69)),
}),
serial: Some(SerialConfig {
uart: Some("COM1".to_string()),
baud: Some(115200),
net_port: Some(5432),
net_bind: Some("0.0.0.0".to_string()),
}),
};
let toml_content = toml::to_string_pretty(&config).unwrap();
format!(
"# xtool configuration file\n# All fields are optional, command line arguments override config file values\n\n{}",
toml_content
)
}
}