From a101091ffd5028cf852ca68d91ee5a320e41e60b Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 3 Jan 2023 17:49:50 +0100 Subject: [PATCH 01/11] refactor: Split configs in server and service We used to use the same config for the service and server (aka the binary). This is confusing when creating configs to use with e.g. iroh-one, iroh-embed or iroh-share because some fields are not used. This splits off the config structs to avoid this problem, services now have a Config and binaries a ServerConfig. This allows creating the services standalone without all the baggage a server needs. While this isn't many fields yet, this will get worse as we add more features (this is split off from another PR where this seemed useful). --- iroh-api/benches/add.rs | 2 - iroh-embed/src/store.rs | 1 - iroh-gateway/src/core.rs | 1 - iroh-one/src/config.rs | 6 +-- iroh-share/src/p2p_node.rs | 4 -- iroh-store/benches/rpc.rs | 3 -- iroh-store/benches/store.rs | 3 -- iroh-store/src/config.rs | 79 +++++++++++++++++++++++++++++++------ iroh-store/src/main.rs | 7 ++-- iroh-store/src/store.rs | 4 -- 10 files changed, 72 insertions(+), 38 deletions(-) diff --git a/iroh-api/benches/add.rs b/iroh-api/benches/add.rs index 1f94d92be3..bd3f63da58 100644 --- a/iroh-api/benches/add.rs +++ b/iroh-api/benches/add.rs @@ -1,6 +1,5 @@ use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use futures::TryStreamExt; -use iroh_metrics::config::Config as MetricsConfig; use iroh_resolver::resolver::Resolver; use iroh_rpc_client::{Client, Config as RpcClientConfig}; use iroh_rpc_types::Addr; @@ -44,7 +43,6 @@ fn add_benchmark(c: &mut Criterion) { let config = StoreConfig { path: dir.path().join("db"), rpc_client: rpc_client.clone(), - metrics: MetricsConfig::default(), }; let (_task, client, resolver) = executor.block_on(async { let store = Store::create(config).await.unwrap(); diff --git a/iroh-embed/src/store.rs b/iroh-embed/src/store.rs index 590e6d6f80..ea816bb9d8 100644 --- a/iroh-embed/src/store.rs +++ b/iroh-embed/src/store.rs @@ -34,7 +34,6 @@ impl RocksStoreService { store_addr: Some(addr.clone()), channels: Some(1), }, - metrics: Default::default(), }; let task = mem_store::start(addr.clone(), config).await?; Ok(Self { task, addr }) diff --git a/iroh-gateway/src/core.rs b/iroh-gateway/src/core.rs index f908fb98a1..78d8c5ea10 100644 --- a/iroh-gateway/src/core.rs +++ b/iroh-gateway/src/core.rs @@ -197,7 +197,6 @@ mod tests { let config = iroh_store::Config { path: store_dir.path().join("db"), rpc_client: RpcClientConfig::default(), - metrics: iroh_metrics::config::Config::default(), }; let store = iroh_store::Store::create(config).await.unwrap(); let task = diff --git a/iroh-one/src/config.rs b/iroh-one/src/config.rs index 9e4e86ba11..029b8a6408 100644 --- a/iroh-one/src/config.rs +++ b/iroh-one/src/config.rs @@ -78,7 +78,6 @@ impl Config { self.store.rpc_client = self.rpc_client.clone(); self.gateway.metrics = self.metrics.clone(); self.p2p.metrics = self.metrics.clone(); - self.store.metrics = self.metrics.clone(); } } @@ -93,8 +92,7 @@ impl Default for Config { .join("ipfsd.http"); let rpc_client = Self::default_rpc_config(); let metrics_config = MetricsConfig::default(); - let store_config = - default_store_config(None, rpc_client.clone(), metrics_config.clone()).unwrap(); + let store_config = default_store_config(None, rpc_client.clone()).unwrap(); let key_store_path = iroh_util::iroh_data_root().unwrap(); Self { rpc_client: rpc_client.clone(), @@ -111,13 +109,11 @@ impl Default for Config { fn default_store_config( store_path: Option, ipfsd: RpcClientConfig, - metrics: iroh_metrics::config::Config, ) -> Result { let path = config_data_path(store_path)?; Ok(iroh_store::config::Config { path, rpc_client: ipfsd, - metrics, }) } diff --git a/iroh-share/src/p2p_node.rs b/iroh-share/src/p2p_node.rs index 093d73b0dc..b216a7ec54 100644 --- a/iroh-share/src/p2p_node.rs +++ b/iroh-share/src/p2p_node.rs @@ -173,10 +173,6 @@ impl P2pNode { let store_config = iroh_store::Config { path: db_path.to_path_buf(), rpc_client: rpc_store_client_config, - metrics: iroh_metrics::config::Config { - tracing: false, // disable tracing by default - ..Default::default() - }, }; let store = if store_config.path.exists() { diff --git a/iroh-store/benches/rpc.rs b/iroh-store/benches/rpc.rs index a0c6aacc78..82f272e23b 100644 --- a/iroh-store/benches/rpc.rs +++ b/iroh-store/benches/rpc.rs @@ -3,7 +3,6 @@ use std::time::Instant; use bytes::Bytes; use cid::multihash::{Code, MultihashDigest}; use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; -use iroh_metrics::config::Config as MetricsConfig; use iroh_rpc_client::{Client, Config as RpcClientConfig}; use iroh_rpc_types::{store::StoreAddr, Addr}; use iroh_store::{Config, Store}; @@ -63,7 +62,6 @@ pub fn put_benchmark(c: &mut Criterion) { let config = Config { path: dir.path().join("db"), rpc_client: rpc_client.clone(), - metrics: MetricsConfig::default(), }; let (_task, rpc) = executor.block_on(async { let store = Store::create(config).await.unwrap(); @@ -116,7 +114,6 @@ pub fn get_benchmark(c: &mut Criterion) { let config = Config { path: dir.path().join("db"), rpc_client: rpc_client.clone(), - metrics: MetricsConfig::default(), }; let (_task, rpc) = executor.block_on(async { let store = Store::create(config).await.unwrap(); diff --git a/iroh-store/benches/store.rs b/iroh-store/benches/store.rs index 54aebb7eda..a70343113b 100644 --- a/iroh-store/benches/store.rs +++ b/iroh-store/benches/store.rs @@ -2,7 +2,6 @@ use std::time::Instant; use cid::multihash::{Code, MultihashDigest}; use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; -use iroh_metrics::config::Config as MetricsConfig; use iroh_rpc_client::Config as RpcClientConfig; use iroh_store::{Config, Store}; use tokio::runtime::Runtime; @@ -27,7 +26,6 @@ pub fn put_benchmark(c: &mut Criterion) { let config = Config { path: dir.path().into(), rpc_client, - metrics: MetricsConfig::default(), }; let store = executor.block_on(async { Store::create(config).await.unwrap() }); let store_ref = &store; @@ -53,7 +51,6 @@ pub fn get_benchmark(c: &mut Criterion) { let config = Config { path: dir.path().into(), rpc_client, - metrics: MetricsConfig::default(), }; let store = executor.block_on(async { Store::create(config).await.unwrap() }); let store_ref = &store; diff --git a/iroh-store/src/config.rs b/iroh-store/src/config.rs index 2eb493b01f..f5532a88a5 100644 --- a/iroh-store/src/config.rs +++ b/iroh-store/src/config.rs @@ -23,15 +23,77 @@ pub fn config_data_path(arg_path: Option) -> Result { } } -/// The configuration for the store. +/// The configuration for the store server. +/// +/// This is the configuration which the store server binary needs to run. This is a +/// superset from the configuration needed by the store service, which can also run +/// integrated into another binary like in iroh-one, iroh-share and iroh-embed. +/// +/// This config can be deserialised from a config file. +// TODO: I'd prefer to include [`Config`] under the `store` field like iroh-one does. But +// that's a backwards incompatible change. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] -pub struct Config { +pub struct ServerConfig { /// The location of the content database. pub path: PathBuf, pub rpc_client: RpcClientConfig, + /// Configuration for metrics export. pub metrics: MetricsConfig, } +impl ServerConfig { + pub fn new(path: PathBuf) -> Self { + let addr = "irpc://0.0.0.0:4402".parse().unwrap(); + Self { + path, + rpc_client: RpcClientConfig { + store_addr: Some(addr), + ..Default::default() + }, + metrics: Default::default(), + } + } +} + +impl Source for ServerConfig { + fn clone_into_box(&self) -> Box { + Box::new(self.clone()) + } + fn collect(&self) -> Result, ConfigError> { + let mut map: Map = Map::new(); + let path = self + .path + .to_str() + .ok_or_else(|| ConfigError::Foreign("No `path` set. Path is required.".into()))?; + insert_into_config_map(&mut map, "path", path); + insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); + insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); + + Ok(map) + } +} + +/// The configuration for the store service. +/// +/// As opposed to the [`ServerConfig`] this is only the configuration needed to run the +/// store service. It can still be deserialised from a file, which is e.g. used by +/// iroh-one. +#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] +pub struct Config { + /// The location of the content database. + pub path: PathBuf, + pub rpc_client: RpcClientConfig, +} + +impl From for Config { + fn from(source: ServerConfig) -> Self { + Self { + path: source.path, + rpc_client: source.rpc_client, + } + } +} + impl Config { pub fn new_with_rpc(path: PathBuf, client_addr: StoreAddr) -> Self { Self { @@ -40,15 +102,9 @@ impl Config { store_addr: Some(client_addr), ..Default::default() }, - metrics: MetricsConfig::default(), } } - pub fn new_network(path: PathBuf) -> Self { - let addr = "irpc://0.0.0.0:4402"; - Self::new_with_rpc(path, addr.parse().unwrap()) - } - pub fn rpc_addr(&self) -> Option { self.rpc_client.store_addr.clone() } @@ -66,7 +122,6 @@ impl Source for Config { .ok_or_else(|| ConfigError::Foreign("No `path` set. Path is required.".into()))?; insert_into_config_map(&mut map, "path", path); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); - insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); Ok(map) } @@ -80,7 +135,7 @@ mod tests { #[cfg(unix)] fn test_collect() { let path = PathBuf::new().join("test"); - let default = Config::new_network(path); + let default = ServerConfig::new(path); let mut expect: Map = Map::new(); expect.insert( @@ -108,8 +163,8 @@ mod tests { #[cfg(unix)] fn test_build_config_from_struct() { let path = PathBuf::new().join("test"); - let expect = Config::new_network(path); - let got: Config = config::Config::builder() + let expect = ServerConfig::new(path); + let got: ServerConfig = config::Config::builder() .add_source(expect.clone()) .build() .unwrap() diff --git a/iroh-store/src/main.rs b/iroh-store/src/main.rs index d8bf03d14e..20a53ab333 100644 --- a/iroh-store/src/main.rs +++ b/iroh-store/src/main.rs @@ -2,8 +2,8 @@ use anyhow::anyhow; use clap::Parser; use iroh_store::{ cli::Args, - config::{config_data_path, CONFIG_FILE_NAME, ENV_PREFIX}, - metrics, rpc, Config, Store, + config::{config_data_path, Config, ServerConfig, CONFIG_FILE_NAME, ENV_PREFIX}, + metrics, rpc, Store, }; use iroh_util::lock::ProgramLock; use iroh_util::{block_until_sigint, iroh_config_path, make_config}; @@ -24,7 +24,7 @@ async fn main() -> anyhow::Result<()> { let config_data_path = config_data_path(args.path.clone())?; let config = make_config( // default - Config::new_network(config_data_path), + ServerConfig::new(config_data_path), // potential config files sources, // env var prefix for this config @@ -49,6 +49,7 @@ async fn main() -> anyhow::Result<()> { } } + let config = Config::from(config); let rpc_addr = config .rpc_addr() .ok_or_else(|| anyhow!("missing store rpc addr"))?; diff --git a/iroh-store/src/store.rs b/iroh-store/src/store.rs index a1cb6136c9..515df9f8a4 100644 --- a/iroh-store/src/store.rs +++ b/iroh-store/src/store.rs @@ -696,7 +696,6 @@ mod tests { use super::*; - use iroh_metrics::config::Config as MetricsConfig; use iroh_rpc_client::Config as RpcClientConfig; use cid::multihash::{Code, MultihashDigest}; @@ -716,7 +715,6 @@ mod tests { let config = Config { path: dir.path().into(), rpc_client, - metrics: MetricsConfig::default(), }; let store = Store::create(config).await.unwrap(); @@ -755,7 +753,6 @@ mod tests { let config = Config { path: dir.path().into(), rpc_client, - metrics: MetricsConfig::default(), }; let store = Store::create(config.clone()).await.unwrap(); @@ -824,7 +821,6 @@ mod tests { let config = Config { path: dir.path().into(), rpc_client, - metrics: MetricsConfig::default(), }; let store = Store::create(config).await?; From 0858835ef676fa5da0bac7e38b404f690a5236b1 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 3 Jan 2023 18:21:54 +0100 Subject: [PATCH 02/11] p2p --- iroh-one/src/config.rs | 12 ++----- iroh-p2p/src/config.rs | 70 +++++++++++++++++++++++++++++++++++--- iroh-p2p/src/main.rs | 4 ++- iroh-share/src/p2p_node.rs | 1 - iroh-store/src/config.rs | 2 -- 5 files changed, 71 insertions(+), 18 deletions(-) diff --git a/iroh-one/src/config.rs b/iroh-one/src/config.rs index 029b8a6408..944d8b0ddc 100644 --- a/iroh-one/src/config.rs +++ b/iroh-one/src/config.rs @@ -77,7 +77,6 @@ impl Config { self.p2p.rpc_client = self.rpc_client.clone(); self.store.rpc_client = self.rpc_client.clone(); self.gateway.metrics = self.metrics.clone(); - self.p2p.metrics = self.metrics.clone(); } } @@ -96,10 +95,10 @@ impl Default for Config { let key_store_path = iroh_util::iroh_data_root().unwrap(); Self { rpc_client: rpc_client.clone(), - metrics: metrics_config.clone(), + metrics: metrics_config, gateway: iroh_gateway::config::Config::default(), store: store_config, - p2p: default_p2p_config(rpc_client, metrics_config, key_store_path), + p2p: default_p2p_config(rpc_client, key_store_path), #[cfg(all(feature = "http-uds-gateway", unix))] gateway_uds_path: Some(gateway_uds_path), } @@ -117,15 +116,10 @@ fn default_store_config( }) } -fn default_p2p_config( - ipfsd: RpcClientConfig, - metrics: iroh_metrics::config::Config, - key_store_path: PathBuf, -) -> iroh_p2p::config::Config { +fn default_p2p_config(ipfsd: RpcClientConfig, key_store_path: PathBuf) -> iroh_p2p::config::Config { iroh_p2p::config::Config { libp2p: Libp2pConfig::default(), rpc_client: ipfsd, - metrics, key_store_path, } } diff --git a/iroh-p2p/src/config.rs b/iroh-p2p/src/config.rs index 2cba51467e..e360a42dbc 100644 --- a/iroh-p2p/src/config.rs +++ b/iroh-p2p/src/config.rs @@ -30,6 +30,60 @@ pub const DEFAULT_BOOTSTRAP: &[&str] = &[ // "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io +/// The configuration for the p2p server. +/// +/// This is the configuration which the p2p server binary needs to run. It is a superset +/// from the configuration needed by the p2p service, which can also run integrated into +/// another binary like in iroh-one, iroh-share or iroh-embed. +// TODO: I'd prefer to include [`Config`] under a `p2p` field like iroh-one does. But +// that's a backwards incompatible change for the config file. +#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] +pub struct ServerConfig { + pub libp2p: Libp2pConfig, + pub rpc_client: RpcClientConfig, + pub metrics: MetricsConfig, + /// Directory where cryptographic keys are stored. + /// + /// The p2p node needs to have an identity consisting of a cryptographic key pair. As + /// it is useful to have the same identity across restarts this is stored on disk in a + /// format compatible with how ssh stores keys. This points to a directory where these + /// keypairs are stored. + pub key_store_path: PathBuf, +} + +impl ServerConfig { + pub fn new() -> Self { + Default::default() + } +} + +impl Default for ServerConfig { + fn default() -> Self { + Self { + libp2p: Default::default(), + rpc_client: RpcClientConfig::default_network(), + metrics: Default::default(), + key_store_path: iroh_data_root().unwrap(), + } + } +} + +impl Source for ServerConfig { + fn clone_into_box(&self) -> Box { + Box::new(self.clone()) + } + + fn collect(&self) -> Result, ConfigError> { + let mut map: Map = Map::new(); + + insert_into_config_map(&mut map, "libp2p", self.libp2p.collect()?); + insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); + insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); + insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); + Ok(map) + } +} + /// Libp2p config for the node. #[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)] #[non_exhaustive] @@ -69,7 +123,6 @@ pub struct Libp2pConfig { pub struct Config { pub libp2p: Libp2pConfig, pub rpc_client: RpcClientConfig, - pub metrics: MetricsConfig, /// Directory where cryptographic keys are stored. /// /// The p2p node needs to have an identity consisting of a cryptographic key pair. As @@ -79,6 +132,16 @@ pub struct Config { pub key_store_path: PathBuf, } +impl From for Config { + fn from(source: ServerConfig) -> Self { + Self { + libp2p: source.libp2p, + rpc_client: source.rpc_client, + key_store_path: source.key_store_path, + } + } +} + impl Source for Libp2pConfig { fn clone_into_box(&self) -> Box { Box::new(self.clone()) @@ -152,7 +215,6 @@ impl Source for Config { insert_into_config_map(&mut map, "libp2p", self.libp2p.collect()?); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); - insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); Ok(map) } @@ -199,7 +261,6 @@ impl Config { p2p_addr: Some(client_addr), ..Default::default() }, - metrics: MetricsConfig::default(), key_store_path: iroh_data_root().unwrap(), } } @@ -210,7 +271,6 @@ impl Config { Self { libp2p: Libp2pConfig::default(), rpc_client, - metrics: MetricsConfig::default(), key_store_path: iroh_data_root().unwrap(), } } @@ -227,7 +287,7 @@ mod tests { #[test] fn test_collect() { - let default = Config::default_network(); + let default = ServerConfig::default(); let bootstrap_peers: Vec = default .libp2p .bootstrap_peers diff --git a/iroh-p2p/src/main.rs b/iroh-p2p/src/main.rs index 31ee9e4924..f341272b47 100644 --- a/iroh-p2p/src/main.rs +++ b/iroh-p2p/src/main.rs @@ -1,6 +1,7 @@ use anyhow::{anyhow, Context, Result}; use clap::Parser; use iroh_p2p::config::{Config, CONFIG_FILE_NAME, ENV_PREFIX}; +use iroh_p2p::ServerConfig; use iroh_p2p::{cli::Args, metrics, DiskStorage, Keychain, Node}; use iroh_util::lock::ProgramLock; use iroh_util::{iroh_config_path, make_config}; @@ -30,7 +31,7 @@ fn main() -> Result<()> { let sources = [Some(cfg_path.as_path()), args.cfg.as_deref()]; let network_config = make_config( // default - Config::default_network(), + ServerConfig::default(), // potential config files &sources, // env var prefix for this config @@ -56,6 +57,7 @@ fn main() -> Result<()> { } let kc = Keychain::::new(network_config.key_store_path.clone()).await?; + let network_config = Config::from(network_config); let rpc_addr = network_config .rpc_addr() .ok_or_else(|| anyhow!("missing p2p rpc addr"))?; diff --git a/iroh-share/src/p2p_node.rs b/iroh-share/src/p2p_node.rs index b216a7ec54..969ba74467 100644 --- a/iroh-share/src/p2p_node.rs +++ b/iroh-share/src/p2p_node.rs @@ -162,7 +162,6 @@ impl P2pNode { let config = config::Config { libp2p: libp2p_config, rpc_client: rpc_p2p_client_config.clone(), - metrics: Default::default(), key_store_path: db_path.parent().unwrap().to_path_buf(), }; diff --git a/iroh-store/src/config.rs b/iroh-store/src/config.rs index f5532a88a5..1d2d9c4e48 100644 --- a/iroh-store/src/config.rs +++ b/iroh-store/src/config.rs @@ -28,8 +28,6 @@ pub fn config_data_path(arg_path: Option) -> Result { /// This is the configuration which the store server binary needs to run. This is a /// superset from the configuration needed by the store service, which can also run /// integrated into another binary like in iroh-one, iroh-share and iroh-embed. -/// -/// This config can be deserialised from a config file. // TODO: I'd prefer to include [`Config`] under the `store` field like iroh-one does. But // that's a backwards incompatible change. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] From 3518561ea219fdaa9698e57416c2aacc0e55ffd8 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Tue, 3 Jan 2023 18:43:22 +0100 Subject: [PATCH 03/11] gateway --- iroh-gateway/src/config.rs | 129 +++++++++++++++++++++++++++++++++++-- iroh-gateway/src/main.rs | 5 +- iroh-one/src/config.rs | 1 - iroh-store/src/config.rs | 2 +- 4 files changed, 126 insertions(+), 11 deletions(-) diff --git a/iroh-gateway/src/config.rs b/iroh-gateway/src/config.rs index 7d8140c475..f1bc096669 100644 --- a/iroh-gateway/src/config.rs +++ b/iroh-gateway/src/config.rs @@ -21,9 +21,17 @@ pub const CONFIG_FILE_NAME: &str = "gateway.config.toml"; pub const ENV_PREFIX: &str = "IROH_GATEWAY"; pub const DEFAULT_PORT: u16 = 9050; -/// Configuration for [`iroh-gateway`]. +/// The configuration for the gateway server. +/// +/// This is the configuration which the gateway server binary needs to run. This is a +/// superset from the configuration needed by the gateway service, which can also run +/// integrated into another binary like iroh-one, iroh-share or iroh-embed. +// TODO: I'd prefer to include [`Config`] under the `gateway` field liek iroh-one does. But +// that's a backwards incompatible change. +// TODO: If this was moved into main.rs it would not need to be public. Our binary is build +// as being outside of the lib crate, hence here it needs to be public. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct Config { +pub struct ServerConfig { /// Pretty URL to redirect to #[serde(default = "String::new")] pub public_url_base: String, @@ -55,7 +63,7 @@ pub struct Config { pub redirect_to_subdomain: bool, } -impl Config { +impl ServerConfig { pub fn new(port: u16, rpc_client: RpcClientConfig) -> Self { Self { public_url_base: String::new(), @@ -70,6 +78,100 @@ impl Config { redirect_to_subdomain: false, } } +} + +impl Default for ServerConfig { + fn default() -> Self { + let inner = Config::default(); + Self { + public_url_base: inner.public_url_base, + port: inner.port, + use_denylist: inner.use_denylist, + http_resolvers: inner.http_resolvers, + dns_resolver: inner.dns_resolver, + indexer_endpoint: inner.indexer_endpoint, + rpc_client: inner.rpc_client, + metrics: Default::default(), + headers: inner.headers, + redirect_to_subdomain: inner.redirect_to_subdomain, + } + } +} + +impl Source for ServerConfig { + fn clone_into_box(&self) -> Box { + Box::new(self.clone()) + } + + fn collect(&self) -> Result, ConfigError> { + let rpc_client = self.rpc_client.collect()?; + let mut map: Map = Map::new(); + insert_into_config_map(&mut map, "public_url_base", self.public_url_base.clone()); + insert_into_config_map(&mut map, "use_denylist", self.use_denylist); + // Some issue between deserializing u64 & u16, converting this to + // an signed int fixes the issue + insert_into_config_map(&mut map, "port", self.port as i32); + insert_into_config_map(&mut map, "headers", collect_headers(&self.headers)?); + insert_into_config_map(&mut map, "rpc_client", rpc_client); + let metrics = self.metrics.collect()?; + insert_into_config_map(&mut map, "metrics", metrics); + + if let Some(http_resolvers) = &self.http_resolvers { + insert_into_config_map(&mut map, "http_resolvers", http_resolvers.clone()); + } + if let Some(indexer_endpoint) = &self.indexer_endpoint { + insert_into_config_map(&mut map, "indexer_endpoint", indexer_endpoint.clone()); + } + Ok(map) + } +} + +/// Configuration for [`iroh-gateway`]. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct Config { + /// Pretty URL to redirect to + #[serde(default = "String::new")] + pub public_url_base: String, + /// default port to listen on + pub port: u16, + /// flag to toggle whether the gateway should use denylist on requests + pub use_denylist: bool, + /// URL of gateways to be used by the racing resolver. + /// Strings can either be urls or subdomain gateway roots + /// values without https:// prefix are treated as subdomain gateways (eg: dweb.link) + /// values with are treated as IPFS path gateways (eg: ) + pub http_resolvers: Option>, + /// Separate resolvers for particular TLDs + #[serde(default = "DnsResolverConfig::default")] + pub dns_resolver: DnsResolverConfig, + /// Indexer node to use. + pub indexer_endpoint: Option, + /// rpc addresses for the gateway & addresses for the rpc client to dial + pub rpc_client: RpcClientConfig, + // NOTE: for toml to serialize properly, the "table" values must be serialized at the end, and + // so much come at the end of the `Config` struct + /// set of user provided headers to attach to all responses + #[serde(with = "http_serde::header_map")] + pub headers: HeaderMap, + /// Redirects to subdomains for path requests + #[serde(default)] + pub redirect_to_subdomain: bool, +} + +impl Config { + pub fn new(port: u16, rpc_client: RpcClientConfig) -> Self { + Self { + public_url_base: String::new(), + headers: HeaderMap::new(), + port, + rpc_client, + http_resolvers: None, + dns_resolver: DnsResolverConfig::default(), + indexer_endpoint: None, + use_denylist: false, + redirect_to_subdomain: false, + } + } pub fn set_default_headers(&mut self) { self.headers = default_headers(); @@ -80,6 +182,22 @@ impl Config { } } +impl From for Config { + fn from(source: ServerConfig) -> Self { + Self { + public_url_base: source.public_url_base, + port: source.port, + use_denylist: source.use_denylist, + http_resolvers: source.http_resolvers, + dns_resolver: source.dns_resolver, + indexer_endpoint: source.indexer_endpoint, + rpc_client: source.rpc_client, + headers: source.headers, + redirect_to_subdomain: source.redirect_to_subdomain, + } + } +} + fn default_headers() -> HeaderMap { let mut headers = HeaderMap::new(); headers.typed_insert(AccessControlAllowOrigin::ANY); @@ -136,7 +254,6 @@ impl Default for Config { http_resolvers: None, dns_resolver: DnsResolverConfig::default(), indexer_endpoint: None, - metrics: MetricsConfig::default(), use_denylist: false, redirect_to_subdomain: false, }; @@ -160,8 +277,6 @@ impl Source for Config { insert_into_config_map(&mut map, "port", self.port as i32); insert_into_config_map(&mut map, "headers", collect_headers(&self.headers)?); insert_into_config_map(&mut map, "rpc_client", rpc_client); - let metrics = self.metrics.collect()?; - insert_into_config_map(&mut map, "metrics", metrics); if let Some(http_resolvers) = &self.http_resolvers { insert_into_config_map(&mut map, "http_resolvers", http_resolvers.clone()); @@ -228,7 +343,7 @@ mod tests { #[test] fn test_collect() { - let default = Config::default(); + let default = ServerConfig::default(); let mut expect: Map = Map::new(); expect.insert( "public_url_base".to_string(), diff --git a/iroh-gateway/src/main.rs b/iroh-gateway/src/main.rs index e02ee70393..2574ad313c 100644 --- a/iroh-gateway/src/main.rs +++ b/iroh-gateway/src/main.rs @@ -5,7 +5,7 @@ use clap::Parser; use iroh_gateway::{ bad_bits::{self, BadBits}, cli::Args, - config::{Config, CONFIG_FILE_NAME, ENV_PREFIX}, + config::{Config, ServerConfig, CONFIG_FILE_NAME, ENV_PREFIX}, core::Core, metrics, }; @@ -26,7 +26,7 @@ async fn main() -> Result<()> { let sources = [Some(cfg_path.as_path()), args.cfg.as_deref()]; let mut config = make_config( // default - Config::default(), + ServerConfig::default(), // potential config files &sources, // env var prefix for this config @@ -44,6 +44,7 @@ async fn main() -> Result<()> { true => Arc::new(Some(RwLock::new(BadBits::new()))), false => Arc::new(None), }; + let config = Config::from(config); let rpc_addr = config .rpc_addr() .ok_or_else(|| anyhow!("missing gateway rpc addr"))?; diff --git a/iroh-one/src/config.rs b/iroh-one/src/config.rs index 944d8b0ddc..524de79b26 100644 --- a/iroh-one/src/config.rs +++ b/iroh-one/src/config.rs @@ -76,7 +76,6 @@ impl Config { self.gateway.rpc_client = self.rpc_client.clone(); self.p2p.rpc_client = self.rpc_client.clone(); self.store.rpc_client = self.rpc_client.clone(); - self.gateway.metrics = self.metrics.clone(); } } diff --git a/iroh-store/src/config.rs b/iroh-store/src/config.rs index 1d2d9c4e48..6c0800f2c8 100644 --- a/iroh-store/src/config.rs +++ b/iroh-store/src/config.rs @@ -27,7 +27,7 @@ pub fn config_data_path(arg_path: Option) -> Result { /// /// This is the configuration which the store server binary needs to run. This is a /// superset from the configuration needed by the store service, which can also run -/// integrated into another binary like in iroh-one, iroh-share and iroh-embed. +/// integrated into another binary like in iroh-one, iroh-share or iroh-embed. // TODO: I'd prefer to include [`Config`] under the `store` field like iroh-one does. But // that's a backwards incompatible change. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] From 6e91e09e3472f840ab33523abd43cac19365ca57 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 15:56:10 +0100 Subject: [PATCH 04/11] remove duplication between store Config and ServerConfig This adds a StoreConfig section to remove duplication. --- iroh-api/benches/add.rs | 8 +--- iroh-embed/src/store.rs | 11 +----- iroh-gateway/src/core.rs | 5 +-- iroh-one/src/config.rs | 2 +- iroh-one/src/mem_store.rs | 6 +-- iroh-rpc-client/src/config.rs | 3 ++ iroh-share/src/p2p_node.rs | 7 +++- iroh-store/benches/rpc.rs | 16 ++------ iroh-store/benches/store.rs | 13 +------ iroh-store/src/config.rs | 69 ++++++++++++++++++++++++----------- iroh-store/src/main.rs | 6 +-- iroh-store/src/store.rs | 31 ++++------------ 12 files changed, 81 insertions(+), 96 deletions(-) diff --git a/iroh-api/benches/add.rs b/iroh-api/benches/add.rs index bd3f63da58..170c0d4a66 100644 --- a/iroh-api/benches/add.rs +++ b/iroh-api/benches/add.rs @@ -36,14 +36,10 @@ fn add_benchmark(c: &mut Criterion) { let server_addr = Addr::new_mem(); let client_addr = server_addr.clone(); let rpc_client = RpcClientConfig { - store_addr: Some(client_addr), + store_addr: Some(client_addr.clone()), ..Default::default() }; - - let config = StoreConfig { - path: dir.path().join("db"), - rpc_client: rpc_client.clone(), - }; + let config = StoreConfig::with_rpc_addr(dir.path().join("db"), client_addr); let (_task, client, resolver) = executor.block_on(async { let store = Store::create(config).await.unwrap(); let task = executor.spawn(async move { diff --git a/iroh-embed/src/store.rs b/iroh-embed/src/store.rs index ea816bb9d8..1fc6a321bc 100644 --- a/iroh-embed/src/store.rs +++ b/iroh-embed/src/store.rs @@ -4,7 +4,6 @@ use std::path::PathBuf; use anyhow::Result; use iroh_one::mem_store; -use iroh_rpc_client::Config as RpcClientConfig; use iroh_rpc_types::store::StoreAddr; use iroh_rpc_types::Addr; use iroh_store::Config as StoreConfig; @@ -26,15 +25,7 @@ impl RocksStoreService { /// This implicitly starts a task on the tokio runtime to manage the storage node. pub async fn new(path: PathBuf) -> Result { let addr = Addr::new_mem(); - let config = StoreConfig { - path, - rpc_client: RpcClientConfig { - gateway_addr: None, - p2p_addr: None, - store_addr: Some(addr.clone()), - channels: Some(1), - }, - }; + let config = StoreConfig::with_rpc_addr(path, addr.clone()); let task = mem_store::start(addr.clone(), config).await?; Ok(Self { task, addr }) } diff --git a/iroh-gateway/src/core.rs b/iroh-gateway/src/core.rs index 78d8c5ea10..6060de5977 100644 --- a/iroh-gateway/src/core.rs +++ b/iroh-gateway/src/core.rs @@ -194,10 +194,7 @@ mod tests { let server_addr = Addr::new_mem(); let client_addr = server_addr.clone(); let store_dir = tempfile::tempdir().unwrap(); - let config = iroh_store::Config { - path: store_dir.path().join("db"), - rpc_client: RpcClientConfig::default(), - }; + let config = iroh_store::Config::new(store_dir.path().join("db")); let store = iroh_store::Store::create(config).await.unwrap(); let task = tokio::spawn(async move { iroh_store::rpc::new(server_addr, store).await.unwrap() }); diff --git a/iroh-one/src/config.rs b/iroh-one/src/config.rs index 524de79b26..7028487eb8 100644 --- a/iroh-one/src/config.rs +++ b/iroh-one/src/config.rs @@ -110,7 +110,7 @@ fn default_store_config( ) -> Result { let path = config_data_path(store_path)?; Ok(iroh_store::config::Config { - path, + store: iroh_store::config::StoreConfig { path }, rpc_client: ipfsd, }) } diff --git a/iroh-one/src/mem_store.rs b/iroh-one/src/mem_store.rs index c613d2de2b..72e07e8c80 100644 --- a/iroh-one/src/mem_store.rs +++ b/iroh-one/src/mem_store.rs @@ -10,15 +10,15 @@ pub async fn start(rpc_addr: StoreAddr, config: Config) -> anyhow::Result, /// Number of concurent channels. + /// + /// If `None` defaults to `1`, not used for in-memory addresses. + // TODO: Consider changing this to NonZeroUsize instead of Option. pub channels: Option, } diff --git a/iroh-share/src/p2p_node.rs b/iroh-share/src/p2p_node.rs index 969ba74467..dab5b32a45 100644 --- a/iroh-share/src/p2p_node.rs +++ b/iroh-share/src/p2p_node.rs @@ -7,6 +7,7 @@ use iroh_p2p::{config, Keychain, MemoryStorage, NetworkEvent, Node}; use iroh_resolver::resolver::Resolver; use iroh_rpc_client::Client; use iroh_rpc_types::Addr; +use iroh_store::config::StoreConfig; use iroh_unixfs::{ content_loader::{ContentLoader, ContextId, LoaderContext, IROH_STORE}, parse_links, LoadedCid, Source, @@ -170,11 +171,13 @@ impl P2pNode { let resolver = iroh_resolver::resolver::Resolver::new(loader); let store_config = iroh_store::Config { - path: db_path.to_path_buf(), + store: StoreConfig { + path: db_path.to_path_buf(), + }, rpc_client: rpc_store_client_config, }; - let store = if store_config.path.exists() { + let store = if store_config.store.path.exists() { iroh_store::Store::open(store_config).await? } else { iroh_store::Store::create(store_config).await? diff --git a/iroh-store/benches/rpc.rs b/iroh-store/benches/rpc.rs index 82f272e23b..df9d1164ea 100644 --- a/iroh-store/benches/rpc.rs +++ b/iroh-store/benches/rpc.rs @@ -55,14 +55,10 @@ pub fn put_benchmark(c: &mut Criterion) { let executor = Runtime::new().unwrap(); let (server_addr, client_addr, _dir) = transport.new_addr(); let rpc_client = RpcClientConfig { - store_addr: Some(client_addr), + store_addr: Some(client_addr.clone()), ..Default::default() }; - - let config = Config { - path: dir.path().join("db"), - rpc_client: rpc_client.clone(), - }; + let config = Config::with_rpc_addr(dir.path().join("db"), client_addr); let (_task, rpc) = executor.block_on(async { let store = Store::create(config).await.unwrap(); let task = executor.spawn(async move { @@ -107,14 +103,10 @@ pub fn get_benchmark(c: &mut Criterion) { let dir = tempfile::tempdir().unwrap(); let (server_addr, client_addr, _dir) = transport.new_addr(); let rpc_client = RpcClientConfig { - store_addr: Some(client_addr), + store_addr: Some(client_addr.clone()), ..Default::default() }; - - let config = Config { - path: dir.path().join("db"), - rpc_client: rpc_client.clone(), - }; + let config = Config::with_rpc_addr(dir.path().join("db"), client_addr); let (_task, rpc) = executor.block_on(async { let store = Store::create(config).await.unwrap(); let task = executor.spawn(async move { diff --git a/iroh-store/benches/store.rs b/iroh-store/benches/store.rs index a70343113b..f5212a8b6c 100644 --- a/iroh-store/benches/store.rs +++ b/iroh-store/benches/store.rs @@ -2,7 +2,6 @@ use std::time::Instant; use cid::multihash::{Code, MultihashDigest}; use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; -use iroh_rpc_client::Config as RpcClientConfig; use iroh_store::{Config, Store}; use tokio::runtime::Runtime; @@ -22,11 +21,7 @@ pub fn put_benchmark(c: &mut Criterion) { |b, (key, value)| { let executor = Runtime::new().unwrap(); let dir = tempfile::tempdir().unwrap(); - let rpc_client = RpcClientConfig::default(); - let config = Config { - path: dir.path().into(), - rpc_client, - }; + let config = Config::new(dir.path().into()); let store = executor.block_on(async { Store::create(config).await.unwrap() }); let store_ref = &store; b.to_async(&executor) @@ -47,11 +42,7 @@ pub fn get_benchmark(c: &mut Criterion) { |b, _| { let executor = Runtime::new().unwrap(); let dir = tempfile::tempdir().unwrap(); - let rpc_client = RpcClientConfig::default(); - let config = Config { - path: dir.path().into(), - rpc_client, - }; + let config = Config::new(dir.path().into()); let store = executor.block_on(async { Store::create(config).await.unwrap() }); let store_ref = &store; let keys = executor.block_on(async { diff --git a/iroh-store/src/config.rs b/iroh-store/src/config.rs index 6c0800f2c8..6771d0c67c 100644 --- a/iroh-store/src/config.rs +++ b/iroh-store/src/config.rs @@ -32,8 +32,7 @@ pub fn config_data_path(arg_path: Option) -> Result { // that's a backwards incompatible change. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] pub struct ServerConfig { - /// The location of the content database. - pub path: PathBuf, + pub store: StoreConfig, pub rpc_client: RpcClientConfig, /// Configuration for metrics export. pub metrics: MetricsConfig, @@ -43,7 +42,7 @@ impl ServerConfig { pub fn new(path: PathBuf) -> Self { let addr = "irpc://0.0.0.0:4402".parse().unwrap(); Self { - path, + store: StoreConfig { path }, rpc_client: RpcClientConfig { store_addr: Some(addr), ..Default::default() @@ -57,6 +56,28 @@ impl Source for ServerConfig { fn clone_into_box(&self) -> Box { Box::new(self.clone()) } + + fn collect(&self) -> Result, ConfigError> { + let mut map: Map = Map::new(); + insert_into_config_map(&mut map, "store", self.store.collect()?); + insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); + insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); + Ok(map) + } +} + +/// Store-specific configuration. +#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] +pub struct StoreConfig { + /// The location of the content database. + pub path: PathBuf, +} + +impl Source for StoreConfig { + fn clone_into_box(&self) -> Box { + Box::new(self.clone()) + } + fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); let path = self @@ -64,9 +85,6 @@ impl Source for ServerConfig { .to_str() .ok_or_else(|| ConfigError::Foreign("No `path` set. Path is required.".into()))?; insert_into_config_map(&mut map, "path", path); - insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); - insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); - Ok(map) } } @@ -79,25 +97,38 @@ impl Source for ServerConfig { #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] pub struct Config { /// The location of the content database. - pub path: PathBuf, + pub store: StoreConfig, pub rpc_client: RpcClientConfig, } impl From for Config { fn from(source: ServerConfig) -> Self { Self { - path: source.path, + store: source.store, rpc_client: source.rpc_client, } } } impl Config { - pub fn new_with_rpc(path: PathBuf, client_addr: StoreAddr) -> Self { + /// Creates a new store config. + /// + /// This config will not have any RpcClientConfig, but that is fine because it is mostly + /// unused: `iroh_rpc::rpc::new` which is used takes the RPC address as a separate + /// argument. Once #672 is merged we can probably remove the `rpc_client` field. + pub fn new(path: PathBuf) -> Self { + Self { + store: StoreConfig { path }, + rpc_client: Default::default(), + } + } + + /// Creates a new store config with the given RPC listen address. + pub fn with_rpc_addr(path: PathBuf, addr: StoreAddr) -> Self { Self { - path, + store: StoreConfig { path }, rpc_client: RpcClientConfig { - store_addr: Some(client_addr), + store_addr: Some(addr), ..Default::default() }, } @@ -112,15 +143,11 @@ impl Source for Config { fn clone_into_box(&self) -> Box { Box::new(self.clone()) } + fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); - let path = self - .path - .to_str() - .ok_or_else(|| ConfigError::Foreign("No `path` set. Path is required.".into()))?; - insert_into_config_map(&mut map, "path", path); + insert_into_config_map(&mut map, "store", self.store.collect()?); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); - Ok(map) } } @@ -137,12 +164,12 @@ mod tests { let mut expect: Map = Map::new(); expect.insert( - "rpc_client".to_string(), - Value::new(None, default.rpc_client.collect().unwrap()), + "store".to_string(), + Value::new(None, default.store.collect().unwrap()), ); expect.insert( - "path".to_string(), - Value::new(None, default.path.to_str().unwrap()), + "rpc_client".to_string(), + Value::new(None, default.rpc_client.collect().unwrap()), ); expect.insert( "metrics".to_string(), diff --git a/iroh-store/src/main.rs b/iroh-store/src/main.rs index 20a53ab333..fb604e315c 100644 --- a/iroh-store/src/main.rs +++ b/iroh-store/src/main.rs @@ -53,11 +53,11 @@ async fn main() -> anyhow::Result<()> { let rpc_addr = config .rpc_addr() .ok_or_else(|| anyhow!("missing store rpc addr"))?; - let store = if config.path.exists() { - info!("Opening store at {}", config.path.display()); + let store = if config.store.path.exists() { + info!("Opening store at {}", config.store.path.display()); Store::open(config).await? } else { - info!("Creating store at {}", config.path.display()); + info!("Creating store at {}", config.store.path.display()); Store::create(config).await? }; diff --git a/iroh-store/src/store.rs b/iroh-store/src/store.rs index 515df9f8a4..118d748a07 100644 --- a/iroh-store/src/store.rs +++ b/iroh-store/src/store.rs @@ -107,7 +107,7 @@ impl Store { let (mut options, cache) = default_options(); options.create_if_missing(true); - let path = config.path.clone(); + let path = config.store.path.clone(); let db = task::spawn_blocking(move || -> Result<_> { let mut db = RocksDb::open(&options, path)?; { @@ -152,7 +152,7 @@ impl Store { options.create_if_missing(false); // TODO: find a way to read existing options - let path = config.path.clone(); + let path = config.store.path.clone(); let (db, next_id) = task::spawn_blocking(move || -> Result<_> { let db = RocksDb::open_cf( &options, @@ -694,10 +694,6 @@ impl<'a> ReadStore<'a> { mod tests { use std::{str::FromStr, sync::Mutex}; - use super::*; - - use iroh_rpc_client::Config as RpcClientConfig; - use cid::multihash::{Code, MultihashDigest}; use libipld::{ cbor::DagCborCodec, @@ -705,18 +701,16 @@ mod tests { Ipld, IpldCodec, }; use tempfile::TempDir; + + use super::*; + const RAW: u64 = 0x55; const DAG_CBOR: u64 = 0x71; #[tokio::test] async fn test_basics() { let dir = tempfile::tempdir().unwrap(); - let rpc_client = RpcClientConfig::default(); - let config = Config { - path: dir.path().into(), - rpc_client, - }; - + let config = Config::new(dir.path().into()); let store = Store::create(config).await.unwrap(); let mut values = Vec::new(); @@ -749,11 +743,7 @@ mod tests { #[tokio::test] async fn test_reopen() { let dir = tempfile::tempdir().unwrap(); - let rpc_client = RpcClientConfig::default(); - let config = Config { - path: dir.path().into(), - rpc_client, - }; + let config = Config::new(dir.path().into()); let store = Store::create(config.clone()).await.unwrap(); @@ -817,12 +807,7 @@ mod tests { async fn test_store() -> anyhow::Result<(Store, TempDir)> { let dir = tempfile::tempdir()?; - let rpc_client = RpcClientConfig::default(); - let config = Config { - path: dir.path().into(), - rpc_client, - }; - + let config = Config::new(dir.path().into()); let store = Store::create(config).await?; Ok((store, dir)) } From 46ae1dab377285aead79822f96b9e63b03703853 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 16:17:08 +0100 Subject: [PATCH 05/11] p2p config split-ish --- iroh-embed/src/p2p.rs | 2 +- iroh-one/src/config.rs | 4 +-- iroh-one/src/mem_p2p.rs | 2 +- iroh-p2p/src/config.rs | 69 +++++++++++++++++++++++--------------- iroh-p2p/src/main.rs | 2 +- iroh-share/src/p2p_node.rs | 6 ++-- iroh-store/src/config.rs | 2 -- 7 files changed, 51 insertions(+), 36 deletions(-) diff --git a/iroh-embed/src/p2p.rs b/iroh-embed/src/p2p.rs index a35b2f12ee..0c826dec5e 100644 --- a/iroh-embed/src/p2p.rs +++ b/iroh-embed/src/p2p.rs @@ -46,7 +46,7 @@ impl P2pService { config.rpc_client.store_addr = Some(store_service); config.libp2p = libp2p_config; - config.key_store_path = key_store_path; + config.p2p.key_store_path = key_store_path; let task = mem_p2p::start(addr.clone(), config).await?; Ok(Self { task, addr }) } diff --git a/iroh-one/src/config.rs b/iroh-one/src/config.rs index 7028487eb8..2983d55136 100644 --- a/iroh-one/src/config.rs +++ b/iroh-one/src/config.rs @@ -3,7 +3,7 @@ use axum::http::header::*; use config::{ConfigError, Map, Source, Value}; use iroh_metrics::config::Config as MetricsConfig; -use iroh_p2p::Libp2pConfig; +use iroh_p2p::{Libp2pConfig, P2pConfig}; use iroh_rpc_client::Config as RpcClientConfig; use iroh_store::config::config_data_path; use iroh_util::insert_into_config_map; @@ -117,9 +117,9 @@ fn default_store_config( fn default_p2p_config(ipfsd: RpcClientConfig, key_store_path: PathBuf) -> iroh_p2p::config::Config { iroh_p2p::config::Config { + p2p: P2pConfig { key_store_path }, libp2p: Libp2pConfig::default(), rpc_client: ipfsd, - key_store_path, } } diff --git a/iroh-one/src/mem_p2p.rs b/iroh-one/src/mem_p2p.rs index caf8e9a77e..f998d45575 100644 --- a/iroh-one/src/mem_p2p.rs +++ b/iroh-one/src/mem_p2p.rs @@ -8,7 +8,7 @@ use tracing::error; /// Starts a new p2p node, using the given mem rpc channel. pub async fn start(rpc_addr: P2pAddr, config: Config) -> anyhow::Result> { - let kc = Keychain::::new(config.key_store_path.clone()).await?; + let kc = Keychain::::new(config.p2p.key_store_path.clone()).await?; let mut p2p = Node::new(config, rpc_addr, kc).await?; diff --git a/iroh-p2p/src/config.rs b/iroh-p2p/src/config.rs index e360a42dbc..fa31e6b0dc 100644 --- a/iroh-p2p/src/config.rs +++ b/iroh-p2p/src/config.rs @@ -35,20 +35,12 @@ pub const DEFAULT_BOOTSTRAP: &[&str] = &[ /// This is the configuration which the p2p server binary needs to run. It is a superset /// from the configuration needed by the p2p service, which can also run integrated into /// another binary like in iroh-one, iroh-share or iroh-embed. -// TODO: I'd prefer to include [`Config`] under a `p2p` field like iroh-one does. But -// that's a backwards incompatible change for the config file. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] pub struct ServerConfig { + pub p2p: P2pConfig, pub libp2p: Libp2pConfig, pub rpc_client: RpcClientConfig, pub metrics: MetricsConfig, - /// Directory where cryptographic keys are stored. - /// - /// The p2p node needs to have an identity consisting of a cryptographic key pair. As - /// it is useful to have the same identity across restarts this is stored on disk in a - /// format compatible with how ssh stores keys. This points to a directory where these - /// keypairs are stored. - pub key_store_path: PathBuf, } impl ServerConfig { @@ -60,10 +52,10 @@ impl ServerConfig { impl Default for ServerConfig { fn default() -> Self { Self { + p2p: Default::default(), libp2p: Default::default(), rpc_client: RpcClientConfig::default_network(), metrics: Default::default(), - key_store_path: iroh_data_root().unwrap(), } } } @@ -75,10 +67,42 @@ impl Source for ServerConfig { fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); - + insert_into_config_map(&mut map, "p2p", self.p2p.collect()?); insert_into_config_map(&mut map, "libp2p", self.libp2p.collect()?); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); + Ok(map) + } +} + +/// Configuration specific to the p2p service. +#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] +pub struct P2pConfig { + /// Directory where cryptographic keys are stored. + /// + /// The p2p node needs to have an identity consisting of a cryptographic key pair. As + /// it is useful to have the same identity across restarts this is stored on disk in a + /// format compatible with how ssh stores keys. This points to a directory where these + /// keypairs are stored. + pub key_store_path: PathBuf, +} + +impl Default for P2pConfig { + fn default() -> Self { + Self { + key_store_path: iroh_data_root().unwrap(), + } + } +} + +impl Source for P2pConfig { + fn clone_into_box(&self) -> Box { + Box::new(self.clone()) + } + + fn collect(&self) -> Result, ConfigError> { + let mut map: Map = Map::new(); + insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); Ok(map) } @@ -121,23 +145,17 @@ pub struct Libp2pConfig { /// Configuration for the [`iroh-p2p`] node. #[derive(PartialEq, Debug, Clone, Deserialize, Serialize)] pub struct Config { + pub p2p: P2pConfig, pub libp2p: Libp2pConfig, pub rpc_client: RpcClientConfig, - /// Directory where cryptographic keys are stored. - /// - /// The p2p node needs to have an identity consisting of a cryptographic key pair. As - /// it is useful to have the same identity across restarts this is stored on disk in a - /// format compatible with how ssh stores keys. This points to a directory where these - /// keypairs are stored. - pub key_store_path: PathBuf, } impl From for Config { fn from(source: ServerConfig) -> Self { Self { + p2p: source.p2p, libp2p: source.libp2p, rpc_client: source.rpc_client, - key_store_path: source.key_store_path, } } } @@ -212,10 +230,9 @@ impl Source for Config { fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); - + insert_into_config_map(&mut map, "p2p", self.p2p.collect()?); insert_into_config_map(&mut map, "libp2p", self.libp2p.collect()?); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); - insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); Ok(map) } } @@ -256,22 +273,20 @@ impl Default for Libp2pConfig { impl Config { pub fn default_with_rpc(client_addr: P2pAddr) -> Self { Self { - libp2p: Libp2pConfig::default(), + p2p: Default::default(), + libp2p: Default::default(), rpc_client: RpcClientConfig { p2p_addr: Some(client_addr), ..Default::default() }, - key_store_path: iroh_data_root().unwrap(), } } pub fn default_network() -> Self { - let rpc_client = RpcClientConfig::default_network(); - Self { + p2p: Default::default(), libp2p: Libp2pConfig::default(), - rpc_client, - key_store_path: iroh_data_root().unwrap(), + rpc_client: RpcClientConfig::default_network(), } } diff --git a/iroh-p2p/src/main.rs b/iroh-p2p/src/main.rs index f341272b47..41319075bf 100644 --- a/iroh-p2p/src/main.rs +++ b/iroh-p2p/src/main.rs @@ -56,7 +56,7 @@ fn main() -> Result<()> { } } - let kc = Keychain::::new(network_config.key_store_path.clone()).await?; + let kc = Keychain::::new(network_config.p2p.key_store_path.clone()).await?; let network_config = Config::from(network_config); let rpc_addr = network_config .rpc_addr() diff --git a/iroh-share/src/p2p_node.rs b/iroh-share/src/p2p_node.rs index dab5b32a45..eb8d493e9b 100644 --- a/iroh-share/src/p2p_node.rs +++ b/iroh-share/src/p2p_node.rs @@ -3,7 +3,7 @@ use std::{collections::HashSet, path::Path, sync::Arc}; use anyhow::{ensure, Result}; use async_trait::async_trait; use cid::Cid; -use iroh_p2p::{config, Keychain, MemoryStorage, NetworkEvent, Node}; +use iroh_p2p::{config, Keychain, MemoryStorage, NetworkEvent, Node, P2pConfig}; use iroh_resolver::resolver::Resolver; use iroh_rpc_client::Client; use iroh_rpc_types::Addr; @@ -161,9 +161,11 @@ impl P2pNode { libp2p_config.max_conns_in = 8; libp2p_config.max_conns_out = 8; let config = config::Config { + p2p: P2pConfig { + key_store_path: db_path.parent().unwrap().to_path_buf(), + }, libp2p: libp2p_config, rpc_client: rpc_p2p_client_config.clone(), - key_store_path: db_path.parent().unwrap().to_path_buf(), }; let rpc = Client::new(rpc_p2p_client_config).await?; diff --git a/iroh-store/src/config.rs b/iroh-store/src/config.rs index 6771d0c67c..3d73be13f1 100644 --- a/iroh-store/src/config.rs +++ b/iroh-store/src/config.rs @@ -28,8 +28,6 @@ pub fn config_data_path(arg_path: Option) -> Result { /// This is the configuration which the store server binary needs to run. This is a /// superset from the configuration needed by the store service, which can also run /// integrated into another binary like in iroh-one, iroh-share or iroh-embed. -// TODO: I'd prefer to include [`Config`] under the `store` field like iroh-one does. But -// that's a backwards incompatible change. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] pub struct ServerConfig { pub store: StoreConfig, From b06c476beb68b1a8f65d77405de62db2a2d33942 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 17:50:39 +0100 Subject: [PATCH 06/11] gateway, but without the stupid intermediate struct lets remove that struct from the other places too --- iroh-gateway/Cargo.toml | 1 + iroh-gateway/src/config.rs | 150 ++++++++++++------------------------- iroh-gateway/src/main.rs | 4 +- 3 files changed, 52 insertions(+), 103 deletions(-) diff --git a/iroh-gateway/Cargo.toml b/iroh-gateway/Cargo.toml index 8b59368a90..69f3c5a569 100644 --- a/iroh-gateway/Cargo.toml +++ b/iroh-gateway/Cargo.toml @@ -61,6 +61,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] } tracing.workspace = true url.workspace = true urlencoding.workspace = true +testdir.workspace = true [dev-dependencies] iroh-store.workspace = true diff --git a/iroh-gateway/src/config.rs b/iroh-gateway/src/config.rs index f1bc096669..0c6819e372 100644 --- a/iroh-gateway/src/config.rs +++ b/iroh-gateway/src/config.rs @@ -26,74 +26,21 @@ pub const DEFAULT_PORT: u16 = 9050; /// This is the configuration which the gateway server binary needs to run. This is a /// superset from the configuration needed by the gateway service, which can also run /// integrated into another binary like iroh-one, iroh-share or iroh-embed. -// TODO: I'd prefer to include [`Config`] under the `gateway` field liek iroh-one does. But -// that's a backwards incompatible change. -// TODO: If this was moved into main.rs it would not need to be public. Our binary is build +// NOTE: If this was moved into main.rs it would not need to be public. Our binary is build // as being outside of the lib crate, hence here it needs to be public. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)] pub struct ServerConfig { - /// Pretty URL to redirect to - #[serde(default = "String::new")] - pub public_url_base: String, - /// default port to listen on - pub port: u16, - /// flag to toggle whether the gateway should use denylist on requests - pub use_denylist: bool, - /// URL of gateways to be used by the racing resolver. - /// Strings can either be urls or subdomain gateway roots - /// values without https:// prefix are treated as subdomain gateways (eg: dweb.link) - /// values with are treated as IPFS path gateways (eg: ) - pub http_resolvers: Option>, - /// Separate resolvers for particular TLDs - #[serde(default = "DnsResolverConfig::default")] - pub dns_resolver: DnsResolverConfig, - /// Indexer node to use. - pub indexer_endpoint: Option, - /// rpc addresses for the gateway & addresses for the rpc client to dial - pub rpc_client: RpcClientConfig, - /// metrics configuration + /// Configuration of the gateway service. + pub gateway: Config, + /// Metrics configuration. pub metrics: MetricsConfig, - // NOTE: for toml to serialize properly, the "table" values must be serialized at the end, and - // so much come at the end of the `Config` struct - /// set of user provided headers to attach to all responses - #[serde(with = "http_serde::header_map")] - pub headers: HeaderMap, - /// Redirects to subdomains for path requests - #[serde(default)] - pub redirect_to_subdomain: bool, } impl ServerConfig { pub fn new(port: u16, rpc_client: RpcClientConfig) -> Self { Self { - public_url_base: String::new(), - headers: HeaderMap::new(), - port, - rpc_client, - http_resolvers: None, - dns_resolver: DnsResolverConfig::default(), - indexer_endpoint: None, + gateway: Config::new(port, rpc_client), metrics: MetricsConfig::default(), - use_denylist: false, - redirect_to_subdomain: false, - } - } -} - -impl Default for ServerConfig { - fn default() -> Self { - let inner = Config::default(); - Self { - public_url_base: inner.public_url_base, - port: inner.port, - use_denylist: inner.use_denylist, - http_resolvers: inner.http_resolvers, - dns_resolver: inner.dns_resolver, - indexer_endpoint: inner.indexer_endpoint, - rpc_client: inner.rpc_client, - metrics: Default::default(), - headers: inner.headers, - redirect_to_subdomain: inner.redirect_to_subdomain, } } } @@ -104,24 +51,9 @@ impl Source for ServerConfig { } fn collect(&self) -> Result, ConfigError> { - let rpc_client = self.rpc_client.collect()?; let mut map: Map = Map::new(); - insert_into_config_map(&mut map, "public_url_base", self.public_url_base.clone()); - insert_into_config_map(&mut map, "use_denylist", self.use_denylist); - // Some issue between deserializing u64 & u16, converting this to - // an signed int fixes the issue - insert_into_config_map(&mut map, "port", self.port as i32); - insert_into_config_map(&mut map, "headers", collect_headers(&self.headers)?); - insert_into_config_map(&mut map, "rpc_client", rpc_client); - let metrics = self.metrics.collect()?; - insert_into_config_map(&mut map, "metrics", metrics); - - if let Some(http_resolvers) = &self.http_resolvers { - insert_into_config_map(&mut map, "http_resolvers", http_resolvers.clone()); - } - if let Some(indexer_endpoint) = &self.indexer_endpoint { - insert_into_config_map(&mut map, "indexer_endpoint", indexer_endpoint.clone()); - } + insert_into_config_map(&mut map, "gateway", self.gateway.collect()?); + insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); Ok(map) } } @@ -184,17 +116,7 @@ impl Config { impl From for Config { fn from(source: ServerConfig) -> Self { - Self { - public_url_base: source.public_url_base, - port: source.port, - use_denylist: source.use_denylist, - http_resolvers: source.http_resolvers, - dns_resolver: source.dns_resolver, - indexer_endpoint: source.indexer_endpoint, - rpc_client: source.rpc_client, - headers: source.headers, - redirect_to_subdomain: source.redirect_to_subdomain, - } + source.gateway } } @@ -324,6 +246,10 @@ fn collect_headers(headers: &HeaderMap) -> Result, ConfigErro #[cfg(test)] mod tests { + use std::collections::HashMap; + + use testdir::testdir; + use super::*; use config::Config as ConfigBuilder; @@ -345,22 +271,9 @@ mod tests { fn test_collect() { let default = ServerConfig::default(); let mut expect: Map = Map::new(); - expect.insert( - "public_url_base".to_string(), - Value::new(None, default.public_url_base.clone()), - ); - expect.insert("port".to_string(), Value::new(None, default.port as i64)); - expect.insert( - "use_denylist".to_string(), - Value::new(None, default.use_denylist), - ); - expect.insert( - "headers".to_string(), - Value::new(None, collect_headers(&default.headers).unwrap()), - ); expect.insert( "rpc_client".to_string(), - Value::new(None, default.rpc_client.collect().unwrap()), + Value::new(None, default.gateway.collect().unwrap()), ); expect.insert( "metrics".to_string(), @@ -416,4 +329,39 @@ mod tests { assert_eq!(expect, got); } + + #[test] + fn test_toml_file() { + let dir = testdir!(); + let cfg_file = dir.join("config.toml"); + std::fs::write( + &cfg_file, + r#" + [gateway] + public_url_base = "http://example.com/base/" + port = 2001 + [gateway.rpc_client] + gateway_addr = "irpc://127.0.0.42:1234" + "#, + ) + .unwrap(); + let sources = [Some(cfg_file.as_path())]; + let cfg = iroh_util::make_config( + ServerConfig::default(), + &sources, + ENV_PREFIX, + HashMap::<&str, String>::new(), + ) + .unwrap(); + dbg!(&cfg); + + assert_eq!(cfg.gateway.public_url_base, "http://example.com/base/"); + assert_eq!(cfg.gateway.port, 2001); + assert_eq!( + cfg.gateway.rpc_client.gateway_addr.unwrap(), + "irpc://127.0.0.42:1234".parse().unwrap(), + ); + + panic!("boom"); + } } diff --git a/iroh-gateway/src/main.rs b/iroh-gateway/src/main.rs index 2574ad313c..5e6fc7af0f 100644 --- a/iroh-gateway/src/main.rs +++ b/iroh-gateway/src/main.rs @@ -39,8 +39,8 @@ async fn main() -> Result<()> { println!("{config:#?}"); let metrics_config = config.metrics.clone(); - let dns_resolver_config = config.dns_resolver.clone(); - let bad_bits = match config.use_denylist { + let dns_resolver_config = config.gateway.dns_resolver.clone(); + let bad_bits = match config.gateway.use_denylist { true => Arc::new(Some(RwLock::new(BadBits::new()))), false => Arc::new(None), }; From d11e74a3da802cbda543db787c434dcc4cc128cf Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 18:28:20 +0100 Subject: [PATCH 07/11] more sane approach for p2p too --- iroh-embed/src/p2p.rs | 2 +- iroh-one/src/config.rs | 4 +- iroh-one/src/mem_p2p.rs | 2 +- iroh-p2p/src/config.rs | 81 ++++++++++---------------------------- iroh-share/src/p2p_node.rs | 8 ++-- 5 files changed, 27 insertions(+), 70 deletions(-) diff --git a/iroh-embed/src/p2p.rs b/iroh-embed/src/p2p.rs index 0c826dec5e..a35b2f12ee 100644 --- a/iroh-embed/src/p2p.rs +++ b/iroh-embed/src/p2p.rs @@ -46,7 +46,7 @@ impl P2pService { config.rpc_client.store_addr = Some(store_service); config.libp2p = libp2p_config; - config.p2p.key_store_path = key_store_path; + config.key_store_path = key_store_path; let task = mem_p2p::start(addr.clone(), config).await?; Ok(Self { task, addr }) } diff --git a/iroh-one/src/config.rs b/iroh-one/src/config.rs index 2983d55136..3e1f0583a4 100644 --- a/iroh-one/src/config.rs +++ b/iroh-one/src/config.rs @@ -3,7 +3,7 @@ use axum::http::header::*; use config::{ConfigError, Map, Source, Value}; use iroh_metrics::config::Config as MetricsConfig; -use iroh_p2p::{Libp2pConfig, P2pConfig}; +use iroh_p2p::Libp2pConfig; use iroh_rpc_client::Config as RpcClientConfig; use iroh_store::config::config_data_path; use iroh_util::insert_into_config_map; @@ -117,7 +117,7 @@ fn default_store_config( fn default_p2p_config(ipfsd: RpcClientConfig, key_store_path: PathBuf) -> iroh_p2p::config::Config { iroh_p2p::config::Config { - p2p: P2pConfig { key_store_path }, + key_store_path, libp2p: Libp2pConfig::default(), rpc_client: ipfsd, } diff --git a/iroh-one/src/mem_p2p.rs b/iroh-one/src/mem_p2p.rs index f998d45575..caf8e9a77e 100644 --- a/iroh-one/src/mem_p2p.rs +++ b/iroh-one/src/mem_p2p.rs @@ -8,7 +8,7 @@ use tracing::error; /// Starts a new p2p node, using the given mem rpc channel. pub async fn start(rpc_addr: P2pAddr, config: Config) -> anyhow::Result> { - let kc = Keychain::::new(config.p2p.key_store_path.clone()).await?; + let kc = Keychain::::new(config.key_store_path.clone()).await?; let mut p2p = Node::new(config, rpc_addr, kc).await?; diff --git a/iroh-p2p/src/config.rs b/iroh-p2p/src/config.rs index fa31e6b0dc..10301f6114 100644 --- a/iroh-p2p/src/config.rs +++ b/iroh-p2p/src/config.rs @@ -37,9 +37,7 @@ pub const DEFAULT_BOOTSTRAP: &[&str] = &[ /// another binary like in iroh-one, iroh-share or iroh-embed. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] pub struct ServerConfig { - pub p2p: P2pConfig, - pub libp2p: Libp2pConfig, - pub rpc_client: RpcClientConfig, + pub p2p: Config, pub metrics: MetricsConfig, } @@ -52,9 +50,7 @@ impl ServerConfig { impl Default for ServerConfig { fn default() -> Self { Self { - p2p: Default::default(), - libp2p: Default::default(), - rpc_client: RpcClientConfig::default_network(), + p2p: Config::default_network(), metrics: Default::default(), } } @@ -68,46 +64,11 @@ impl Source for ServerConfig { fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); insert_into_config_map(&mut map, "p2p", self.p2p.collect()?); - insert_into_config_map(&mut map, "libp2p", self.libp2p.collect()?); - insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); Ok(map) } } -/// Configuration specific to the p2p service. -#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] -pub struct P2pConfig { - /// Directory where cryptographic keys are stored. - /// - /// The p2p node needs to have an identity consisting of a cryptographic key pair. As - /// it is useful to have the same identity across restarts this is stored on disk in a - /// format compatible with how ssh stores keys. This points to a directory where these - /// keypairs are stored. - pub key_store_path: PathBuf, -} - -impl Default for P2pConfig { - fn default() -> Self { - Self { - key_store_path: iroh_data_root().unwrap(), - } - } -} - -impl Source for P2pConfig { - fn clone_into_box(&self) -> Box { - Box::new(self.clone()) - } - - fn collect(&self) -> Result, ConfigError> { - let mut map: Map = Map::new(); - - insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); - Ok(map) - } -} - /// Libp2p config for the node. #[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)] #[non_exhaustive] @@ -145,18 +106,22 @@ pub struct Libp2pConfig { /// Configuration for the [`iroh-p2p`] node. #[derive(PartialEq, Debug, Clone, Deserialize, Serialize)] pub struct Config { - pub p2p: P2pConfig, + /// Directory where cryptographic keys are stored. + /// + /// The p2p node needs to have an identity consisting of a cryptographic key pair. As + /// it is useful to have the same identity across restarts this is stored on disk in a + /// format compatible with how ssh stores keys. This points to a directory where these + /// keypairs are stored. + pub key_store_path: PathBuf, + /// Configuration for libp2p. pub libp2p: Libp2pConfig, + /// Configuration of RPC to other iroh services. pub rpc_client: RpcClientConfig, } impl From for Config { fn from(source: ServerConfig) -> Self { - Self { - p2p: source.p2p, - libp2p: source.libp2p, - rpc_client: source.rpc_client, - } + source.p2p } } @@ -230,7 +195,7 @@ impl Source for Config { fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); - insert_into_config_map(&mut map, "p2p", self.p2p.collect()?); + insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); insert_into_config_map(&mut map, "libp2p", self.libp2p.collect()?); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); Ok(map) @@ -273,7 +238,7 @@ impl Default for Libp2pConfig { impl Config { pub fn default_with_rpc(client_addr: P2pAddr) -> Self { Self { - p2p: Default::default(), + key_store_path: iroh_data_root().unwrap(), libp2p: Default::default(), rpc_client: RpcClientConfig { p2p_addr: Some(client_addr), @@ -284,7 +249,7 @@ impl Config { pub fn default_network() -> Self { Self { - p2p: Default::default(), + key_store_path: iroh_data_root().unwrap(), libp2p: Libp2pConfig::default(), rpc_client: RpcClientConfig::default_network(), } @@ -304,6 +269,7 @@ mod tests { fn test_collect() { let default = ServerConfig::default(); let bootstrap_peers: Vec = default + .p2p .libp2p .bootstrap_peers .iter() @@ -311,6 +277,7 @@ mod tests { .collect(); let addrs: Vec = default + .p2p .libp2p .listening_multiaddrs .iter() @@ -319,21 +286,13 @@ mod tests { let mut expect: Map = Map::new(); expect.insert( - "libp2p".to_string(), - Value::new(None, default.libp2p.collect().unwrap()), - ); - expect.insert( - "rpc_client".to_string(), - Value::new(None, default.rpc_client.collect().unwrap()), + "p2p".to_string(), + Value::new(None, default.p2p.collect().unwrap()), ); expect.insert( "metrics".to_string(), Value::new(None, default.metrics.collect().unwrap()), ); - expect.insert( - "key_store_path".to_string(), - Value::new(None, iroh_data_root().unwrap().to_str()), - ); let got = default.collect().unwrap(); for key in got.keys() { @@ -344,7 +303,7 @@ mod tests { // libp2p let mut expect: Map = Map::new(); - let default = &default.libp2p; + let default = &default.p2p.libp2p; // see `Source` implementation for why we need to cast this as a signed int expect.insert( diff --git a/iroh-share/src/p2p_node.rs b/iroh-share/src/p2p_node.rs index eb8d493e9b..a842189e29 100644 --- a/iroh-share/src/p2p_node.rs +++ b/iroh-share/src/p2p_node.rs @@ -3,7 +3,7 @@ use std::{collections::HashSet, path::Path, sync::Arc}; use anyhow::{ensure, Result}; use async_trait::async_trait; use cid::Cid; -use iroh_p2p::{config, Keychain, MemoryStorage, NetworkEvent, Node, P2pConfig}; +use iroh_p2p::{config, Config, Keychain, MemoryStorage, NetworkEvent, Node}; use iroh_resolver::resolver::Resolver; use iroh_rpc_client::Client; use iroh_rpc_types::Addr; @@ -160,10 +160,8 @@ impl P2pNode { libp2p_config.relay_server = false; libp2p_config.max_conns_in = 8; libp2p_config.max_conns_out = 8; - let config = config::Config { - p2p: P2pConfig { - key_store_path: db_path.parent().unwrap().to_path_buf(), - }, + let config = Config { + key_store_path: db_path.parent().unwrap().to_path_buf(), libp2p: libp2p_config, rpc_client: rpc_p2p_client_config.clone(), }; From 14b513b174fb973504fb17657de80dd06d967a6a Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 18:37:04 +0100 Subject: [PATCH 08/11] and store, let's see what this looks like --- iroh-one/src/config.rs | 2 +- iroh-one/src/mem_store.rs | 6 ++--- iroh-share/src/p2p_node.rs | 7 ++--- iroh-store/src/config.rs | 55 +++++++++----------------------------- iroh-store/src/main.rs | 6 ++--- iroh-store/src/store.rs | 4 +-- 6 files changed, 23 insertions(+), 57 deletions(-) diff --git a/iroh-one/src/config.rs b/iroh-one/src/config.rs index 3e1f0583a4..caf875897f 100644 --- a/iroh-one/src/config.rs +++ b/iroh-one/src/config.rs @@ -110,7 +110,7 @@ fn default_store_config( ) -> Result { let path = config_data_path(store_path)?; Ok(iroh_store::config::Config { - store: iroh_store::config::StoreConfig { path }, + path, rpc_client: ipfsd, }) } diff --git a/iroh-one/src/mem_store.rs b/iroh-one/src/mem_store.rs index 72e07e8c80..c613d2de2b 100644 --- a/iroh-one/src/mem_store.rs +++ b/iroh-one/src/mem_store.rs @@ -10,15 +10,15 @@ pub async fn start(rpc_addr: StoreAddr, config: Config) -> anyhow::Result) -> Result { /// integrated into another binary like in iroh-one, iroh-share or iroh-embed. #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] pub struct ServerConfig { - pub store: StoreConfig, - pub rpc_client: RpcClientConfig, + /// Configuration of the store service. + pub store: Config, /// Configuration for metrics export. pub metrics: MetricsConfig, } @@ -40,11 +40,7 @@ impl ServerConfig { pub fn new(path: PathBuf) -> Self { let addr = "irpc://0.0.0.0:4402".parse().unwrap(); Self { - store: StoreConfig { path }, - rpc_client: RpcClientConfig { - store_addr: Some(addr), - ..Default::default() - }, + store: Config::with_rpc_addr(path, addr), metrics: Default::default(), } } @@ -58,35 +54,11 @@ impl Source for ServerConfig { fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); insert_into_config_map(&mut map, "store", self.store.collect()?); - insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); insert_into_config_map(&mut map, "metrics", self.metrics.collect()?); Ok(map) } } -/// Store-specific configuration. -#[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] -pub struct StoreConfig { - /// The location of the content database. - pub path: PathBuf, -} - -impl Source for StoreConfig { - fn clone_into_box(&self) -> Box { - Box::new(self.clone()) - } - - fn collect(&self) -> Result, ConfigError> { - let mut map: Map = Map::new(); - let path = self - .path - .to_str() - .ok_or_else(|| ConfigError::Foreign("No `path` set. Path is required.".into()))?; - insert_into_config_map(&mut map, "path", path); - Ok(map) - } -} - /// The configuration for the store service. /// /// As opposed to the [`ServerConfig`] this is only the configuration needed to run the @@ -95,16 +67,13 @@ impl Source for StoreConfig { #[derive(PartialEq, Debug, Deserialize, Serialize, Clone)] pub struct Config { /// The location of the content database. - pub store: StoreConfig, + pub path: PathBuf, pub rpc_client: RpcClientConfig, } impl From for Config { fn from(source: ServerConfig) -> Self { - Self { - store: source.store, - rpc_client: source.rpc_client, - } + source.store } } @@ -116,7 +85,7 @@ impl Config { /// argument. Once #672 is merged we can probably remove the `rpc_client` field. pub fn new(path: PathBuf) -> Self { Self { - store: StoreConfig { path }, + path, rpc_client: Default::default(), } } @@ -124,7 +93,7 @@ impl Config { /// Creates a new store config with the given RPC listen address. pub fn with_rpc_addr(path: PathBuf, addr: StoreAddr) -> Self { Self { - store: StoreConfig { path }, + path, rpc_client: RpcClientConfig { store_addr: Some(addr), ..Default::default() @@ -144,7 +113,11 @@ impl Source for Config { fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); - insert_into_config_map(&mut map, "store", self.store.collect()?); + let path = self + .path + .to_str() + .ok_or_else(|| ConfigError::Foreign("No `path` set. Path is required.".into()))?; + insert_into_config_map(&mut map, "path", path); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); Ok(map) } @@ -165,10 +138,6 @@ mod tests { "store".to_string(), Value::new(None, default.store.collect().unwrap()), ); - expect.insert( - "rpc_client".to_string(), - Value::new(None, default.rpc_client.collect().unwrap()), - ); expect.insert( "metrics".to_string(), Value::new(None, default.metrics.collect().unwrap()), diff --git a/iroh-store/src/main.rs b/iroh-store/src/main.rs index fb604e315c..20a53ab333 100644 --- a/iroh-store/src/main.rs +++ b/iroh-store/src/main.rs @@ -53,11 +53,11 @@ async fn main() -> anyhow::Result<()> { let rpc_addr = config .rpc_addr() .ok_or_else(|| anyhow!("missing store rpc addr"))?; - let store = if config.store.path.exists() { - info!("Opening store at {}", config.store.path.display()); + let store = if config.path.exists() { + info!("Opening store at {}", config.path.display()); Store::open(config).await? } else { - info!("Creating store at {}", config.store.path.display()); + info!("Creating store at {}", config.path.display()); Store::create(config).await? }; diff --git a/iroh-store/src/store.rs b/iroh-store/src/store.rs index 118d748a07..874546ab49 100644 --- a/iroh-store/src/store.rs +++ b/iroh-store/src/store.rs @@ -107,7 +107,7 @@ impl Store { let (mut options, cache) = default_options(); options.create_if_missing(true); - let path = config.store.path.clone(); + let path = config.path.clone(); let db = task::spawn_blocking(move || -> Result<_> { let mut db = RocksDb::open(&options, path)?; { @@ -152,7 +152,7 @@ impl Store { options.create_if_missing(false); // TODO: find a way to read existing options - let path = config.store.path.clone(); + let path = config.path.clone(); let (db, next_id) = task::spawn_blocking(move || -> Result<_> { let db = RocksDb::open_cf( &options, From 2b08d3f95b9d5a015f3437144692032f13ec9f21 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 18:40:34 +0100 Subject: [PATCH 09/11] maybe don't explode? --- iroh-gateway/src/config.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/iroh-gateway/src/config.rs b/iroh-gateway/src/config.rs index 0c6819e372..9bf4105744 100644 --- a/iroh-gateway/src/config.rs +++ b/iroh-gateway/src/config.rs @@ -361,7 +361,5 @@ mod tests { cfg.gateway.rpc_client.gateway_addr.unwrap(), "irpc://127.0.0.42:1234".parse().unwrap(), ); - - panic!("boom"); } } From 7eddc0be044fab90d6b16d55c010a629b98657d3 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 18:50:52 +0100 Subject: [PATCH 10/11] needless diff --- iroh-p2p/src/config.rs | 20 +++++++++++--------- iroh-p2p/src/main.rs | 2 +- iroh-share/src/p2p_node.rs | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/iroh-p2p/src/config.rs b/iroh-p2p/src/config.rs index 10301f6114..926ad3d133 100644 --- a/iroh-p2p/src/config.rs +++ b/iroh-p2p/src/config.rs @@ -106,6 +106,10 @@ pub struct Libp2pConfig { /// Configuration for the [`iroh-p2p`] node. #[derive(PartialEq, Debug, Clone, Deserialize, Serialize)] pub struct Config { + /// Configuration for libp2p. + pub libp2p: Libp2pConfig, + /// Configuration of RPC to other iroh services. + pub rpc_client: RpcClientConfig, /// Directory where cryptographic keys are stored. /// /// The p2p node needs to have an identity consisting of a cryptographic key pair. As @@ -113,10 +117,6 @@ pub struct Config { /// format compatible with how ssh stores keys. This points to a directory where these /// keypairs are stored. pub key_store_path: PathBuf, - /// Configuration for libp2p. - pub libp2p: Libp2pConfig, - /// Configuration of RPC to other iroh services. - pub rpc_client: RpcClientConfig, } impl From for Config { @@ -195,9 +195,9 @@ impl Source for Config { fn collect(&self) -> Result, ConfigError> { let mut map: Map = Map::new(); - insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); insert_into_config_map(&mut map, "libp2p", self.libp2p.collect()?); insert_into_config_map(&mut map, "rpc_client", self.rpc_client.collect()?); + insert_into_config_map(&mut map, "key_store_path", self.key_store_path.to_str()); Ok(map) } } @@ -238,20 +238,22 @@ impl Default for Libp2pConfig { impl Config { pub fn default_with_rpc(client_addr: P2pAddr) -> Self { Self { - key_store_path: iroh_data_root().unwrap(), - libp2p: Default::default(), + libp2p: Libp2pConfig::default(), rpc_client: RpcClientConfig { p2p_addr: Some(client_addr), ..Default::default() }, + key_store_path: iroh_data_root().unwrap(), } } pub fn default_network() -> Self { + let rpc_client = RpcClientConfig::default_network(); + Self { - key_store_path: iroh_data_root().unwrap(), libp2p: Libp2pConfig::default(), - rpc_client: RpcClientConfig::default_network(), + rpc_client, + key_store_path: iroh_data_root().unwrap(), } } diff --git a/iroh-p2p/src/main.rs b/iroh-p2p/src/main.rs index 41319075bf..61426ae4ba 100644 --- a/iroh-p2p/src/main.rs +++ b/iroh-p2p/src/main.rs @@ -56,8 +56,8 @@ fn main() -> Result<()> { } } - let kc = Keychain::::new(network_config.p2p.key_store_path.clone()).await?; let network_config = Config::from(network_config); + let kc = Keychain::::new(network_config.key_store_path.clone()).await?; let rpc_addr = network_config .rpc_addr() .ok_or_else(|| anyhow!("missing p2p rpc addr"))?; diff --git a/iroh-share/src/p2p_node.rs b/iroh-share/src/p2p_node.rs index d32c8dc4e1..ec22d7b403 100644 --- a/iroh-share/src/p2p_node.rs +++ b/iroh-share/src/p2p_node.rs @@ -160,9 +160,9 @@ impl P2pNode { libp2p_config.max_conns_in = 8; libp2p_config.max_conns_out = 8; let config = Config { - key_store_path: db_path.parent().unwrap().to_path_buf(), libp2p: libp2p_config, rpc_client: rpc_p2p_client_config.clone(), + key_store_path: db_path.parent().unwrap().to_path_buf(), }; let rpc = Client::new(rpc_p2p_client_config).await?; From 4bae9f6c872dce5ab064c51534c7765b49a8e3b6 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Wed, 4 Jan 2023 19:04:28 +0100 Subject: [PATCH 11/11] fix test --- iroh-gateway/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iroh-gateway/src/config.rs b/iroh-gateway/src/config.rs index 9bf4105744..f84f593858 100644 --- a/iroh-gateway/src/config.rs +++ b/iroh-gateway/src/config.rs @@ -272,7 +272,7 @@ mod tests { let default = ServerConfig::default(); let mut expect: Map = Map::new(); expect.insert( - "rpc_client".to_string(), + "gateway".to_string(), Value::new(None, default.gateway.collect().unwrap()), ); expect.insert(