From c776c53d33200be623948e2f00856622eeab7b82 Mon Sep 17 00:00:00 2001 From: EAimTY Date: Thu, 4 May 2023 18:40:53 +0900 Subject: [PATCH] parse duration in config using `humantime` --- tuic-client/Cargo.toml | 1 + tuic-client/src/config.rs | 52 +++++++++++++++++++++++++--- tuic-server/Cargo.toml | 1 + tuic-server/src/config.rs | 71 ++++++++++++--------------------------- 4 files changed, 72 insertions(+), 53 deletions(-) diff --git a/tuic-client/Cargo.toml b/tuic-client/Cargo.toml index 767bae3..34a3c06 100644 --- a/tuic-client/Cargo.toml +++ b/tuic-client/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bytes = { version = "1.4.0", default-features = false, features = ["std"] } crossbeam-utils = { version = "0.8.15", default-features = false, features = ["std"] } env_logger = { version = "0.10.0", default-features = false, features = ["humantime"] } +humantime = { version = "2.1.0", default-features = false } lexopt = { version = "0.3.0", default-features = false } log = { version = "0.4.17", default-features = false, features = ["serde", "std"] } once_cell = { version = "1.17.1", default-features = false, features = ["parking_lot", "std"] } diff --git a/tuic-client/src/config.rs b/tuic-client/src/config.rs index 6855fb3..98879a1 100644 --- a/tuic-client/src/config.rs +++ b/tuic-client/src/config.rs @@ -1,4 +1,5 @@ use crate::utils::{CongestionControl, UdpRelayMode}; +use humantime::Duration as HumanDuration; use lexopt::{Arg, Error as ArgumentError, Parser}; use log::LevelFilter; use serde::{de::Error as DeError, Deserialize, Deserializer}; @@ -29,7 +30,9 @@ Arguments: #[serde(deny_unknown_fields)] pub struct Config { pub relay: Relay, + pub local: Local, + #[serde(default = "default::log_level")] pub log_level: LevelFilter, } @@ -39,36 +42,62 @@ pub struct Config { pub struct Relay { #[serde(deserialize_with = "deserialize_server")] pub server: (String, u16), + pub uuid: Uuid, + pub password: String, + pub ip: Option, + #[serde(default = "default::relay::certificates")] pub certificates: Vec, + #[serde( default = "default::relay::udp_relay_mode", deserialize_with = "deserialize_from_str" )] pub udp_relay_mode: UdpRelayMode, + #[serde( default = "default::relay::congestion_control", deserialize_with = "deserialize_from_str" )] pub congestion_control: CongestionControl, + #[serde(default = "default::relay::alpn")] pub alpn: Vec, + #[serde(default = "default::relay::zero_rtt_handshake")] pub zero_rtt_handshake: bool, + #[serde(default = "default::relay::disable_sni")] pub disable_sni: bool, - #[serde(default = "default::relay::timeout")] + + #[serde( + default = "default::relay::timeout", + deserialize_with = "deserialize_duration" + )] pub timeout: Duration, - #[serde(default = "default::relay::heartbeat")] + + #[serde( + default = "default::relay::heartbeat", + deserialize_with = "deserialize_duration" + )] pub heartbeat: Duration, + #[serde(default = "default::relay::disable_native_certs")] pub disable_native_certs: bool, - #[serde(default = "default::relay::gc_interval")] + + #[serde( + default = "default::relay::gc_interval", + deserialize_with = "deserialize_duration" + )] pub gc_interval: Duration, - #[serde(default = "default::relay::gc_lifetime")] + + #[serde( + default = "default::relay::gc_lifetime", + deserialize_with = "deserialize_duration" + )] pub gc_lifetime: Duration, } @@ -76,9 +105,13 @@ pub struct Relay { #[serde(deny_unknown_fields)] pub struct Local { pub server: SocketAddr, + pub username: Option, + pub password: Option, + pub dual_stack: Option, + #[serde(default = "default::local::max_packet_size")] pub max_packet_size: usize, } @@ -203,6 +236,17 @@ where } } +pub fn deserialize_duration<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + + s.parse::() + .map(|d| *d) + .map_err(DeError::custom) +} + #[derive(Debug, Error)] pub enum ConfigError { #[error(transparent)] diff --git a/tuic-server/Cargo.toml b/tuic-server/Cargo.toml index dcda275..dc96788 100644 --- a/tuic-server/Cargo.toml +++ b/tuic-server/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bytes = { version = "1.4.0", default-features = false, features = ["std"] } crossbeam-utils = { version = "0.8.15", default-features = false, features = ["std"] } env_logger = { version = "0.10.0", default-features = false, features = ["humantime"] } +humantime = { version = "2.1.0", default-features = false } lexopt = { version = "0.3.0", default-features = false } log = { version = "0.4.17", default-features = false, features = ["serde", "std"] } parking_lot = { version = "0.12.1", default-features = false } diff --git a/tuic-server/src/config.rs b/tuic-server/src/config.rs index 9d0deea..2442290 100644 --- a/tuic-server/src/config.rs +++ b/tuic-server/src/config.rs @@ -1,4 +1,5 @@ use crate::utils::CongestionControl; +use humantime::Duration as HumanDuration; use lexopt::{Arg, Error as ArgumentError, Parser}; use log::LevelFilter; use serde::{de::Error as DeError, Deserialize, Deserializer}; @@ -23,44 +24,58 @@ Arguments: #[serde(deny_unknown_fields)] pub struct Config { pub server: SocketAddr, + #[serde(deserialize_with = "deserialize_users")] pub users: HashMap, + pub certificate: PathBuf, + pub private_key: PathBuf, + #[serde( default = "default::congestion_control", deserialize_with = "deserialize_from_str" )] pub congestion_control: CongestionControl, + #[serde(default = "default::alpn")] pub alpn: Vec, + #[serde(default = "default::udp_relay_ipv6")] pub udp_relay_ipv6: bool, + #[serde(default = "default::zero_rtt_handshake")] pub zero_rtt_handshake: bool, + pub dual_stack: Option, + #[serde( default = "default::auth_timeout", deserialize_with = "deserialize_duration" )] pub auth_timeout: Duration, + #[serde( default = "default::max_idle_time", deserialize_with = "deserialize_duration" )] pub max_idle_time: Duration, + #[serde(default = "default::max_external_packet_size")] pub max_external_packet_size: usize, + #[serde( default = "default::gc_interval", deserialize_with = "deserialize_duration" )] pub gc_interval: Duration, + #[serde( default = "default::gc_lifetime", deserialize_with = "deserialize_duration" )] pub gc_lifetime: Duration, + #[serde(default = "default::log_level")] pub log_level: LevelFilter, } @@ -118,11 +133,11 @@ mod default { } pub fn auth_timeout() -> Duration { - Duration::from_secs(10) + Duration::from_secs(3) } pub fn max_idle_time() -> Duration { - Duration::from_secs(15) + Duration::from_secs(10) } pub fn max_external_packet_size() -> usize { @@ -165,57 +180,15 @@ where Ok(map) } -fn parse_duration(s: &str) -> Result { - let mut num = Vec::with_capacity(8); - let mut chars = Vec::with_capacity(2); - let mut expected_unit = false; - for c in s.chars() { - if !expected_unit && c.is_numeric() { - num.push(c); - continue; - } - - if !expected_unit && c.is_ascii() { - expected_unit = true; - } - chars.push(c); - } - - let n: u64 = num - .into_iter() - .collect::() - .parse() - .map_err(|e| format!("invalid value: {}, reason {}", &s, e))?; - - match chars.into_iter().collect::().as_str() { - "" => Ok(Duration::from_millis(n)), - "s" => Ok(Duration::from_secs(n)), - "ms" => Ok(Duration::from_millis(n)), - _ => Err(format!("invalid value: {}, expected 10s or 10ms", &s)), - } -} - -#[test] -fn test_parseduration() { - // test parse - assert_eq!(parse_duration("100s"), Ok(Duration::from_secs(100))); - assert_eq!(parse_duration("100ms"), Ok(Duration::from_millis(100))); - - // test default unit - assert_eq!(parse_duration("10000"), Ok(Duration::from_millis(10000))); - - // test invalid data - assert!(parse_duration("").is_err()); - assert!(parse_duration("1ms100").is_err()); - assert!(parse_duration("ms").is_err()); -} - pub fn deserialize_duration<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { - let s: String = String::deserialize(deserializer)?; - parse_duration(&s).map_err(DeError::custom) + let s = String::deserialize(deserializer)?; + + s.parse::() + .map(|d| *d) + .map_err(DeError::custom) } #[derive(Debug, Error)]