veilid/veilid-cli/src/settings.rs

260 lines
6.8 KiB
Rust
Raw Normal View History

2021-11-22 16:28:30 +00:00
use directories::*;
2021-11-28 02:31:01 +00:00
2021-11-22 16:28:30 +00:00
use serde_derive::*;
use std::ffi::OsStr;
use std::net::{SocketAddr, ToSocketAddrs};
use std::path::{Path, PathBuf};
2022-06-26 21:00:05 +00:00
pub fn load_default_config() -> Result<config::Config, config::ConfigError> {
2021-11-22 16:28:30 +00:00
let default_config = r###"---
address: "localhost:5959"
autoconnect: true
autoreconnect: true
logging:
level: "info"
terminal:
enabled: false
file:
enabled: true
2022-07-02 15:41:25 +00:00
directory: '%LOGGING_FILE_DIRECTORY%'
2021-11-22 16:28:30 +00:00
append: true
interface:
node_log:
scrollback: 2048
command_line:
history_size: 2048
theme:
shadow: false
borders: "simple"
colors:
2023-06-21 02:18:59 +00:00
background : "black"
shadow : "black"
view : "black"
primary : "light cyan"
secondary : "cyan"
tertiary : "green"
title_primary : "light magenta"
title_secondary : "magenta"
highlight : "light white"
highlight_inactive : "white"
highlight_text : "black"
2021-11-22 16:28:30 +00:00
log_colors:
2023-06-21 02:18:59 +00:00
trace : "light blue"
debug : "light green"
info : "white"
warn : "light yellow"
error : "light red"
2022-06-26 21:00:05 +00:00
"###
.replace(
"%LOGGING_FILE_DIRECTORY%",
&Settings::get_default_log_directory().to_string_lossy(),
);
config::Config::builder()
.add_source(config::File::from_str(
&default_config,
config::FileFormat::Yaml,
))
.build()
2021-11-22 16:28:30 +00:00
}
pub fn load_config(
2022-06-26 21:00:05 +00:00
cfg: config::Config,
2021-11-22 16:28:30 +00:00
config_file: &Path,
2022-06-26 21:00:05 +00:00
) -> Result<config::Config, config::ConfigError> {
2021-11-22 16:28:30 +00:00
if let Some(config_file_str) = config_file.to_str() {
2022-06-26 21:00:05 +00:00
config::Config::builder()
.add_source(cfg)
.add_source(config::File::new(config_file_str, config::FileFormat::Yaml))
.build()
2021-11-22 16:28:30 +00:00
} else {
Err(config::ConfigError::Message(
"config file path is not valid UTF-8".to_owned(),
))
}
}
#[derive(Copy, Clone, Debug)]
pub enum LogLevel {
Error,
Warn,
Info,
Debug,
Trace,
}
impl<'de> serde::Deserialize<'de> for LogLevel {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.to_ascii_lowercase().as_str() {
"error" => Ok(LogLevel::Error),
"warn" => Ok(LogLevel::Warn),
"info" => Ok(LogLevel::Info),
"debug" => Ok(LogLevel::Debug),
"trace" => Ok(LogLevel::Trace),
_ => Err(serde::de::Error::custom(format!(
"Invalid log level: {}",
s
))),
}
}
}
pub fn convert_loglevel(log_level: LogLevel) -> log::LevelFilter {
match log_level {
LogLevel::Error => log::LevelFilter::Error,
LogLevel::Warn => log::LevelFilter::Warn,
LogLevel::Info => log::LevelFilter::Info,
LogLevel::Debug => log::LevelFilter::Debug,
LogLevel::Trace => log::LevelFilter::Trace,
}
}
#[derive(Debug)]
pub struct NamedSocketAddrs {
pub name: String,
pub addrs: Vec<SocketAddr>,
}
impl<'de> serde::Deserialize<'de> for NamedSocketAddrs {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
2022-03-13 16:45:36 +00:00
let addr_iter = s.to_socket_addrs().map_err(serde::de::Error::custom)?;
2021-11-22 16:28:30 +00:00
Ok(NamedSocketAddrs {
name: s,
addrs: addr_iter.collect(),
})
}
}
#[derive(Debug, Deserialize)]
pub struct Terminal {
pub enabled: bool,
}
#[derive(Debug, Deserialize)]
pub struct File {
pub enabled: bool,
pub directory: String,
pub append: bool,
}
#[derive(Debug, Deserialize)]
pub struct Logging {
pub terminal: Terminal,
pub file: File,
pub level: LogLevel,
}
#[derive(Debug, Deserialize)]
pub struct Colors {
pub background: String,
pub shadow: String,
pub view: String,
pub primary: String,
pub secondary: String,
pub tertiary: String,
pub title_primary: String,
pub title_secondary: String,
pub highlight: String,
pub highlight_inactive: String,
pub highlight_text: String,
}
#[derive(Debug, Deserialize)]
pub struct LogColors {
pub trace: String,
pub debug: String,
pub info: String,
pub warn: String,
pub error: String,
}
#[derive(Debug, Deserialize)]
pub struct Theme {
pub shadow: bool,
pub borders: String,
pub colors: Colors,
pub log_colors: LogColors,
}
#[derive(Debug, Deserialize)]
pub struct NodeLog {
pub scrollback: usize,
}
#[derive(Debug, Deserialize)]
pub struct CommandLine {
pub history_size: usize,
}
#[derive(Debug, Deserialize)]
pub struct Interface {
pub theme: Theme,
pub node_log: NodeLog,
pub command_line: CommandLine,
}
#[derive(Debug, Deserialize)]
pub struct Settings {
pub address: NamedSocketAddrs,
pub autoconnect: bool,
pub autoreconnect: bool,
pub logging: Logging,
pub interface: Interface,
}
impl Settings {
pub fn get_default_config_path() -> PathBuf {
// Get default configuration file location
2022-03-13 16:45:36 +00:00
let mut default_config_path =
if let Some(my_proj_dirs) = ProjectDirs::from("org", "Veilid", "Veilid") {
PathBuf::from(my_proj_dirs.config_dir())
} else {
PathBuf::from("./")
};
2021-11-22 16:28:30 +00:00
default_config_path.push("veilid-client.conf");
default_config_path
}
pub fn get_default_log_directory() -> PathBuf {
// Get default configuration file location
2022-03-13 16:45:36 +00:00
let mut default_log_directory =
if let Some(my_proj_dirs) = ProjectDirs::from("org", "Veilid", "Veilid") {
PathBuf::from(my_proj_dirs.config_dir())
} else {
PathBuf::from("./")
};
2021-11-22 16:28:30 +00:00
default_log_directory.push("logs/");
default_log_directory
}
2022-06-26 21:00:05 +00:00
pub fn new(config_file: Option<&OsStr>) -> Result<Self, config::ConfigError> {
2021-11-22 16:28:30 +00:00
// Load the default config
2022-06-26 21:00:05 +00:00
let mut cfg = load_default_config()?;
2021-11-22 16:28:30 +00:00
// Merge in the config file if we have one
2022-06-26 21:00:05 +00:00
if let Some(config_file) = config_file {
let config_file_path = Path::new(config_file);
2021-11-22 16:28:30 +00:00
// If the user specifies a config file on the command line then it must exist
2022-06-26 21:00:05 +00:00
cfg = load_config(cfg, config_file_path)?;
2021-11-22 16:28:30 +00:00
}
2022-06-26 21:00:05 +00:00
// Generate config
cfg.try_deserialize()
2021-11-22 16:28:30 +00:00
}
}
#[test]
fn test_default_config() {
2022-06-26 21:00:05 +00:00
let cfg = load_default_config().unwrap();
let settings = cfg.try_deserialize::<Settings>().unwrap();
2021-11-22 16:28:30 +00:00
println!("default settings: {:?}", settings);
}