Skip to content

Commit f174c8e

Browse files
rklaehndignifiedquiredivagant-martian
authored
refactor(iroh)!: Extract net and node rpc (#2927)
## Description Introduce a new crate iroh-node-util. This contains generic utilities that are needed to build an iroh node, as well as the rpc protocol and rpc client to remote control an arbitrary iroh-net endpoint (add/remove addresses etc.) as well as to control the node as a whole (shutdown/stats/status). ## Breaking Changes - module iroh::client::net is now a reexport of iroh_node_util::rpc::client::net - module iroh::client::node is now a reexport of iroh_node_util::rpc::client::node - fn iroh::client::Iroh::net returns a net::Client instead of a &net::Client - fn iroh::client::Iroh::node returns a node::Client instead of a &node::Client ## Notes & open questions Note: I think the rpc protocol and the client needs some refactoring. It isn't always clear to me what is node and what is net. But I think it might be best to do this in a subsequent PR and keep this one as a pure move things around PR for better separation. ## Change checklist - [ ] Self-review. - [ ] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. - [ ] Tests if relevant. - [ ] All breaking changes documented. --------- Co-authored-by: dignifiedquire <[email protected]> Co-authored-by: Diva M <[email protected]>
1 parent 8b7611e commit f174c8e

File tree

21 files changed

+527
-317
lines changed

21 files changed

+527
-317
lines changed

Cargo.lock

Lines changed: 42 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ members = [
1212
"iroh-router",
1313
"net-tools/netwatch",
1414
"net-tools/portmapper",
15+
"iroh-node-util",
1516
]
1617
resolver = "2"
1718

iroh-cli/src/commands/rpc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl RpcCommands {
101101
Self::Tags { command } => command.run(&iroh.tags()).await,
102102
Self::Gossip { command } => command.run(&iroh.gossip()).await,
103103
Self::Stats => {
104-
let stats = iroh.stats().await?;
104+
let stats = iroh.node().stats().await?;
105105
for (name, details) in stats.iter() {
106106
println!(
107107
"{:23} : {:>6} ({})",
@@ -111,11 +111,11 @@ impl RpcCommands {
111111
Ok(())
112112
}
113113
Self::Shutdown { force } => {
114-
iroh.shutdown(force).await?;
114+
iroh.node().shutdown(force).await?;
115115
Ok(())
116116
}
117117
Self::Status => {
118-
let response = iroh.status().await?;
118+
let response = iroh.node().status().await?;
119119
println!("Listening addresses: {:#?}", response.listen_addrs);
120120
println!("Node ID: {}", response.addr.node_id);
121121
println!("Version: {}", response.version);

iroh-node-util/Cargo.toml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
[package]
2+
name = "iroh-node-util"
3+
description = "Utilities to build binaries containing an iroh-net endpoint"
4+
readme = "README.md"
5+
license = "MIT OR Apache-2.0"
6+
version = "0.28.0"
7+
edition = "2021"
8+
authors = ["n0 team"]
9+
repository = "https://github.com/n0-computer/iroh"
10+
keywords = ["quic", "networking", "holepunching", "p2p"]
11+
12+
# Sadly this also needs to be updated in .github/workflows/ci.yml
13+
rust-version = "1.76"
14+
15+
[lints]
16+
workspace = true
17+
18+
[dependencies]
19+
anyhow = "1"
20+
tokio = "1"
21+
iroh-net = { path = "../iroh-net" }
22+
tempfile = "3"
23+
strum = "0.26"
24+
nested_enum_utils = "0.1.0"
25+
quic-rpc = "0.15.0"
26+
quic-rpc-derive = "0.15.0"
27+
serde = "1"
28+
serde-error = "0.1.3"
29+
futures-lite = "2.5.0"
30+
tracing = "0.1.40"

iroh-node-util/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# iroh-node-util
2+
3+
This crate provides utilities to build binaries containing an iroh-net endpoint.
4+
5+
# License
6+
7+
This project is licensed under either of
8+
9+
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
10+
http://www.apache.org/licenses/LICENSE-2.0)
11+
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
12+
http://opensource.org/licenses/MIT)
13+
14+
at your option.
15+
16+
### Contribution
17+
18+
Unless you explicitly state otherwise, any contribution intentionally submitted
19+
for inclusion in this project by you, as defined in the Apache-2.0 license,
20+
shall be dual licensed as above, without any additional terms or conditions.
21+

iroh-node-util/src/lib.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
2+
//! Utilities for building iroh nodes.
3+
pub mod rpc;
4+
5+
use std::path::PathBuf;
6+
7+
use anyhow::Context;
8+
use iroh_net::key::SecretKey;
9+
use tokio::io::AsyncWriteExt;
10+
11+
/// Loads a [`SecretKey`] from the provided file, or stores a newly generated one
12+
/// at the given location.
13+
pub async fn load_secret_key(key_path: PathBuf) -> anyhow::Result<SecretKey> {
14+
if key_path.exists() {
15+
let keystr = tokio::fs::read(key_path).await?;
16+
let secret_key = SecretKey::try_from_openssh(keystr).context("invalid keyfile")?;
17+
Ok(secret_key)
18+
} else {
19+
let secret_key = SecretKey::generate();
20+
let ser_key = secret_key.to_openssh()?;
21+
22+
// Try to canonicalize if possible
23+
let key_path = key_path.canonicalize().unwrap_or(key_path);
24+
let key_path_parent = key_path.parent().ok_or_else(|| {
25+
anyhow::anyhow!("no parent directory found for '{}'", key_path.display())
26+
})?;
27+
tokio::fs::create_dir_all(&key_path_parent).await?;
28+
29+
// write to tempfile
30+
let (file, temp_file_path) = tempfile::NamedTempFile::new_in(key_path_parent)
31+
.context("unable to create tempfile")?
32+
.into_parts();
33+
let mut file = tokio::fs::File::from_std(file);
34+
file.write_all(ser_key.as_bytes())
35+
.await
36+
.context("unable to write keyfile")?;
37+
file.flush().await?;
38+
drop(file);
39+
40+
// move file
41+
tokio::fs::rename(temp_file_path, key_path)
42+
.await
43+
.context("failed to rename keyfile")?;
44+
45+
Ok(secret_key)
46+
}
47+
}

iroh-node-util/src/rpc.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! RPC client, server and protocol to control iroh-net endpoints and iroh nodes
2+
pub mod client;
3+
pub mod proto;
4+
pub mod server;

iroh-node-util/src/rpc/client.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! Client to interact with iroh nodes and endpoints.
2+
use anyhow::Result;
3+
use futures_lite::{Stream, StreamExt};
4+
5+
pub mod net;
6+
pub mod node;
7+
8+
fn flatten<T, E1, E2>(
9+
s: impl Stream<Item = Result<Result<T, E1>, E2>>,
10+
) -> impl Stream<Item = Result<T>>
11+
where
12+
E1: std::error::Error + Send + Sync + 'static,
13+
E2: std::error::Error + Send + Sync + 'static,
14+
{
15+
s.map(|res| match res {
16+
Ok(Ok(res)) => Ok(res),
17+
Ok(Err(err)) => Err(err.into()),
18+
Err(err) => Err(err.into()),
19+
})
20+
}

0 commit comments

Comments
 (0)