diff --git a/Cargo.lock b/Cargo.lock index 6048d3f4e6e8acea5790db1a4a79260ad6836684..5ec9f0ef93fc3414be6f7afaf572066491904725 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -871,8 +871,7 @@ dependencies = [ [[package]] name = "derive_builder_core" version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5" +source = "git+https://github.com/ijackson/rust-derive-builder?rev=dccbbb8ad75717c8bc0070b6f0364b2c3a54abb7#dccbbb8ad75717c8bc0070b6f0364b2c3a54abb7" dependencies = [ "darling", "proc-macro2", @@ -3099,6 +3098,8 @@ name = "tor-basic-utils" version = "0.1.0" dependencies = [ "educe", + "humantime-serde", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c88138e9f92de1aec82b8d332f163ee751b5011c..2695a05bdd4e868b289f6bcc2630e9d143069b50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,7 @@ codegen-units = 1 # Optimize for size. [Actually this is even smaller than 'z' on rust # 1.56. It saves about 11% download size over the default value of '3'.] opt-level = 's' + +[patch.crates-io.derive_builder_core] +git = "https://github.com/ijackson/rust-derive-builder" +rev = "dccbbb8ad75717c8bc0070b6f0364b2c3a54abb7" diff --git a/crates/arti-client/Cargo.toml b/crates/arti-client/Cargo.toml index f304eb5f1fb75ee2d3135a66cc9c4caefa2d208c..d8a556681c920b031b0dc7633e61c64985f875c3 100644 --- a/crates/arti-client/Cargo.toml +++ b/crates/arti-client/Cargo.toml @@ -39,7 +39,7 @@ tor-proto = { path="../tor-proto", version = "0.1.0"} tor-rtcompat = { path="../tor-rtcompat", version = "0.1.0"} humantime-serde = "1" -derive_builder = "0.10" +derive_builder = "0.10.2" derive_more = "0.99" directories = "4" educe = "0.4.6" diff --git a/crates/arti-client/src/config.rs b/crates/arti-client/src/config.rs index e2af900cfcde1a07a45ef1791fd3b438f56c7113..7459ac6694e7ccdd180d9c681a8fe1ba1271a5ab 100644 --- a/crates/arti-client/src/config.rs +++ b/crates/arti-client/src/config.rs @@ -17,6 +17,7 @@ use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; use std::time::Duration; +pub use tor_basic_utils::humantime_serde_option; pub use tor_config::{CfgPath, ConfigBuildError, Reconfigure}; /// Types for configuring how Tor circuits are built. @@ -46,6 +47,7 @@ pub mod dir { /// and requests. #[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] #[serde(deny_unknown_fields)] pub struct ClientAddrConfig { /// Should we allow attempts to make Tor connections to local addresses? @@ -67,6 +69,7 @@ pub struct ClientAddrConfig { /// and requests—even those that are currently waiting. #[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] #[serde(deny_unknown_fields)] #[non_exhaustive] pub struct StreamTimeoutConfig { @@ -74,17 +77,20 @@ pub struct StreamTimeoutConfig { /// to a host? #[builder(default = "default_connect_timeout()")] #[serde(with = "humantime_serde", default = "default_connect_timeout")] + #[builder(attrs(serde(with = "humantime_serde_option")))] pub(crate) connect_timeout: Duration, /// How long should we wait before timing out when resolving a DNS record? #[builder(default = "default_dns_resolve_timeout()")] #[serde(with = "humantime_serde", default = "default_dns_resolve_timeout")] + #[builder(attrs(serde(with = "humantime_serde_option")))] pub(crate) resolve_timeout: Duration, /// How long should we wait before timing out when resolving a DNS /// PTR record? #[builder(default = "default_dns_resolve_ptr_timeout()")] #[serde(with = "humantime_serde", default = "default_dns_resolve_ptr_timeout")] + #[builder(attrs(serde(with = "humantime_serde_option")))] pub(crate) resolve_ptr_timeout: Duration, } @@ -98,14 +104,6 @@ impl Default for ClientAddrConfig { } } -impl From<ClientAddrConfig> for ClientAddrConfigBuilder { - fn from(cfg: ClientAddrConfig) -> ClientAddrConfigBuilder { - let mut builder = ClientAddrConfigBuilder::default(); - builder.allow_local_addrs(cfg.allow_local_addrs); - builder - } -} - impl ClientAddrConfig { /// Return a new [`ClientAddrConfigBuilder`]. pub fn builder() -> ClientAddrConfigBuilder { @@ -120,18 +118,6 @@ impl Default for StreamTimeoutConfig { } } -impl From<StreamTimeoutConfig> for StreamTimeoutConfigBuilder { - fn from(cfg: StreamTimeoutConfig) -> StreamTimeoutConfigBuilder { - let mut builder = StreamTimeoutConfigBuilder::default(); - builder - .connect_timeout(cfg.connect_timeout) - .resolve_timeout(cfg.resolve_timeout) - .resolve_ptr_timeout(cfg.resolve_ptr_timeout); - - builder - } -} - impl StreamTimeoutConfig { /// Return a new [`StreamTimeoutConfigBuilder`]. pub fn builder() -> StreamTimeoutConfigBuilder { @@ -172,6 +158,7 @@ fn default_dns_resolve_ptr_timeout() -> Duration { #[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)] #[serde(deny_unknown_fields)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct StorageConfig { /// Location on disk for cached directory information. #[builder(setter(into), default = "default_cache_dir()")] @@ -225,20 +212,13 @@ impl StorageConfig { } } -impl From<StorageConfig> for StorageConfigBuilder { - fn from(cfg: StorageConfig) -> StorageConfigBuilder { - let mut builder = StorageConfigBuilder::default(); - builder.state_dir(cfg.state_dir).cache_dir(cfg.cache_dir); - builder - } -} - /// Configuration for system resources used by Tor. /// /// You cannot change this section on a running Arti client. #[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)] #[serde(deny_unknown_fields)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] #[non_exhaustive] pub struct SystemConfig { /// Maximum number of file descriptors we should launch with @@ -265,14 +245,6 @@ impl SystemConfig { } } -impl From<SystemConfig> for SystemConfigBuilder { - fn from(cfg: SystemConfig) -> SystemConfigBuilder { - let mut builder = SystemConfigBuilder::default(); - builder.max_files(cfg.max_files); - builder - } -} - /// A configuration used to bootstrap a [`TorClient`](crate::TorClient). /// /// In order to connect to the Tor network, Arti needs to know a few @@ -556,36 +528,6 @@ impl TorClientConfigBuilder { } } -impl From<TorClientConfig> for TorClientConfigBuilder { - fn from(cfg: TorClientConfig) -> TorClientConfigBuilder { - let TorClientConfig { - tor_network, - storage, - download_schedule, - override_net_params, - path_rules, - preemptive_circuits, - circuit_timing, - address_filter, - stream_timeouts, - system, - } = cfg; - - TorClientConfigBuilder { - tor_network: tor_network.into(), - storage: storage.into(), - download_schedule: download_schedule.into(), - override_net_params, - path_rules: path_rules.into(), - preemptive_circuits: preemptive_circuits.into(), - circuit_timing: circuit_timing.into(), - address_filter: address_filter.into(), - stream_timeouts: stream_timeouts.into(), - system: system.into(), - } - } -} - #[cfg(test)] mod test { #![allow(clippy::unwrap_used)] @@ -594,7 +536,7 @@ mod test { #[test] fn defaults() { let dflt = TorClientConfig::default(); - let b2 = TorClientConfigBuilder::from(dflt.clone()); + let b2 = TorClientConfigBuilder::default(); let dflt2 = b2.build().unwrap(); assert_eq!(&dflt, &dflt2); } @@ -640,11 +582,6 @@ mod test { let val = bld.build().unwrap(); - // Reconstruct, rebuild, and validate. - let bld2 = TorClientConfigBuilder::from(val.clone()); - let val2 = bld2.build().unwrap(); - assert_eq!(val, val2); - assert_ne!(val, TorClientConfig::default()); } } diff --git a/crates/arti-config/Cargo.toml b/crates/arti-config/Cargo.toml index d5e068310680bab68df7af7aca04ffb721a8abec..b1c8115666a10608ee9f2f54b2810f7a2e4328bd 100644 --- a/crates/arti-config/Cargo.toml +++ b/crates/arti-config/Cargo.toml @@ -20,7 +20,7 @@ serde = { version = "1.0.103", features = ["derive"] } toml = "0.5" regex = { version = "1", default-features = false, features = ["std"] } thiserror = "1" -derive_builder = "0.10" +derive_builder = "0.10.2" [dev-dependencies] tempfile = "3" diff --git a/crates/arti-config/src/options.rs b/crates/arti-config/src/options.rs index 4d832f42466b0592c5f47d7bee72f88adb186a6e..d5fbda9dcc815a49e3480a378220a6ea3e7fc9ab 100644 --- a/crates/arti-config/src/options.rs +++ b/crates/arti-config/src/options.rs @@ -1,11 +1,8 @@ //! Handling for arti's configuration formats. use arti_client::config::{ - circ, - dir::{self, DownloadScheduleConfig, NetworkConfig}, - ClientAddrConfig, ClientAddrConfigBuilder, StorageConfig, StorageConfigBuilder, - StreamTimeoutConfig, StreamTimeoutConfigBuilder, SystemConfig, SystemConfigBuilder, - TorClientConfig, TorClientConfigBuilder, + circ, dir, ClientAddrConfigBuilder, StorageConfigBuilder, StreamTimeoutConfigBuilder, + SystemConfig, SystemConfigBuilder, TorClientConfig, TorClientConfigBuilder, }; use derive_builder::Builder; use serde::Deserialize; @@ -20,6 +17,7 @@ pub(crate) const ARTI_DEFAULTS: &str = concat!(include_str!("./arti_defaults.tom #[derive(Deserialize, Debug, Default, Clone, Builder, Eq, PartialEq)] #[serde(deny_unknown_fields)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct ApplicationConfig { /// If true, we should watch our configuration files for changes, and reload /// our configuration when they change. @@ -33,14 +31,6 @@ pub struct ApplicationConfig { watch_configuration: bool, } -impl From<ApplicationConfig> for ApplicationConfigBuilder { - fn from(cfg: ApplicationConfig) -> Self { - let mut builder = ApplicationConfigBuilder::default(); - builder.watch_configuration(cfg.watch_configuration); - builder - } -} - impl ApplicationConfig { /// Return true if we're configured to watch for configuration changes. pub fn watch_configuration(&self) -> bool { @@ -53,6 +43,7 @@ impl ApplicationConfig { #[serde(deny_unknown_fields)] #[non_exhaustive] // TODO(nickm) remove public elements when I revise this. #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct LoggingConfig { /// Filtering directives that determine tracing levels as described at /// <https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/targets/struct.Targets.html#impl-FromStr> @@ -117,19 +108,6 @@ impl LoggingConfig { } } -impl From<LoggingConfig> for LoggingConfigBuilder { - fn from(cfg: LoggingConfig) -> LoggingConfigBuilder { - let mut builder = LoggingConfigBuilder::default(); - if let Some(console) = cfg.console { - builder.console(console); - } - if let Some(journald) = cfg.journald { - builder.journald(journald); - } - builder - } -} - /// Configuration information for an (optionally rotating) logfile. #[derive(Deserialize, Debug, Builder, Clone, Eq, PartialEq)] pub struct LogfileConfig { @@ -188,6 +166,7 @@ impl LogfileConfig { #[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)] #[serde(deny_unknown_fields)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct ProxyConfig { /// Port to listen on (at localhost) for incoming SOCKS /// connections. @@ -221,14 +200,6 @@ impl ProxyConfig { } } -impl From<ProxyConfig> for ProxyConfigBuilder { - fn from(cfg: ProxyConfig) -> ProxyConfigBuilder { - let mut builder = ProxyConfigBuilder::default(); - builder.socks_port(cfg.socks_port); - builder - } -} - /// Structure to hold Arti's configuration options, whether from a /// configuration file or the command line. // @@ -243,8 +214,7 @@ impl From<ProxyConfig> for ProxyConfigBuilder { /// /// NOTE: These are NOT the final options or their final layout. Expect NO /// stability here. -#[derive(Deserialize, Debug, Clone, Eq, PartialEq, Default)] -#[serde(deny_unknown_fields)] +#[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct ArtiConfig { /// Configuration for application behavior. application: ApplicationConfig, @@ -255,51 +225,28 @@ pub struct ArtiConfig { /// Logging configuration logging: LoggingConfig, - /// Information about the Tor network we want to connect to. - #[serde(default)] - tor_network: NetworkConfig, - - /// Directories for storing information on disk - storage: StorageConfig, - - /// Information about when and how often to download directory information - download_schedule: DownloadScheduleConfig, - - /// Facility to override network parameters from the values set in the - /// consensus. - #[serde(default)] - override_net_params: HashMap<String, i32>, - - /// Information about how to build paths through the network. - path_rules: circ::PathConfig, - - /// Information about preemptive circuits - preemptive_circuits: circ::PreemptiveCircuitConfig, - - /// Information about how to retry and expire circuits and request for circuits. - circuit_timing: circ::CircuitTiming, - - /// Rules about which addresses the client is willing to connect to. - address_filter: ClientAddrConfig, - - /// Information about when to time out client requests. - stream_timeouts: StreamTimeoutConfig, - /// Information on system resources used by Arti. system: SystemConfig, + + /// Configuration of the actual Tor client + tor: TorClientConfig, } impl TryFrom<config::Config> for ArtiConfig { type Error = config::ConfigError; fn try_from(cfg: config::Config) -> Result<ArtiConfig, Self::Error> { - cfg.try_deserialize() + let builder: ArtiConfigBuilder = cfg.try_deserialize()?; + builder + .build() + .map_err(|e| config::ConfigError::Foreign(Box::new(e))) } } -impl From<ArtiConfig> for TorClientConfigBuilder { - fn from(cfg: ArtiConfig) -> TorClientConfigBuilder { +// This handwritten impl ought not to exist, but it is needed until #374 is done. +impl From<ArtiConfigBuilder> for TorClientConfigBuilder { + fn from(cfg: ArtiConfigBuilder) -> TorClientConfigBuilder { let mut builder = TorClientConfig::builder(); - let ArtiConfig { + let ArtiConfigBuilder { storage, address_filter, path_rules, @@ -310,14 +257,14 @@ impl From<ArtiConfig> for TorClientConfigBuilder { tor_network, .. } = cfg; - *builder.storage() = storage.into(); - *builder.address_filter() = address_filter.into(); - *builder.path_rules() = path_rules.into(); - *builder.preemptive_circuits() = preemptive_circuits.into(); - *builder.circuit_timing() = circuit_timing.into(); + *builder.storage() = storage; + *builder.address_filter() = address_filter; + *builder.path_rules() = path_rules; + *builder.preemptive_circuits() = preemptive_circuits; + *builder.circuit_timing() = circuit_timing; *builder.override_net_params() = override_net_params; - *builder.download_schedule() = download_schedule.into(); - *builder.tor_network() = tor_network.into(); + *builder.download_schedule() = download_schedule; + *builder.tor_network() = tor_network; builder } } @@ -325,8 +272,7 @@ impl From<ArtiConfig> for TorClientConfigBuilder { impl ArtiConfig { /// Construct a [`TorClientConfig`] based on this configuration. pub fn tor_client_config(&self) -> Result<TorClientConfig, ConfigBuildError> { - let builder: TorClientConfigBuilder = self.clone().into(); - builder.build() + Ok(self.tor.clone()) } /// Return a new ArtiConfigBuilder. @@ -356,33 +302,48 @@ impl ArtiConfig { /// /// Unlike other builder types in Arti, this builder works by exposing an /// inner builder for each section in the [`TorClientConfig`]. -#[derive(Default, Clone)] +#[derive(Default, Clone, Deserialize)] +// This ought to be replaced by a derive-builder generated struct (probably as part of #374), +// but currently derive-builder can't do this. pub struct ArtiConfigBuilder { /// Builder for the application section + #[serde(default)] application: ApplicationConfigBuilder, /// Builder for the proxy section. + #[serde(default)] proxy: ProxyConfigBuilder, /// Builder for the logging section. + #[serde(default)] logging: LoggingConfigBuilder, /// Builder for the storage section. + #[serde(default)] storage: StorageConfigBuilder, /// Builder for the tor_network section. + #[serde(default)] tor_network: dir::NetworkConfigBuilder, /// Builder for the download_schedule section. + #[serde(default)] download_schedule: dir::DownloadScheduleConfigBuilder, /// In-progress object for the override_net_params section. + #[serde(default)] override_net_params: HashMap<String, i32>, /// Builder for the path_rules section. + #[serde(default)] path_rules: circ::PathConfigBuilder, /// Builder for the preemptive_circuits section. + #[serde(default)] preemptive_circuits: circ::PreemptiveCircuitConfigBuilder, /// Builder for the circuit_timing section. + #[serde(default)] circuit_timing: circ::CircuitTimingBuilder, /// Builder for the address_filter section. + #[serde(default)] address_filter: ClientAddrConfigBuilder, /// Builder for the stream timeout rules. + #[serde(default)] stream_timeouts: StreamTimeoutConfigBuilder, /// Builder for system resource configuration. + #[serde(default)] system: SystemConfigBuilder, } @@ -395,51 +356,15 @@ impl ArtiConfigBuilder { .map_err(|e| e.within("application"))?; let proxy = self.proxy.build().map_err(|e| e.within("proxy"))?; let logging = self.logging.build().map_err(|e| e.within("logging"))?; - let tor_network = self - .tor_network - .build() - .map_err(|e| e.within("tor_network"))?; - let storage = self.storage.build().map_err(|e| e.within("storage"))?; - let download_schedule = self - .download_schedule - .build() - .map_err(|e| e.within("download_schedule"))?; - let override_net_params = self.override_net_params.clone(); - let path_rules = self - .path_rules - .build() - .map_err(|e| e.within("path_rules"))?; - let preemptive_circuits = self - .preemptive_circuits - .build() - .map_err(|e| e.within("preemptive_circuits"))?; - let circuit_timing = self - .circuit_timing - .build() - .map_err(|e| e.within("circuit_timing"))?; - let address_filter = self - .address_filter - .build() - .map_err(|e| e.within("address_filter"))?; - let stream_timeouts = self - .stream_timeouts - .build() - .map_err(|e| e.within("stream_timeouts"))?; let system = self.system.build().map_err(|e| e.within("system"))?; + let tor = TorClientConfigBuilder::from(self.clone()); + let tor = tor.build()?; Ok(ArtiConfig { application, proxy, logging, - tor_network, - storage, - download_schedule, - override_net_params, - path_rules, - preemptive_circuits, - circuit_timing, - address_filter, - stream_timeouts, system, + tor, }) } @@ -554,26 +479,6 @@ impl ArtiConfigBuilder { } } -impl From<ArtiConfig> for ArtiConfigBuilder { - fn from(cfg: ArtiConfig) -> ArtiConfigBuilder { - ArtiConfigBuilder { - application: cfg.application.into(), - proxy: cfg.proxy.into(), - logging: cfg.logging.into(), - storage: cfg.storage.into(), - tor_network: cfg.tor_network.into(), - download_schedule: cfg.download_schedule.into(), - override_net_params: cfg.override_net_params, - path_rules: cfg.path_rules.into(), - preemptive_circuits: cfg.preemptive_circuits.into(), - circuit_timing: cfg.circuit_timing.into(), - address_filter: cfg.address_filter.into(), - stream_timeouts: cfg.stream_timeouts.into(), - system: cfg.system.into(), - } - } -} - #[cfg(test)] mod test { #![allow(clippy::unwrap_used)] @@ -598,11 +503,6 @@ mod test { let default = ArtiConfig::default(); assert_eq!(&parsed, &default); - // Make sure we can round-trip through the builder. - let bld: ArtiConfigBuilder = default.into(); - let rebuilt = bld.build().unwrap(); - assert_eq!(&rebuilt, &parsed); - // Make sure that the client configuration this gives us is the default one. let client_config = parsed.tor_client_config().unwrap(); let dflt_client_config = TorClientConfig::default(); @@ -658,11 +558,6 @@ mod test { let val = bld.build().unwrap(); - // Reconstruct, rebuild, and validate. - let bld2 = ArtiConfigBuilder::from(val.clone()); - let val2 = bld2.build().unwrap(); - assert_eq!(val, val2); - assert_ne!(val, ArtiConfig::default()); } } diff --git a/crates/tor-basic-utils/Cargo.toml b/crates/tor-basic-utils/Cargo.toml index e9ec806110616c5905f98c694e7d6806081b734e..ce445b123a9fced9d9a482907943dc3a31193134 100644 --- a/crates/tor-basic-utils/Cargo.toml +++ b/crates/tor-basic-utils/Cargo.toml @@ -11,6 +11,12 @@ categories = ["rust-patterns"] # We must put *something* here and this will do repository = "https://gitlab.torproject.org/tpo/core/arti.git/" [dependencies] +serde = { version = "1.0.103", features = ["derive"], optional = true } +humantime-serde-crate = { package = "humantime-serde", version = "1", optional = true } + +[features] +default = ["humantime-serde"] +humantime-serde = ["humantime-serde-crate", "serde"] [dev-dependencies] educe = "0.4.6" diff --git a/crates/tor-basic-utils/src/humantime_serde_option.rs b/crates/tor-basic-utils/src/humantime_serde_option.rs new file mode 100644 index 0000000000000000000000000000000000000000..c2f4ef8f3855ad01e2cce7a7e4f45964e70e2171 --- /dev/null +++ b/crates/tor-basic-utils/src/humantime_serde_option.rs @@ -0,0 +1,24 @@ +//! Module to adaopt `humantime_serde` to `Option<Duration>` + +use humantime_serde_crate::Serde as HtSerde; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// Serializes an `Option<Duration>` or `Option<SystemTime>` via the humantime crate. +pub fn serialize<T, S>(d: &Option<T>, s: S) -> Result<S::Ok, S::Error> +where + for<'a> HtSerde<&'a T>: Serialize, + S: Serializer, +{ + let nested: Option<HtSerde<&T>> = d.as_ref().map(Into::into); + nested.serialize(s) +} + +/// Deserialize an `Option<Duration>` or `Option<SystemTime>` via the humantime crate. +pub fn deserialize<'a, T, D>(d: D) -> Result<Option<T>, D::Error> +where + HtSerde<T>: Deserialize<'a>, + D: Deserializer<'a>, +{ + let got: Option<HtSerde<T>> = Deserialize::deserialize(d)?; + Ok(got.map(HtSerde::into_inner)) +} diff --git a/crates/tor-basic-utils/src/lib.rs b/crates/tor-basic-utils/src/lib.rs index 811cb686690c1181c1655e81a732212a1e5f8e09..fc09b62108383b717ee7a46bdaef59ead311b06d 100644 --- a/crates/tor-basic-utils/src/lib.rs +++ b/crates/tor-basic-utils/src/lib.rs @@ -41,6 +41,9 @@ use std::fmt; +#[cfg(feature = "humantime-serde")] +pub mod humantime_serde_option; + // ---------------------------------------------------------------------- /// Function with the signature of `Debug::fmt` that just prints `".."` diff --git a/crates/tor-circmgr/Cargo.toml b/crates/tor-circmgr/Cargo.toml index 660fd2ea8ba3e234a822630e47867a08766e066c..5c624f6483b64e1f36afbe7f789e6751d367adf5 100644 --- a/crates/tor-circmgr/Cargo.toml +++ b/crates/tor-circmgr/Cargo.toml @@ -33,7 +33,7 @@ tor-rtcompat = { path="../tor-rtcompat", version = "0.1.0"} async-trait = "0.1.2" bounded-vec-deque = "0.1" -derive_builder = "0.10" +derive_builder = "0.10.2" educe = "0.4.6" futures = "0.3.14" humantime-serde = "1" diff --git a/crates/tor-circmgr/src/config.rs b/crates/tor-circmgr/src/config.rs index def852c61365bd50fd598f40e8426376339d251d..a866151d875bc98c61ddc2ee93fb1aeb0dc671db 100644 --- a/crates/tor-circmgr/src/config.rs +++ b/crates/tor-circmgr/src/config.rs @@ -4,6 +4,7 @@ //! //! Most types in this module are re-exported by `arti-client`. +use tor_basic_utils::humantime_serde_option; use tor_config::ConfigBuildError; use derive_builder::Builder; @@ -22,6 +23,7 @@ use std::time::Duration; /// restrictive. #[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] #[serde(deny_unknown_fields)] pub struct PathConfig { /// Set the length of a bit-prefix for a default IPv4 subnet-family. @@ -81,16 +83,6 @@ impl Default for PathConfig { } } -impl From<PathConfig> for PathConfigBuilder { - fn from(cfg: PathConfig) -> PathConfigBuilder { - let mut builder = PathConfigBuilder::default(); - builder - .ipv4_subnet_family_prefix(cfg.ipv4_subnet_family_prefix) - .ipv6_subnet_family_prefix(cfg.ipv6_subnet_family_prefix); - builder - } -} - /// Configuration for preemptive circuits. /// /// Preemptive circuits are built ahead of time, to anticipate client need. This @@ -103,6 +95,7 @@ impl From<PathConfig> for PathConfigBuilder { /// Except as noted, this configuration can be changed on a running Arti client. #[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] #[serde(deny_unknown_fields)] pub struct PreemptiveCircuitConfig { /// If we have at least this many available circuits, we suspend @@ -128,6 +121,7 @@ pub struct PreemptiveCircuitConfig { /// available for that port? #[builder(default = "default_preemptive_duration()")] #[serde(with = "humantime_serde", default = "default_preemptive_duration")] + #[builder(attrs(serde(with = "humantime_serde_option")))] pub(crate) prediction_lifetime: Duration, /// How many available circuits should we try to have, at minimum, for each @@ -149,12 +143,14 @@ pub struct PreemptiveCircuitConfig { /// [#263](https://gitlab.torproject.org/tpo/core/arti/-/issues/263). #[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] #[serde(deny_unknown_fields)] pub struct CircuitTiming { /// How long after a circuit has first been used should we give /// it out for new requests? #[builder(default = "default_max_dirtiness()")] #[serde(with = "humantime_serde", default = "default_max_dirtiness")] + #[builder(attrs(serde(with = "humantime_serde_option")))] pub(crate) max_dirtiness: Duration, /// When a circuit is requested, we stop retrying new circuits @@ -162,6 +158,7 @@ pub struct CircuitTiming { // TODO: Impose a maximum or minimum? #[builder(default = "default_request_timeout()")] #[serde(with = "humantime_serde", default = "default_request_timeout")] + #[builder(attrs(serde(with = "humantime_serde_option")))] pub(crate) request_timeout: Duration, /// When a circuit is requested, we stop retrying new circuits after @@ -176,6 +173,7 @@ pub struct CircuitTiming { /// request. #[builder(default = "default_request_loyalty()")] #[serde(with = "humantime_serde", default = "default_request_loyalty")] + #[builder(attrs(serde(with = "humantime_serde_option")))] pub(crate) request_loyalty: Duration, } @@ -236,18 +234,6 @@ impl CircuitTiming { } } -impl From<CircuitTiming> for CircuitTimingBuilder { - fn from(cfg: CircuitTiming) -> CircuitTimingBuilder { - let mut builder = CircuitTimingBuilder::default(); - builder - .max_dirtiness(cfg.max_dirtiness) - .request_timeout(cfg.request_timeout) - .request_max_retries(cfg.request_max_retries) - .request_loyalty(cfg.request_loyalty); - builder - } -} - impl Default for PreemptiveCircuitConfig { fn default() -> Self { PreemptiveCircuitConfigBuilder::default() @@ -263,18 +249,6 @@ impl PreemptiveCircuitConfig { } } -impl From<PreemptiveCircuitConfig> for PreemptiveCircuitConfigBuilder { - fn from(cfg: PreemptiveCircuitConfig) -> PreemptiveCircuitConfigBuilder { - let mut builder = PreemptiveCircuitConfigBuilder::default(); - builder - .disable_at_threshold(cfg.disable_at_threshold) - .initial_predicted_ports(cfg.initial_predicted_ports) - .prediction_lifetime(cfg.prediction_lifetime) - .min_exit_circs_for_port(cfg.min_exit_circs_for_port); - builder - } -} - /// Configuration for a circuit manager. /// /// This configuration includes information about how to build paths diff --git a/crates/tor-config/Cargo.toml b/crates/tor-config/Cargo.toml index 78eb20d2fe567a6ef2d79fd95a64956c294a7906..de3835fa1d3ec0a1f31542d39de2fdc3334cc4b1 100644 --- a/crates/tor-config/Cargo.toml +++ b/crates/tor-config/Cargo.toml @@ -18,7 +18,7 @@ expand-paths = ["shellexpand", "directories"] tor-error = { path="../tor-error", version = "0.1.0"} thiserror = "1" -derive_builder = "0.10" +derive_builder = "0.10.2" once_cell = "1" serde = { version = "1.0.103", features = ["derive"] } shellexpand = { version = "2.1", package = "shellexpand-fork", optional = true } diff --git a/crates/tor-dirmgr/Cargo.toml b/crates/tor-dirmgr/Cargo.toml index 70323b0fb85d2754b4a3e4c5c098e406b2c8adb4..c565c7dca258aff02aa9d376c5293090d9817410 100644 --- a/crates/tor-dirmgr/Cargo.toml +++ b/crates/tor-dirmgr/Cargo.toml @@ -33,7 +33,7 @@ tor-rtcompat = { path = "../tor-rtcompat", version = "0.1.0"} async-trait = "0.1.2" base64 = "0.13.0" -derive_builder = "0.10" +derive_builder = "0.10.2" derive_more = "0.99" digest = "0.10.0" educe = "0.4.6" diff --git a/crates/tor-dirmgr/src/authority.rs b/crates/tor-dirmgr/src/authority.rs index 475bce84cef43e654a5d1374429d626c6c281946..175a1e9ad8699af418c8f1aeecfaacd6d80de325 100644 --- a/crates/tor-dirmgr/src/authority.rs +++ b/crates/tor-dirmgr/src/authority.rs @@ -14,6 +14,7 @@ use tor_netdoc::doc::authcert::{AuthCert, AuthCertKeyIds}; // we want our authorities format to be future-proof against adding new info // about each authority. #[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)] +#[builder(derive(Deserialize))] pub struct Authority { /// A memorable nickname for this authority. #[builder(setter(into))] diff --git a/crates/tor-dirmgr/src/config.rs b/crates/tor-dirmgr/src/config.rs index 536d6bf4d82a8aa02cf1dd92446f4b72374c0c67..43db89af7d8fb8a88fb0407c39ea85062ecdd73c 100644 --- a/crates/tor-dirmgr/src/config.rs +++ b/crates/tor-dirmgr/src/config.rs @@ -28,6 +28,7 @@ use serde::Deserialize; #[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)] #[serde(deny_unknown_fields)] #[builder(build_fn(validate = "Self::validate", error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct NetworkConfig { /// List of locations to look in when downloading directory information, if /// we don't actually have a directory yet. @@ -62,16 +63,6 @@ impl Default for NetworkConfig { } } -impl From<NetworkConfig> for NetworkConfigBuilder { - fn from(cfg: NetworkConfig) -> NetworkConfigBuilder { - let mut builder = NetworkConfigBuilder::default(); - builder - .fallback_caches(cfg.fallback_caches) - .authorities(cfg.authorities); - builder - } -} - impl NetworkConfig { /// Return a new builder to construct a NetworkConfig. pub fn builder() -> NetworkConfigBuilder { @@ -110,6 +101,7 @@ impl NetworkConfigBuilder { #[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)] #[serde(deny_unknown_fields)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct DownloadScheduleConfig { /// Top-level configuration for how to retry our initial bootstrap attempt. #[serde(default = "default_retry_bootstrap")] @@ -157,18 +149,6 @@ impl DownloadScheduleConfig { } } -impl From<DownloadScheduleConfig> for DownloadScheduleConfigBuilder { - fn from(cfg: DownloadScheduleConfig) -> DownloadScheduleConfigBuilder { - let mut builder = DownloadScheduleConfigBuilder::default(); - builder - .retry_bootstrap(cfg.retry_bootstrap) - .retry_consensus(cfg.retry_consensus) - .retry_certs(cfg.retry_certs) - .retry_microdescs(cfg.retry_microdescs); - builder - } -} - /// Configuration type for network directory operations. /// /// This type is immutable once constructed. @@ -181,6 +161,7 @@ impl From<DownloadScheduleConfig> for DownloadScheduleConfigBuilder { /// running Arti client. Those that cannot are documented. #[derive(Debug, Clone, Builder, Eq, PartialEq)] #[builder(build_fn(error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct DirMgrConfig { /// Location to use for storing and reading current-format /// directory information. diff --git a/crates/tor-guardmgr/Cargo.toml b/crates/tor-guardmgr/Cargo.toml index ea1b4c345a4a1ec0830ac05fe8b9af0e8cd8f6b5..55dfedec702331e7fb8b9738645b4f07ee58cf5d 100644 --- a/crates/tor-guardmgr/Cargo.toml +++ b/crates/tor-guardmgr/Cargo.toml @@ -29,7 +29,7 @@ tor-proto = { path="../tor-proto", version = "0.1.0"} tor-rtcompat = { path="../tor-rtcompat", version = "0.1.0"} tor-units = { path="../tor-units", version = "0.1.0"} -derive_builder = "0.10" +derive_builder = "0.10.2" educe = "0.4.6" futures = "0.3.14" humantime-serde = "1" diff --git a/crates/tor-netdir/Cargo.toml b/crates/tor-netdir/Cargo.toml index e1c23baaf711340c2fb0fd97e04a22a1d418c8fc..61d846199d5b1b78184e5e44cc142ca56ff00cd1 100644 --- a/crates/tor-netdir/Cargo.toml +++ b/crates/tor-netdir/Cargo.toml @@ -33,7 +33,7 @@ tor-protover = { path="../tor-protover", version = "0.1.0"} tor-units = { path="../tor-units", version = "0.1.0"} bitflags = "1" -derive_builder = "0.10" +derive_builder = "0.10.2" derive_more = "0.99" hex = { version = "0.4", optional = true } hex-literal = { version = "0.3", optional = true } diff --git a/crates/tor-netdir/src/fallback.rs b/crates/tor-netdir/src/fallback.rs index 3de0d9747fd7e74610020e914768bedc5e127682..f4332b9f5483b21dbe43c0ec92ae9669cd854517 100644 --- a/crates/tor-netdir/src/fallback.rs +++ b/crates/tor-netdir/src/fallback.rs @@ -27,6 +27,7 @@ use std::net::SocketAddr; // be future-proof against adding new info about each fallback. #[derive(Debug, Clone, Deserialize, Builder, Eq, PartialEq)] #[builder(build_fn(validate = "FallbackDirBuilder::validate", error = "ConfigBuildError"))] +#[builder(derive(Deserialize))] pub struct FallbackDir { /// RSA identity for the directory relay rsa_identity: RsaIdentity, diff --git a/doc/semver_status.md b/doc/semver_status.md index 26568c4419e9be6eae467a43d2b0b5b32fe05974..ad348cf2682c31d84af92f83f766432352389df1 100644 --- a/doc/semver_status.md +++ b/doc/semver_status.md @@ -19,6 +19,13 @@ We can delete older sections here after we bump the releases. ## Since Arti 0.1.0 +arti-client, arti-config, tor-circmgr, tor-dirmgr: + + Drop conversion from FooConfig to FooConfigBuilder for many Foo. + Further change in this area is expected. + + Drop impl Deserialize for ArtiConfig. + tor-llcrypto: new-api: Added RsaIdentity::from_hex().