Denis Drakhnia
1 year ago
7 changed files with 255 additions and 62 deletions
@ -0,0 +1,15 @@ |
|||||||
|
# Default config file |
||||||
|
|
||||||
|
[log] |
||||||
|
# Possible values: 0-5, off, error, warn, info, debug, trace |
||||||
|
level = "warn" |
||||||
|
|
||||||
|
[server] |
||||||
|
ip = "0.0.0.0" |
||||||
|
port = 27010 |
||||||
|
|
||||||
|
[server.timeout] |
||||||
|
# Time in seconds while challenge is valid |
||||||
|
challenge = 300 |
||||||
|
# Time in seconds while server is valid |
||||||
|
server = 300 |
@ -0,0 +1,142 @@ |
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
// SPDX-FileCopyrightText: 2023 Denis Drakhnia <numas13@gmail.com>
|
||||||
|
|
||||||
|
use std::fs; |
||||||
|
use std::io; |
||||||
|
use std::net::{IpAddr, Ipv4Addr}; |
||||||
|
use std::path::Path; |
||||||
|
|
||||||
|
use log::LevelFilter; |
||||||
|
use serde::{de::Error as _, Deserialize, Deserializer}; |
||||||
|
use thiserror::Error; |
||||||
|
|
||||||
|
pub const DEFAULT_CONFIG_PATH: &str = "config/main.toml"; |
||||||
|
|
||||||
|
pub const DEFAULT_MASTER_SERVER_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)); |
||||||
|
pub const DEFAULT_MASTER_SERVER_PORT: u16 = 27010; |
||||||
|
pub const DEFAULT_TIMEOUT: u32 = 300; |
||||||
|
|
||||||
|
#[derive(Debug, Error)] |
||||||
|
pub enum Error { |
||||||
|
#[error(transparent)] |
||||||
|
Toml(#[from] toml::de::Error), |
||||||
|
#[error(transparent)] |
||||||
|
Io(#[from] io::Error), |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)] |
||||||
|
#[serde(deny_unknown_fields)] |
||||||
|
pub struct Config { |
||||||
|
#[serde(default)] |
||||||
|
pub log: LogConfig, |
||||||
|
#[serde(default)] |
||||||
|
pub server: ServerConfig, |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)] |
||||||
|
#[serde(deny_unknown_fields)] |
||||||
|
pub struct LogConfig { |
||||||
|
#[serde(default = "default_log_level")] |
||||||
|
#[serde(deserialize_with = "deserialize_log_level")] |
||||||
|
pub level: LevelFilter, |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for LogConfig { |
||||||
|
fn default() -> Self { |
||||||
|
Self { |
||||||
|
level: default_log_level(), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)] |
||||||
|
#[serde(deny_unknown_fields)] |
||||||
|
pub struct ServerConfig { |
||||||
|
#[serde(default = "default_server_ip")] |
||||||
|
pub ip: IpAddr, |
||||||
|
#[serde(default = "default_server_port")] |
||||||
|
pub port: u16, |
||||||
|
#[serde(default)] |
||||||
|
pub timeout: TimeoutConfig, |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for ServerConfig { |
||||||
|
fn default() -> Self { |
||||||
|
Self { |
||||||
|
ip: default_server_ip(), |
||||||
|
port: default_server_port(), |
||||||
|
timeout: Default::default(), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)] |
||||||
|
#[serde(deny_unknown_fields)] |
||||||
|
pub struct TimeoutConfig { |
||||||
|
#[serde(default = "default_timeout")] |
||||||
|
pub challenge: u32, |
||||||
|
#[serde(default = "default_timeout")] |
||||||
|
pub server: u32, |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for TimeoutConfig { |
||||||
|
fn default() -> Self { |
||||||
|
Self { |
||||||
|
challenge: default_timeout(), |
||||||
|
server: default_timeout(), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn default_log_level() -> LevelFilter { |
||||||
|
LevelFilter::Warn |
||||||
|
} |
||||||
|
|
||||||
|
fn default_server_ip() -> IpAddr { |
||||||
|
DEFAULT_MASTER_SERVER_IP |
||||||
|
} |
||||||
|
|
||||||
|
fn default_server_port() -> u16 { |
||||||
|
DEFAULT_MASTER_SERVER_PORT |
||||||
|
} |
||||||
|
|
||||||
|
fn default_timeout() -> u32 { |
||||||
|
DEFAULT_TIMEOUT |
||||||
|
} |
||||||
|
|
||||||
|
fn deserialize_log_level<'de, D>(de: D) -> Result<LevelFilter, D::Error> |
||||||
|
where |
||||||
|
D: Deserializer<'de>, |
||||||
|
{ |
||||||
|
let s = <&str>::deserialize(de)?; |
||||||
|
parse_log_level(s) |
||||||
|
.ok_or_else(|| D::Error::custom(format!("Invalid value for log option: \"{}\"", s))) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn parse_log_level(s: &str) -> Option<LevelFilter> { |
||||||
|
use LevelFilter as E; |
||||||
|
|
||||||
|
let level_filter = match s { |
||||||
|
_ if "off".starts_with(s) => E::Off, |
||||||
|
_ if "error".starts_with(s) => E::Error, |
||||||
|
_ if "warn".starts_with(s) => E::Warn, |
||||||
|
_ if "info".starts_with(s) => E::Info, |
||||||
|
_ if "debug".starts_with(s) => E::Debug, |
||||||
|
_ if "trace".starts_with(s) => E::Trace, |
||||||
|
_ => match s.parse::<u8>() { |
||||||
|
Ok(0) => E::Off, |
||||||
|
Ok(1) => E::Error, |
||||||
|
Ok(2) => E::Warn, |
||||||
|
Ok(3) => E::Info, |
||||||
|
Ok(4) => E::Debug, |
||||||
|
Ok(5) => E::Trace, |
||||||
|
_ => return None, |
||||||
|
}, |
||||||
|
}; |
||||||
|
Some(level_filter) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn load<P: AsRef<Path>>(path: P) -> Result<Config, Error> { |
||||||
|
let data = fs::read(path)?; |
||||||
|
Ok(toml::de::from_slice(&data)?) |
||||||
|
} |
Loading…
Reference in new issue