Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
cli: rad node connect - attempt without explicit address
Merged did:key:z6MkgFWv...1Lu7 opened 10 months ago

In many cases the radicle node is already aware of the publicly advertised addresses for each node. This PR attempts to offer connection by nid alone, ommiting the @addr part.

rad node connect z6MkrLMMsiPWUcNPHcRajuMi9mDfYckSoJyPwwnknocNYPm7 now works by finding an advertised public url to attempt the connection with. Tor and local addresses are not in scope.

2 files changed +42 -4 76e00a34 895ca5d0
modified crates/radicle-cli/examples/rad-node.md
@@ -113,8 +113,21 @@ $ rad node inventory
rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji
```

-
Some commands also give us a hint if the node isn't running:
+
We might want to directly connect to a specific node, ie. for private repositories, where routing information is not available on the network:
+

+
```
+
$ rad node connect z6MkrLMMsiPWUcNPHcRajuMi9mDfYckSoJyPwwnknocNYPm7@iris.radicle.xyz:8776
+
✓ Connecting to z6MkrLM…ocNYPm7@iris.radicle.xyz:8776...
+
```
+

+
Nodes advertise their own external addresses if they are configured to do so. If our node is aware of a public address for a node, we can attempt to connect without explicitly specifying that address:

+
```
+
$ rad node connect z6MkrLMMsiPWUcNPHcRajuMi9mDfYckSoJyPwwnknocNYPm7
+
✓ Connecting to z6MkrLM…ocNYPm7@iris.radicle.xyz:8776...
+
```
+

+
Some commands also give us a hint if the node isn't running:
``` (fail)
$ rad node events
✗ Error: failed to open node control socket "[..]/.radicle/node/control.sock" (entity not found)
modified crates/radicle-cli/src/commands/node.rs
@@ -1,14 +1,17 @@
use std::ffi::OsString;
use std::path::PathBuf;
+
use std::str::FromStr;
use std::time;

use anyhow::anyhow;

+
use radicle::node::address::Store as AddressStore;
use radicle::node::config::ConnectAddress;
use radicle::node::routing::Store;
-
use radicle::node::Handle as _;
use radicle::node::{Address, Node, NodeId, PeerAddr};
+
use radicle::node::{Handle as _, HostName};
use radicle::prelude::RepoId;
+
use radicle_crypto::PublicKey;

use crate::terminal as term;
use crate::terminal::args::{Args, Error, Help};
@@ -35,7 +38,7 @@ Usage
    rad node stop [<option>...]
    rad node logs [-n <lines>]
    rad node debug [<option>...]
-
    rad node connect <nid>@<addr> [<option>...]
+
    rad node connect <nid>[@<addr>] [<option>...]
    rad node routing [--rid <rid>] [--nid <nid>] [--json] [<option>...]
    rad node inventory [--nid <nid>] [<option>...]
    rad node events [--timeout <secs>] [-n <count>] [<option>...]
@@ -171,7 +174,29 @@ impl Args for Options {
                    unknown => anyhow::bail!("unknown operation '{}'", unknown),
                },
                Value(val) if matches!(op, Some(OperationName::Connect)) => {
-
                    addr = Some(val.parse()?);
+
                    addr = if let Some(connect_string) = val.to_str() {
+
                        if connect_string.contains('@') {
+
                            Some(connect_string.parse()?)
+
                        } else {
+
                            let profile = radicle::Profile::load()?;
+
                            let db = profile.database()?;
+

+
                            let known_addresses =
+
                                db.addresses_of(&PublicKey::from_str(connect_string)?)?;
+

+
                            let guess = known_addresses
+
                                .iter()
+
                                .find(|known_address| {
+
                                    matches!(&known_address.addr.host, HostName::Dns(_))
+
                                })
+
                                .ok_or(anyhow!("couldn't find a public address for the node"))?;
+
                            let address = guess.addr.to_string();
+

+
                            Some(format!("{connect_string}@{address}").parse()?)
+
                        }
+
                    } else {
+
                        None
+
                    }
                }
                Long("rid") if matches!(op, Some(OperationName::Routing)) => {
                    let val = parser.value()?;