Skip to content

Commit

Permalink
feat(iroh)!: expand ability to connect to RPC (#2398)
Browse files Browse the repository at this point in the history
Allows for easier connectivity of RPC, when not having access to the
folder, e.g. in a docker setup

## Breaking Changes

- renamed `iroh::client::Iroh::connect` ->
`iroh::client::Iroh::connect_path`
- added `iroh::client::Iroh::connect_addr`
- added `rpc_port` field to `iroh::client::NodeStatus` 

## Notes & open questions

There might be nicer ways, but this works for now

## Change checklist

- [x] Self-review.
- [x] Documentation updates if relevant.
- [x] Tests if relevant.
- [x] All breaking changes documented.
  • Loading branch information
dignifiedquire authored Jun 24, 2024
1 parent 38e8ce0 commit 0ed020c
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 10 deletions.
4 changes: 2 additions & 2 deletions iroh-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl Cli {
.await
} else {
crate::logging::init_terminal_logging()?;
let iroh = Iroh::connect(data_dir).await.context("rpc connect")?;
let iroh = Iroh::connect_path(data_dir).await.context("rpc connect")?;
let env = ConsoleEnv::for_console(data_dir_owned, &iroh).await?;
console::run(&iroh, &env).await
}
Expand All @@ -151,7 +151,7 @@ impl Cli {
.await
} else {
crate::logging::init_terminal_logging()?;
let iroh = Iroh::connect(data_dir).await.context("rpc connect")?;
let iroh = Iroh::connect_path(data_dir).await.context("rpc connect")?;
let env = ConsoleEnv::for_cli(data_dir_owned, &iroh).await?;
command.run(&iroh, &env).await
}
Expand Down
2 changes: 1 addition & 1 deletion iroh-cli/src/commands/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,7 @@ mod tests {
let cli = ConsoleEnv::for_console(data_dir.path().to_owned(), &node)
.await
.context("ConsoleEnv")?;
let iroh = iroh::client::Iroh::connect(data_dir.path())
let iroh = iroh::client::Iroh::connect_path(data_dir.path())
.await
.context("rpc connect")?;

Expand Down
3 changes: 3 additions & 0 deletions iroh-cli/src/commands/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ impl NodeCommands {
println!("Listening addresses: {:#?}", response.listen_addrs);
println!("Node public key: {}", response.addr.node_id);
println!("Version: {}", response.version);
if let Some(port) = response.rpc_port {
println!("RPC Port: {}", port);
}
}
}
Ok(())
Expand Down
2 changes: 2 additions & 0 deletions iroh/src/client/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,6 @@ pub struct NodeStatus {
pub listen_addrs: Vec<SocketAddr>,
/// The version of the node
pub version: String,
/// RPC port, if currently listening.
pub rpc_port: Option<u16>,
}
14 changes: 10 additions & 4 deletions iroh/src/client/quic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,29 @@ pub type RpcClient = quic_rpc::RpcClient<RpcService, BoxedConnection<RpcService>

impl Iroh {
/// Connect to an iroh node running on the same computer, but in a different process.
pub async fn connect(root: impl AsRef<Path>) -> anyhow::Result<Self> {
pub async fn connect_path(root: impl AsRef<Path>) -> anyhow::Result<Self> {
let rpc_status = RpcStatus::load(root).await?;
match rpc_status {
RpcStatus::Stopped => {
bail!("iroh is not running, please start it");
}
RpcStatus::Running { client, .. } => Ok(Iroh::new(client)),
RpcStatus::Running { client, port: _ } => Ok(Iroh::new(client)),
}
}

/// Connect to an iroh node at the given RPC address.
pub async fn connect_addr(addr: SocketAddr) -> anyhow::Result<Self> {
let client = connect_raw(addr).await?;
Ok(Iroh::new(client))
}
}

/// Create a raw RPC client to an iroh node running on the same computer, but in a different
/// process.
pub(crate) async fn connect_raw(rpc_port: u16) -> anyhow::Result<RpcClient> {
pub(crate) async fn connect_raw(addr: SocketAddr) -> anyhow::Result<RpcClient> {
let bind_addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into();
let endpoint = create_quinn_client(bind_addr, vec![RPC_ALPN.to_vec()], false)?;
let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), rpc_port);

let server_name = "localhost".to_string();
let connection = QuinnConnection::<RpcService>::new(endpoint, addr, server_name);
let connection = BoxedConnection::new(connection);
Expand Down
6 changes: 6 additions & 0 deletions iroh/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub struct Node<D> {
#[derive(derive_more::Debug)]
struct NodeInner<D> {
db: D,
rpc_port: Option<u16>,
docs: Option<DocsEngine>,
endpoint: Endpoint,
gossip: Gossip,
Expand Down Expand Up @@ -150,6 +151,11 @@ impl<D: BaoStore> Node<D> {
self.inner.endpoint.home_relay()
}

/// Returns `Some(port)` if an RPC endpoint is running on this port.
pub fn my_rpc_port(&self) -> Option<u16> {
self.inner.rpc_port
}

/// Shutdown the node.
///
/// This does not gracefully terminate currently: all connections are closed and
Expand Down
13 changes: 12 additions & 1 deletion iroh/src/node/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ where
bind_port: Option<u16>,
secret_key: SecretKey,
rpc_endpoint: E,
rpc_port: Option<u16>,
blobs_store: D,
keylog: bool,
relay_mode: RelayMode,
Expand Down Expand Up @@ -156,6 +157,7 @@ impl Default for Builder<iroh_blobs::store::mem::Store> {
relay_mode: RelayMode::Default,
dns_resolver: None,
rpc_endpoint: Default::default(),
rpc_port: None,
gc_policy: GcPolicy::Disabled,
docs_storage: DocsStorage::Memory,
node_discovery: Default::default(),
Expand All @@ -182,6 +184,7 @@ impl<D: Map> Builder<D> {
relay_mode: RelayMode::Default,
dns_resolver: None,
rpc_endpoint: Default::default(),
rpc_port: None,
gc_policy: GcPolicy::Disabled,
docs_storage,
node_discovery: Default::default(),
Expand Down Expand Up @@ -244,6 +247,7 @@ where
blobs_store,
keylog: self.keylog,
rpc_endpoint: self.rpc_endpoint,
rpc_port: self.rpc_port,
relay_mode: self.relay_mode,
dns_resolver: self.dns_resolver,
gc_policy: self.gc_policy,
Expand All @@ -256,7 +260,11 @@ where
}

/// Configure rpc endpoint, changing the type of the builder to the new endpoint type.
pub fn rpc_endpoint<E2: ServiceEndpoint<RpcService>>(self, value: E2) -> Builder<D, E2> {
pub fn rpc_endpoint<E2: ServiceEndpoint<RpcService>>(
self,
value: E2,
port: Option<u16>,
) -> Builder<D, E2> {
// we can't use ..self here because the return type is different
Builder {
storage: self.storage,
Expand All @@ -265,6 +273,7 @@ where
blobs_store: self.blobs_store,
keylog: self.keylog,
rpc_endpoint: value,
rpc_port: port,
relay_mode: self.relay_mode,
dns_resolver: self.dns_resolver,
gc_policy: self.gc_policy,
Expand All @@ -291,6 +300,7 @@ where
blobs_store: self.blobs_store,
keylog: self.keylog,
rpc_endpoint: ep,
rpc_port: Some(actual_rpc_port),
relay_mode: self.relay_mode,
dns_resolver: self.dns_resolver,
gc_policy: self.gc_policy,
Expand Down Expand Up @@ -501,6 +511,7 @@ where
let client = crate::client::Iroh::new(quic_rpc::RpcClient::new(controller.clone()));

let inner = Arc::new(NodeInner {
rpc_port: self.rpc_port,
db: self.blobs_store,
docs,
endpoint,
Expand Down
1 change: 1 addition & 0 deletions iroh/src/node/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,7 @@ impl<D: BaoStore> Handler<D> {
.await
.unwrap_or_default(),
version: env!("CARGO_PKG_VERSION").to_string(),
rpc_port: self.inner.rpc_port,
})
}

Expand Down
8 changes: 6 additions & 2 deletions iroh/src/node/rpc_status.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::path::Path;
use std::{
net::{Ipv4Addr, SocketAddr},
path::Path,
};

use anyhow::{ensure, Context, Result};
use tokio::{fs, io::AsyncReadExt};
Expand Down Expand Up @@ -40,7 +43,8 @@ impl RpcStatus {
.await
.context("read rpc lock file")?;
let running_rpc_port = u16::from_le_bytes(buffer);
if let Ok(client) = crate::client::quic_connect_raw(running_rpc_port).await {
let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), running_rpc_port);
if let Ok(client) = crate::client::quic_connect_raw(addr).await {
return Ok(RpcStatus::Running {
port: running_rpc_port,
client,
Expand Down

0 comments on commit 0ed020c

Please sign in to comment.