Skip to content

Commit 30577d3

Browse files
authored
feat: improve transfer, publish, resolve examples (#3296)
## Description This improves the `transfer`, `publish` and `resolve` examples, which we often use for dogfooding new releases. #### `transfer` example: * Set `prod` or `staging` environments with a single arg, while still optionally allowing to override relay, pkarr, and DNS servers. * Add a `dev` environment that uses locally running `iroh-relay` and `iroh-dns-server` instances, for easily using the example with a locally running dev setup of all services. * Optionally enable mDNS discovery * Print connection type changes * Allow reusing a node id by setting `IROH_SECRET` environment variable * Improve help and print output * Improve code to not duplicate endpoint setup and arguments between fetch and provide side Here's the new help text and output: <details> <summary>Help text for provide</summary> ``` $ cargo run --release --example transfer --all-features -- provide --help Provide data Usage: transfer provide [OPTIONS] Options: --size <SIZE> [default: 100M] -e, --env <ENV> Set the environment for relay, pkarr, and DNS servers. If other options are set, those will override the environment defaults. [default: staging] Possible values: - prod: Use the production servers hosted by number0 - staging: Use the staging servers hosted by number0 - dev: Use localhost servers --relay-url <RELAY_URL> Set one or more relay servers to use --no-relay Disable relays completely --relay-only If set no direct connections will be established --pkarr-relay-url <PKARR_RELAY_URL> Use a custom pkarr server --no-pkarr-publish Disable publishing node info to pkarr --dns-origin-domain <DNS_ORIGIN_DOMAIN> Use a custom domain when resolving node info via DNS --dns-server <DNS_SERVER> Use a custom DNS server for resolving relay and node info domains --no-dns-resolve Do not resolve node info via DNS --mdns Enable mDNS discovery -h, --help Print help (see a summary with '-h') ``` </details> <details> <summary>Help text for fetch</summary> ``` $ cargo run -q --release --example transfer --all-features -- fetch --help Fetch data Usage: transfer fetch [OPTIONS] <TICKET> Arguments: <TICKET> Options: -e, --env <ENV> Set the environment for relay, pkarr, and DNS servers. If other options are set, those will override the environment defaults. [default: staging] Possible values: - prod: Use the production servers hosted by number0 - staging: Use the staging servers hosted by number0 - dev: Use localhost servers --relay-url <RELAY_URL> Set one or more relay servers to use --no-relay Disable relays completely --relay-only If set no direct connections will be established --pkarr-relay-url <PKARR_RELAY_URL> Use a custom pkarr server --no-pkarr-publish Disable publishing node info to pkarr --dns-origin-domain <DNS_ORIGIN_DOMAIN> Use a custom domain when resolving node info via DNS --dns-server <DNS_SERVER> Use a custom DNS server for resolving relay and node info domains --no-dns-resolve Do not resolve node info via DNS --mdns Enable mDNS discovery -h, --help Print help (see a summary with '-h') ``` </details> <details> <summary>Output on provide side</summary> ``` $ cargo -q run --release --example transfer --all-features -- provide -e staging Our node id: fdeb67bd2995cbdf1844e1170b01848af5e6b13beb4d754ec86dd38b4ecdae3a Our direct addresses: 78.xx.xx.xx:44377 (type: Stun) 192.168.xxx.xxx:44377 (type: Local) Our home relay server: https://staging-euw1-1.relay.iroh.network./ Ticket with our home relay and direct addresses: nodead66wz55[redacted] Ticket with our home relay but no direct addresses: nodead66wz55fgk4xxyyitqrocybqsfplzvrhpvu25kozbw5hc2ozwxduajlnb2hi4dthixs643umftws3thfvsxk5zrfuys44tfnrqxsltjojxwqltomv2ho33snmxc6aa Ticket with only our node id: nodead66wz55fgk4xxyyitqrocybqsfplzvrhpvu25kozbw5hc2ozwxduaaa [7b1a7ac46f] Connected [7b1a7ac46f] Received: "7b1a7ac46f is saying hello!" [7b1a7ac46f] Connection type changed to: direct(192.168.xxx.xxx:48801) [7b1a7ac46f] Transferred 100.00 MiB in 0.6929s, 144.31 MiB/s [7b1a7ac46f] Disconnected ``` </details> <details> <summary>Output on fetch side</summary> ``` $ cargo -q run --release --example transfer --all-features -- fetch -e staging nodead66wz55fgk4xxyyitqrocybqsfplzvrhpvu25kozbw5hc2ozwxduaaa Generated a new node secret. To reuse, set IROH_SECRET=a924573310dc0c0763b64ea82c307895965883d1046f4555954689dd8a937d8c Our node id: 7b1a7ac46f528bc5182ea214326fe2a348d2a6f3a3a63d505947c3f0980e8f43 Our direct addresses: 78.xxx.xxx.xxx:48801 (type: Stun) 192.168.xxx.xxx:48801 (type: Local) Our home relay server: https://staging-euw1-1.relay.iroh.network./ Connected to fdeb67bd2995cbdf1844e1170b01848af5e6b13beb4d754ec86dd38b4ecdae3a Sent: "7b1a7ac46f is saying hello!" [fdeb67bd29] Connection type changed to: direct(192.168.xxx.xxx:44555) Received 100.00 MiB in 1.0968s (91.17 MiB/s, time to first byte 0.002208444s, 3518 chunks) ``` </details> #### `publish` and `resolve` examples * Set a default relay URL in the publish example. Otherwise an empty node info would be published if not setting any further arguments, which was a major UX footgun. A new argument `no-relay-url` allows to publish without relay URL. * Cleanup constant names to match those used in the `transfer` example * Allow to set a custom origin domain in the resolve example ## Breaking Changes <!-- Optional, if there are any breaking changes document them, including how to migrate older code. --> ## Notes & open questions <!-- Any notes, remarks or open questions you have to make about the PR. --> ## Change checklist <!-- Remove any that are not relevant. --> - [x] Self-review. - [x] 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.
1 parent f3c9af3 commit 30577d3

File tree

3 files changed

+345
-229
lines changed

3 files changed

+345
-229
lines changed

iroh-dns-server/examples/publish.rs

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{net::SocketAddr, str::FromStr};
22

3-
use anyhow::{bail, Result};
3+
use anyhow::{Context, Result};
44
use clap::{Parser, ValueEnum};
55
use iroh::{
66
discovery::{
@@ -13,8 +13,9 @@ use iroh::{
1313
};
1414
use url::Url;
1515

16-
const LOCALHOST_PKARR: &str = "http://localhost:8080/pkarr";
17-
const EXAMPLE_ORIGIN: &str = "irohdns.example";
16+
const DEV_PKARR_RELAY_URL: &str = "http://localhost:8080/pkarr";
17+
const DEV_DNS_ORIGIN_DOMAIN: &str = "irohdns.example";
18+
const EXAMPLE_RELAY_URL: &str = "https://relay.iroh.example";
1819

1920
#[derive(ValueEnum, Clone, Debug, Default, Copy, strum::Display)]
2021
#[strum(serialize_all = "kebab-case")]
@@ -38,19 +39,19 @@ struct Cli {
3839
env: Env,
3940
/// Pkarr Relay URL. If set, the --env option will be ignored.
4041
#[clap(long, conflicts_with = "env")]
41-
pkarr_relay: Option<Url>,
42-
/// Home relay server to publish for this node
43-
#[clap(short, long)]
42+
pkarr_relay_url: Option<Url>,
43+
/// Home relay server URL to publish.
44+
#[clap(short, long, conflicts_with = "no_relay_url")]
4445
relay_url: Option<Url>,
45-
/// Direct addresses to publish for this node
46+
/// Do not publish a home relay server URL.
47+
#[clap(long)]
48+
no_relay_url: bool,
49+
/// Direct addresses to publish.
4650
#[clap(short, long)]
4751
addr: Vec<SocketAddr>,
4852
/// User data to publish for this node
4953
#[clap(short, long)]
5054
user_data: Option<UserData>,
51-
/// Create a new node secret if IROH_SECRET is unset. Only for development / debugging.
52-
#[clap(short, long)]
53-
create: bool,
5455
}
5556

5657
#[tokio::main]
@@ -59,28 +60,34 @@ async fn main() -> Result<()> {
5960
let args = Cli::parse();
6061

6162
let secret_key = match std::env::var("IROH_SECRET") {
62-
Ok(s) => SecretKey::from_str(&s)?,
63-
Err(_) if args.create => {
63+
Ok(s) => SecretKey::from_str(&s)
64+
.context("failed to parse IROH_SECRET environment variable as iroh secret key")?,
65+
Err(_) => {
6466
let s = SecretKey::generate(rand::rngs::OsRng);
6567
println!("Generated a new node secret. To reuse, set");
66-
println!("IROH_SECRET={s}");
68+
println!("\tIROH_SECRET={s}\n");
6769
s
6870
}
69-
Err(_) => {
70-
bail!("Environment variable IROH_SECRET is not set. To create a new secret, use the --create option.")
71-
}
7271
};
7372

7473
let node_id = secret_key.public();
75-
let pkarr_relay = match (args.pkarr_relay, args.env) {
76-
(Some(pkarr_relay), _) => pkarr_relay,
74+
let pkarr_relay_url = match (args.pkarr_relay_url, args.env) {
75+
(Some(url), _) => url,
7776
(None, Env::Staging) => N0_DNS_PKARR_RELAY_STAGING.parse().expect("valid url"),
7877
(None, Env::Prod) => N0_DNS_PKARR_RELAY_PROD.parse().expect("valid url"),
79-
(None, Env::Dev) => LOCALHOST_PKARR.parse().expect("valid url"),
78+
(None, Env::Dev) => DEV_PKARR_RELAY_URL.parse().expect("valid url"),
8079
};
8180

82-
println!("announce {node_id}:");
83-
if let Some(relay_url) = &args.relay_url {
81+
let relay_url = if let Some(relay_url) = args.relay_url {
82+
Some(relay_url)
83+
} else if !args.no_relay_url {
84+
Some(EXAMPLE_RELAY_URL.parse().expect("valid url"))
85+
} else {
86+
None
87+
};
88+
89+
println!("announce node {node_id}:");
90+
if let Some(relay_url) = &relay_url {
8491
println!(" relay={relay_url}");
8592
}
8693
for addr in &args.addr {
@@ -90,11 +97,11 @@ async fn main() -> Result<()> {
9097
println!(" user-data={user_data}");
9198
}
9299
println!();
93-
println!("publish to {pkarr_relay} ...");
100+
println!("publish to {pkarr_relay_url} ...");
94101

95-
let pkarr = PkarrRelayClient::new(pkarr_relay);
102+
let pkarr = PkarrRelayClient::new(pkarr_relay_url);
96103
let node_info = NodeInfo::new(node_id)
97-
.with_relay_url(args.relay_url.map(Into::into))
104+
.with_relay_url(relay_url.map(Into::into))
98105
.with_direct_addresses(args.addr.into_iter().collect())
99106
.with_user_data(args.user_data);
100107
let signed_packet = node_info.to_pkarr_signed_packet(&secret_key, 30)?;
@@ -105,7 +112,10 @@ async fn main() -> Result<()> {
105112

106113
match args.env {
107114
Env::Staging => {
108-
println!(" cargo run --example resolve -- node {}", node_id);
115+
println!(
116+
" cargo run --example resolve -- --env staging node {}",
117+
node_id
118+
);
109119
println!(
110120
" dig {} TXT",
111121
fmt_domain(&node_id, N0_DNS_NODE_ORIGIN_STAGING)
@@ -128,7 +138,7 @@ async fn main() -> Result<()> {
128138
);
129139
println!(
130140
" dig @localhost -p 5300 {} TXT",
131-
fmt_domain(&node_id, EXAMPLE_ORIGIN)
141+
fmt_domain(&node_id, DEV_DNS_ORIGIN_DOMAIN)
132142
)
133143
}
134144
}

iroh-dns-server/examples/resolve.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
use anyhow::Context;
12
use clap::{Parser, ValueEnum};
23
use iroh::{
34
discovery::dns::{N0_DNS_NODE_ORIGIN_PROD, N0_DNS_NODE_ORIGIN_STAGING},
45
dns::DnsResolver,
56
NodeId,
67
};
78

8-
const LOCALHOST_DNS: &str = "127.0.0.1:5300";
9-
const EXAMPLE_ORIGIN: &str = "irohdns.example";
9+
const DEV_DNS_SERVER: &str = "127.0.0.1:5300";
10+
const DEV_DNS_ORIGIN_DOMAIN: &str = "irohdns.example";
1011

1112
#[derive(ValueEnum, Clone, Debug, Default)]
1213
pub enum Env {
@@ -23,31 +24,55 @@ pub enum Env {
2324
struct Cli {
2425
#[clap(value_enum, short, long, default_value_t = Env::Staging)]
2526
env: Env,
27+
dns_server: Option<String>,
2628
#[clap(subcommand)]
2729
command: Command,
2830
}
2931

3032
#[derive(Debug, Parser)]
3133
enum Command {
3234
/// Resolve node info by node id.
33-
Node { node_id: NodeId },
35+
Node {
36+
/// The node id to resolve.
37+
node_id: NodeId,
38+
/// Use a custom domain when resolving node info via DNS.
39+
#[clap(long)]
40+
dns_origin_domain: Option<String>,
41+
},
3442
/// Resolve node info by domain.
3543
Domain { domain: String },
3644
}
3745

3846
#[tokio::main]
3947
async fn main() -> anyhow::Result<()> {
4048
let args = Cli::parse();
41-
let (resolver, origin) = match args.env {
42-
Env::Staging => (DnsResolver::new(), N0_DNS_NODE_ORIGIN_STAGING),
43-
Env::Prod => (DnsResolver::new(), N0_DNS_NODE_ORIGIN_PROD),
44-
Env::Dev => (
45-
DnsResolver::with_nameserver(LOCALHOST_DNS.parse()?),
46-
EXAMPLE_ORIGIN,
47-
),
49+
let resolver = if let Some(host) = args.dns_server {
50+
let addr = tokio::net::lookup_host(host)
51+
.await?
52+
.next()
53+
.context("failed to resolve DNS server address")?;
54+
DnsResolver::with_nameserver(addr)
55+
} else {
56+
match args.env {
57+
Env::Staging | Env::Prod => DnsResolver::new(),
58+
Env::Dev => {
59+
DnsResolver::with_nameserver(DEV_DNS_SERVER.parse().expect("valid address"))
60+
}
61+
}
4862
};
4963
let resolved = match args.command {
50-
Command::Node { node_id } => resolver.lookup_node_by_id(&node_id, origin).await?,
64+
Command::Node {
65+
node_id,
66+
dns_origin_domain,
67+
} => {
68+
let origin_domain = match (&dns_origin_domain, args.env) {
69+
(Some(domain), _) => domain,
70+
(None, Env::Prod) => N0_DNS_NODE_ORIGIN_PROD,
71+
(None, Env::Staging) => N0_DNS_NODE_ORIGIN_STAGING,
72+
(None, Env::Dev) => DEV_DNS_ORIGIN_DOMAIN,
73+
};
74+
resolver.lookup_node_by_id(&node_id, origin_domain).await?
75+
}
5176
Command::Domain { domain } => resolver.lookup_node_by_domain_name(&domain).await?,
5277
};
5378
println!("resolved node {}", resolved.node_id);

0 commit comments

Comments
 (0)