diff --git a/Cargo.lock b/Cargo.lock index ae3ec06761..a45ec99dd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -360,6 +360,7 @@ dependencies = [ "futures 0.3.5", "gateway-client", "gateway-requests", + "humantime-serde", "log", "nonexhaustive-delayqueue", "nymsphinx", @@ -711,7 +712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" dependencies = [ "atty", - "humantime", + "humantime 1.3.0", "log", "regex", "termcolor", @@ -1096,6 +1097,22 @@ dependencies = [ "quick-error 1.2.3", ] +[[package]] +name = "humantime" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" + +[[package]] +name = "humantime-serde" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058" +dependencies = [ + "humantime 2.0.1", + "serde", +] + [[package]] name = "hyper" version = "0.13.7" @@ -1588,6 +1605,7 @@ dependencies = [ "dotenv", "futures 0.3.5", "gateway-requests", + "humantime-serde", "log", "mixnet-client", "mixnode-common", @@ -1618,6 +1636,7 @@ dependencies = [ "dirs 2.0.2", "dotenv", "futures 0.3.5", + "humantime-serde", "log", "mixnet-client", "mixnode-common", diff --git a/clients/client-core/Cargo.toml b/clients/client-core/Cargo.toml index 2c2a962773..bde319e468 100644 --- a/clients/client-core/Cargo.toml +++ b/clients/client-core/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] dirs = "2.0.2" futures = "0.3.1" +humantime-serde = "1.0.1" log = "0.4" rand = { version = "0.7.3", features = ["wasm-bindgen"] } serde = { version = "1.0.104", features = ["derive"] } diff --git a/clients/client-core/src/config/mod.rs b/clients/client-core/src/config/mod.rs index 470bc20fad..f7509f3dfc 100644 --- a/clients/client-core/src/config/mod.rs +++ b/clients/client-core/src/config/mod.rs @@ -13,10 +13,12 @@ // limitations under the License. use config::NymConfig; -use serde::{Deserialize, Serialize}; +use serde::{ + de::{self, IntoDeserializer, Visitor}, + Deserialize, Deserializer, Serialize, +}; use std::marker::PhantomData; use std::path::PathBuf; -use std::time; use std::time::Duration; pub mod persistence; @@ -26,21 +28,66 @@ pub const MISSING_VALUE: &str = "MISSING VALUE"; // 'CLIENT' const DEFAULT_DIRECTORY_SERVER: &str = "https://directory.nymtech.net"; // 'DEBUG' -// where applicable, the below are defined in milliseconds const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5; -// all delays are in milliseconds -const DEFAULT_ACK_WAIT_ADDITION: u64 = 1_500; -const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: u64 = 1000; -const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: u64 = 100; -const DEFAULT_AVERAGE_PACKET_DELAY: u64 = 100; -const DEFAULT_TOPOLOGY_REFRESH_RATE: u64 = 30_000; -const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: u64 = 5_000; -const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: u64 = 1_500; +const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500); +const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(1000); +const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(100); +const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(100); +const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_millis(30_000); +const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000); +const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500); const DEFAULT_VPN_KEY_REUSE_LIMIT: usize = 1000; const ZERO_DELAY: Duration = Duration::from_nanos(0); +// custom function is defined to deserialize based on whether field contains a pre 0.9.0 +// u64 interpreted as milliseconds or proper duration introduced in 0.9.0 +// +// TODO: when we get to refactoring down the line, this code can just be removed +// and all Duration fields could just have #[serde(with = "humantime_serde")] instead +// reason for that is that we don't expect anyone to be upgrading from pre 0.9.0 when we have, +// for argument sake, 0.11.0 out +fn deserialize_duration<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct DurationVisitor; + + impl<'de> Visitor<'de> for DurationVisitor { + type Value = Duration; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("u64 or a duration") + } + + fn visit_i64(self, value: i64) -> Result + where + E: de::Error, + { + self.visit_u64(value as u64) + } + + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(Duration::from_millis(Deserialize::deserialize( + value.into_deserializer(), + )?)) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + humantime_serde::deserialize(value.into_deserializer()) + } + } + + deserializer.deserialize_any(DurationVisitor) +} + pub fn missing_string_value() -> String { MISSING_VALUE.to_string() } @@ -133,9 +180,9 @@ impl Config { } pub fn set_high_default_traffic_volume(&mut self) { - self.debug.average_packet_delay = 10; - self.debug.loop_cover_traffic_average_delay = 20; // 50 cover messages / s - self.debug.message_sending_average_delay = 5; // 200 "real" messages / s + self.debug.average_packet_delay = Duration::from_millis(10); + self.debug.loop_cover_traffic_average_delay = Duration::from_millis(100); // 10 cover messages / s + self.debug.message_sending_average_delay = Duration::from_millis(5); // 200 "real" messages / s } pub fn set_vpn_mode(&mut self, vpn_mode: bool) { @@ -199,19 +246,19 @@ impl Config { } // Debug getters - pub fn get_average_packet_delay(&self) -> time::Duration { + pub fn get_average_packet_delay(&self) -> Duration { if self.client.vpn_mode { ZERO_DELAY } else { - time::Duration::from_millis(self.debug.average_packet_delay) + self.debug.average_packet_delay } } - pub fn get_average_ack_delay(&self) -> time::Duration { + pub fn get_average_ack_delay(&self) -> Duration { if self.client.vpn_mode { ZERO_DELAY } else { - time::Duration::from_millis(self.debug.average_ack_delay) + self.debug.average_ack_delay } } @@ -219,32 +266,32 @@ impl Config { self.debug.ack_wait_multiplier } - pub fn get_ack_wait_addition(&self) -> time::Duration { - time::Duration::from_millis(self.debug.ack_wait_addition) + pub fn get_ack_wait_addition(&self) -> Duration { + self.debug.ack_wait_addition } - pub fn get_loop_cover_traffic_average_delay(&self) -> time::Duration { - time::Duration::from_millis(self.debug.loop_cover_traffic_average_delay) + pub fn get_loop_cover_traffic_average_delay(&self) -> Duration { + self.debug.loop_cover_traffic_average_delay } - pub fn get_message_sending_average_delay(&self) -> time::Duration { + pub fn get_message_sending_average_delay(&self) -> Duration { if self.client.vpn_mode { ZERO_DELAY } else { - time::Duration::from_millis(self.debug.message_sending_average_delay) + self.debug.message_sending_average_delay } } - pub fn get_gateway_response_timeout(&self) -> time::Duration { - time::Duration::from_millis(self.debug.gateway_response_timeout) + pub fn get_gateway_response_timeout(&self) -> Duration { + self.debug.gateway_response_timeout } - pub fn get_topology_refresh_rate(&self) -> time::Duration { - time::Duration::from_millis(self.debug.topology_refresh_rate) + pub fn get_topology_refresh_rate(&self) -> Duration { + self.debug.topology_refresh_rate } - pub fn get_topology_resolution_timeout(&self) -> time::Duration { - time::Duration::from_millis(self.debug.topology_resolution_timeout) + pub fn get_topology_resolution_timeout(&self) -> Duration { + self.debug.topology_resolution_timeout } pub fn get_vpn_mode(&self) -> bool { @@ -405,15 +452,21 @@ pub struct Debug { /// sent packet is going to be delayed at any given mix node. /// So for a packet going through three mix nodes, on average, it will take three times this value /// until the packet reaches its destination. - /// The provided value is interpreted as milliseconds. - average_packet_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + average_packet_delay: Duration, /// The parameter of Poisson distribution determining how long, on average, /// sent acknowledgement is going to be delayed at any given mix node. /// So for an ack going through three mix nodes, on average, it will take three times this value /// until the packet reaches its destination. - /// The provided value is interpreted as milliseconds. - average_ack_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + average_ack_delay: Duration, /// Value multiplied with the expected round trip time of an acknowledgement packet before /// it is assumed it was lost and retransmission of the data packet happens. @@ -423,36 +476,54 @@ pub struct Debug { /// Value added to the expected round trip time of an acknowledgement packet before /// it is assumed it was lost and retransmission of the data packet happens. /// In an ideal network with 0 latency, this value would have been 0. - /// The provided value is interpreted as milliseconds. - ack_wait_addition: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + ack_wait_addition: Duration, /// The parameter of Poisson distribution determining how long, on average, /// it is going to take for another loop cover traffic message to be sent. - /// The provided value is interpreted as milliseconds. - loop_cover_traffic_average_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + loop_cover_traffic_average_delay: Duration, /// The parameter of Poisson distribution determining how long, on average, /// it is going to take another 'real traffic stream' message to be sent. /// If no real packets are available and cover traffic is enabled, /// a loop cover message is sent instead in order to preserve the rate. - /// The provided value is interpreted as milliseconds. - message_sending_average_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + message_sending_average_delay: Duration, /// How long we're willing to wait for a response to a message sent to the gateway, /// before giving up on it. - /// The provided value is interpreted as milliseconds. - gateway_response_timeout: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + gateway_response_timeout: Duration, /// The uniform delay every which clients are querying the directory server /// to try to obtain a compatible network topology to send sphinx packets through. - /// The provided value is interpreted as milliseconds. - topology_refresh_rate: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + topology_refresh_rate: Duration, /// During topology refresh, test packets are sent through every single possible network /// path. This timeout determines waiting period until it is decided that the packet /// did not reach its destination. - /// The provided value is interpreted as milliseconds. - topology_resolution_timeout: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + topology_resolution_timeout: Duration, /// If the mode of the client is set to VPN it specifies number of packets created with the /// same initial secret until it gets rotated. diff --git a/clients/native/src/client/config/template.rs b/clients/native/src/client/config/template.rs index 72b3531126..d3d7d6063b 100644 --- a/clients/native/src/client/config/template.rs +++ b/clients/native/src/client/config/template.rs @@ -101,10 +101,10 @@ listening_port = {{ socket.listening_port }} [debug] -average_packet_delay = {{ debug.average_packet_delay }} -average_ack_delay = {{ debug.average_ack_delay }} -loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }} -message_sending_average_delay = {{ debug.message_sending_average_delay }} +average_packet_delay = '{{ debug.average_packet_delay }}' +average_ack_delay = '{{ debug.average_ack_delay }}' +loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}' +message_sending_average_delay = '{{ debug.message_sending_average_delay }}' "# } diff --git a/clients/socks5/src/client/config/template.rs b/clients/socks5/src/client/config/template.rs index c0af36207a..a02fc8d1c6 100644 --- a/clients/socks5/src/client/config/template.rs +++ b/clients/socks5/src/client/config/template.rs @@ -100,10 +100,10 @@ listening_port = {{ socks5.listening_port }} [debug] -average_packet_delay = {{ debug.average_packet_delay }} -average_ack_delay = {{ debug.average_ack_delay }} -loop_cover_traffic_average_delay = {{ debug.loop_cover_traffic_average_delay }} -message_sending_average_delay = {{ debug.message_sending_average_delay }} +average_packet_delay = '{{ debug.average_packet_delay }}' +average_ack_delay = '{{ debug.average_ack_delay }}' +loop_cover_traffic_average_delay = '{{ debug.loop_cover_traffic_average_delay }}' +message_sending_average_delay = '{{ debug.message_sending_average_delay }}' "# } diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index ea4a9ea0c7..2c4cc774ea 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -13,6 +13,7 @@ dirs = "2.0.2" dashmap = "4.0.0-rc6" dotenv = "0.15.0" futures = "0.3" +humantime-serde = "1.0.1" log = "0.4" pretty_env_logger = "0.3" rand = "0.7" diff --git a/gateway/src/config/mod.rs b/gateway/src/config/mod.rs index f7fae3f26f..85664042a5 100644 --- a/gateway/src/config/mod.rs +++ b/gateway/src/config/mod.rs @@ -15,11 +15,14 @@ use crate::config::template::config_template; use config::NymConfig; use log::*; -use serde::{Deserialize, Serialize}; +use serde::{ + de::{self, IntoDeserializer, Visitor}, + Deserialize, Deserializer, Serialize, +}; use std::net::{IpAddr, SocketAddr}; use std::path::PathBuf; use std::str::FromStr; -use std::time; +use std::time::Duration; pub mod persistence; mod template; @@ -33,11 +36,11 @@ const DEFAULT_DIRECTORY_SERVER: &str = "https://directory.nymtech.net"; // 'DEBUG' // where applicable, the below are defined in milliseconds -const DEFAULT_PRESENCE_SENDING_DELAY: u64 = 10_000; // 10s -const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: u64 = 10_000; // 10s -const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: u64 = 300_000; // 5min -const DEFAULT_INITIAL_CONNECTION_TIMEOUT: u64 = 1_500; // 1.5s -const DEFAULT_CACHE_ENTRY_TTL: u64 = 30_000; +const DEFAULT_PRESENCE_SENDING_DELAY: Duration = Duration::from_millis(10_000); +const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: Duration = Duration::from_millis(10_000); +const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: Duration = Duration::from_millis(300_000); +const DEFAULT_INITIAL_CONNECTION_TIMEOUT: Duration = Duration::from_millis(1_500); +const DEFAULT_CACHE_ENTRY_TTL: Duration = Duration::from_millis(30_000); const DEFAULT_STORED_MESSAGE_FILENAME_LENGTH: u16 = 16; const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: u16 = 5; @@ -88,6 +91,53 @@ impl NymConfig for Config { } } +// custom function is defined to deserialize based on whether field contains a pre 0.9.0 +// u64 interpreted as milliseconds or proper duration introduced in 0.9.0 +// +// TODO: when we get to refactoring down the line, this code can just be removed +// and all Duration fields could just have #[serde(with = "humantime_serde")] instead +// reason for that is that we don't expect anyone to be upgrading from pre 0.9.0 when we have, +// for argument sake, 0.11.0 out +fn deserialize_duration<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct DurationVisitor; + + impl<'de> Visitor<'de> for DurationVisitor { + type Value = Duration; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("u64 or a duration") + } + + fn visit_i64(self, value: i64) -> Result + where + E: de::Error, + { + self.visit_u64(value as u64) + } + + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(Duration::from_millis(Deserialize::deserialize( + value.into_deserializer(), + )?)) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + humantime_serde::deserialize(value.into_deserializer()) + } + } + + deserializer.deserialize_any(DurationVisitor) +} + pub fn missing_string_value() -> String { MISSING_VALUE.to_string() } @@ -358,8 +408,8 @@ impl Config { self.gateway.presence_directory_server.clone() } - pub fn get_presence_sending_delay(&self) -> time::Duration { - time::Duration::from_millis(self.debug.presence_sending_delay) + pub fn get_presence_sending_delay(&self) -> Duration { + self.debug.presence_sending_delay } pub fn get_mix_listening_address(&self) -> SocketAddr { @@ -386,16 +436,16 @@ impl Config { self.clients_endpoint.ledger_path.clone() } - pub fn get_packet_forwarding_initial_backoff(&self) -> time::Duration { - time::Duration::from_millis(self.debug.packet_forwarding_initial_backoff) + pub fn get_packet_forwarding_initial_backoff(&self) -> Duration { + self.debug.packet_forwarding_initial_backoff } - pub fn get_packet_forwarding_maximum_backoff(&self) -> time::Duration { - time::Duration::from_millis(self.debug.packet_forwarding_maximum_backoff) + pub fn get_packet_forwarding_maximum_backoff(&self) -> Duration { + self.debug.packet_forwarding_maximum_backoff } - pub fn get_initial_connection_timeout(&self) -> time::Duration { - time::Duration::from_millis(self.debug.initial_connection_timeout) + pub fn get_initial_connection_timeout(&self) -> Duration { + self.debug.initial_connection_timeout } pub fn get_message_retrieval_limit(&self) -> u16 { @@ -406,8 +456,8 @@ impl Config { self.debug.stored_messages_filename_length } - pub fn get_cache_entry_ttl(&self) -> time::Duration { - time::Duration::from_millis(self.debug.cache_entry_ttl) + pub fn get_cache_entry_ttl(&self) -> Duration { + self.debug.cache_entry_ttl } pub fn get_version(&self) -> &str { @@ -577,20 +627,33 @@ impl Default for Logging { pub struct Debug { /// Initial value of an exponential backoff to reconnect to dropped TCP connection when /// forwarding sphinx packets. - /// The provided value is interpreted as milliseconds. - packet_forwarding_initial_backoff: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + packet_forwarding_initial_backoff: Duration, /// Maximum value of an exponential backoff to reconnect to dropped TCP connection when /// forwarding sphinx packets. - /// The provided value is interpreted as milliseconds. - packet_forwarding_maximum_backoff: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + packet_forwarding_maximum_backoff: Duration, /// Timeout for establishing initial connection when trying to forward a sphinx packet. - /// The provider value is interpreted as milliseconds. - initial_connection_timeout: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + initial_connection_timeout: Duration, /// Delay between each subsequent presence data being sent. - presence_sending_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + presence_sending_delay: Duration, /// Length of filenames for new client messages. stored_messages_filename_length: u16, @@ -601,8 +664,11 @@ pub struct Debug { message_retrieval_limit: u16, /// Duration for which a cached vpn processing result is going to get stored for. - /// The provided value is interpreted as milliseconds. - cache_entry_ttl: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + cache_entry_ttl: Duration, } impl Default for Debug { diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index d9e4c5bae9..2a7f3f137c 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -13,6 +13,7 @@ curve25519-dalek = "2.0.0" dirs = "2.0.2" dotenv = "0.15.0" futures = "0.3.1" +humantime-serde = "1.0.1" log = "0.4" pretty_env_logger = "0.3" serde = { version = "1.0.104", features = ["derive"] } diff --git a/mixnode/src/config/mod.rs b/mixnode/src/config/mod.rs index 2390ce0033..fc3775485a 100644 --- a/mixnode/src/config/mod.rs +++ b/mixnode/src/config/mod.rs @@ -15,11 +15,14 @@ use crate::config::template::config_template; use config::NymConfig; use log::*; -use serde::{Deserialize, Serialize}; +use serde::{ + de::{self, IntoDeserializer, Visitor}, + Deserialize, Deserializer, Serialize, +}; use std::net::{IpAddr, SocketAddr}; use std::path::PathBuf; use std::str::FromStr; -use std::time; +use std::time::Duration; pub mod persistence; mod template; @@ -31,14 +34,13 @@ const DEFAULT_LISTENING_PORT: u16 = 1789; const DEFAULT_DIRECTORY_SERVER: &str = "https://directory.nymtech.net"; // 'DEBUG' -// where applicable, the below are defined in milliseconds -const DEFAULT_PRESENCE_SENDING_DELAY: u64 = 10_000; // 10s -const DEFAULT_METRICS_SENDING_DELAY: u64 = 5_000; // 10s -const DEFAULT_METRICS_RUNNING_STATS_LOGGING_DELAY: u64 = 60_000; // 1min -const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: u64 = 10_000; // 10s -const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: u64 = 300_000; // 5min -const DEFAULT_INITIAL_CONNECTION_TIMEOUT: u64 = 1_500; // 1.5s -const DEFAULT_CACHE_ENTRY_TTL: u64 = 30_000; +const DEFAULT_PRESENCE_SENDING_DELAY: Duration = Duration::from_millis(10_000); +const DEFAULT_METRICS_SENDING_DELAY: Duration = Duration::from_millis(5_000); +const DEFAULT_METRICS_RUNNING_STATS_LOGGING_DELAY: Duration = Duration::from_millis(60_000); +const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: Duration = Duration::from_millis(10_000); +const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: Duration = Duration::from_millis(300_000); +const DEFAULT_INITIAL_CONNECTION_TIMEOUT: Duration = Duration::from_millis(1_500); +const DEFAULT_CACHE_ENTRY_TTL: Duration = Duration::from_millis(30_000); #[derive(Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] @@ -82,6 +84,53 @@ impl NymConfig for Config { } } +// custom function is defined to deserialize based on whether field contains a pre 0.9.0 +// u64 interpreted as milliseconds or proper duration introduced in 0.9.0 +// +// TODO: when we get to refactoring down the line, this code can just be removed +// and all Duration fields could just have #[serde(with = "humantime_serde")] instead +// reason for that is that we don't expect anyone to be upgrading from pre 0.9.0 when we have, +// for argument sake, 0.11.0 out +fn deserialize_duration<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct DurationVisitor; + + impl<'de> Visitor<'de> for DurationVisitor { + type Value = Duration; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("u64 or a duration") + } + + fn visit_i64(self, value: i64) -> Result + where + E: de::Error, + { + self.visit_u64(value as u64) + } + + fn visit_u64(self, value: u64) -> Result + where + E: de::Error, + { + Ok(Duration::from_millis(Deserialize::deserialize( + value.into_deserializer(), + )?)) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + humantime_serde::deserialize(value.into_deserializer()) + } + } + + deserializer.deserialize_any(DurationVisitor) +} + pub fn missing_string_value>() -> T { MISSING_VALUE.to_string().into() } @@ -249,20 +298,20 @@ impl Config { self.mixnode.presence_directory_server.clone() } - pub fn get_presence_sending_delay(&self) -> time::Duration { - time::Duration::from_millis(self.debug.presence_sending_delay) + pub fn get_presence_sending_delay(&self) -> Duration { + self.debug.presence_sending_delay } pub fn get_metrics_directory_server(&self) -> String { self.mixnode.metrics_directory_server.clone() } - pub fn get_metrics_sending_delay(&self) -> time::Duration { - time::Duration::from_millis(self.debug.metrics_sending_delay) + pub fn get_metrics_sending_delay(&self) -> Duration { + self.debug.metrics_sending_delay } - pub fn get_metrics_running_stats_logging_delay(&self) -> time::Duration { - time::Duration::from_millis(self.debug.metrics_running_stats_logging_delay) + pub fn get_metrics_running_stats_logging_delay(&self) -> Duration { + self.debug.metrics_running_stats_logging_delay } pub fn get_layer(&self) -> u64 { @@ -277,20 +326,20 @@ impl Config { self.mixnode.announce_address.clone() } - pub fn get_packet_forwarding_initial_backoff(&self) -> time::Duration { - time::Duration::from_millis(self.debug.packet_forwarding_initial_backoff) + pub fn get_packet_forwarding_initial_backoff(&self) -> Duration { + self.debug.packet_forwarding_initial_backoff } - pub fn get_packet_forwarding_maximum_backoff(&self) -> time::Duration { - time::Duration::from_millis(self.debug.packet_forwarding_maximum_backoff) + pub fn get_packet_forwarding_maximum_backoff(&self) -> Duration { + self.debug.packet_forwarding_maximum_backoff } - pub fn get_initial_connection_timeout(&self) -> time::Duration { - time::Duration::from_millis(self.debug.initial_connection_timeout) + pub fn get_initial_connection_timeout(&self) -> Duration { + self.debug.initial_connection_timeout } - pub fn get_cache_entry_ttl(&self) -> time::Duration { - time::Duration::from_millis(self.debug.cache_entry_ttl) + pub fn get_cache_entry_ttl(&self) -> Duration { + self.debug.cache_entry_ttl } pub fn get_version(&self) -> &str { @@ -365,11 +414,11 @@ pub struct MixNode { impl MixNode { fn default_private_identity_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("private_identity.pem") + Config::default_data_directory(id).join("private_identity.pem") } fn default_public_identity_key_file(id: &str) -> PathBuf { - Config::default_data_directory(Some(id)).join("public_identity.pem") + Config::default_data_directory(id).join("public_identity.pem") } fn default_private_sphinx_key_file(id: &str) -> PathBuf { @@ -421,34 +470,55 @@ impl Default for Logging { #[serde(default, deny_unknown_fields)] pub struct Debug { /// Delay between each subsequent presence data being sent. - /// The provided value is interpreted as milliseconds. - presence_sending_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + presence_sending_delay: Duration, /// Delay between each subsequent metrics data being sent. - /// The provided value is interpreted as milliseconds. - metrics_sending_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + metrics_sending_delay: Duration, /// Delay between each subsequent running metrics statistics being logged. - /// The provided value is interpreted as milliseconds. - metrics_running_stats_logging_delay: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + metrics_running_stats_logging_delay: Duration, /// Initial value of an exponential backoff to reconnect to dropped TCP connection when /// forwarding sphinx packets. - /// The provided value is interpreted as milliseconds. - packet_forwarding_initial_backoff: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + packet_forwarding_initial_backoff: Duration, /// Maximum value of an exponential backoff to reconnect to dropped TCP connection when /// forwarding sphinx packets. - /// The provided value is interpreted as milliseconds. - packet_forwarding_maximum_backoff: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + packet_forwarding_maximum_backoff: Duration, /// Timeout for establishing initial connection when trying to forward a sphinx packet. - /// The provider value is interpreted as milliseconds. - initial_connection_timeout: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + initial_connection_timeout: Duration, /// Duration for which a cached vpn processing result is going to get stored for. - /// The provided value is interpreted as milliseconds. - cache_entry_ttl: u64, + #[serde( + deserialize_with = "deserialize_duration", + serialize_with = "humantime_serde::serialize" + )] + cache_entry_ttl: Duration, } impl Default for Debug {