Skip to content

Commit 16dbbf8

Browse files
authored
fix: Outdated code examples (#295)
* Update quickstart * Simplify code in `concepts/discovery/page.mdx` * Fix `router/page.mdx` * Remove ticket section that's outdated * Fix numbering in the tour * Fix the tour styling * Update tour to latest protocol & iroh versions
1 parent b37859a commit 16dbbf8

File tree

11 files changed

+89
-107
lines changed

11 files changed

+89
-107
lines changed

src/app/docs/concepts/discovery/page.mdx

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ There are four different implementations of the discovery service in iroh, all o
1616
| --- | --- | --- |
1717
| 1 | [DNS](#dns-discovery) | uses a custom Domain Name System server |
1818
| 2 | [Local](#local-discovery) | uses an mDNS-like system to find nodes on the local network |
19-
| 3 | [Pkarr](#pkarr-discovery) | uses Pkarr Servers over HTTP |
19+
| 3 | [Pkarr](#pkarr-discovery) | uses Pkarr Servers over HTTP |
2020
| 4 | [DHT](#dht-discovery) | uses the BitTorrent Mainline DHT |
2121

2222
By Default, iroh uses the DNS discovery system to resolve NodeIds to addresses. And can be configured to use any of the other discovery systems.
@@ -35,26 +35,18 @@ Local Discovery is _not_ enabled by default, and must be enabled by the user. Yo
3535

3636
```toml
3737
[dependencies]
38-
iroh = { version = "0.1", features = ["discovery-local-network"] }
38+
# Make sure to use the most recent version here instead of nn. (at the time of writing: 0.32)
39+
iroh = { version = "0.nn", features = ["discovery-local-network"] }
3940
```
4041

4142
Then configure your endpoint to use local discovery concurrently with DNS discovery:
4243

4344
```rust
44-
use iroh::{
45-
discovery::{dns::DnsDiscovery, LocalSwarmDiscovery, pkarr::PkarrPublisher, ConcurrentDiscovery},
46-
Endpoint, SecretKey,
47-
};
48-
49-
let secret_key = SecretKey::generate(rand::rngs::OsRng);
50-
let discovery = ConcurrentDiscovery::from_services(vec![
51-
Box::new(DnsDiscovery::n0_dns()),
52-
Box::new(LocalSwarmDiscovery::new(secret_key.public())?),
53-
]);
45+
use iroh::Endpoint;
5446

5547
let ep = Endpoint::builder()
56-
.secret_key(secret_key)
57-
.discovery(Box::new(discovery))
48+
.discovery_n0()
49+
.discovery_local_network()
5850
.bind()
5951
.await?;
6052
```
@@ -69,27 +61,18 @@ DHT Discovery is _not_ enabled by default, and must be enabled by the user. You'
6961

7062
```toml
7163
[dependencies]
72-
# Make sure to use the most recent version here instead of nn.
64+
# Make sure to use the most recent version here instead of nn. (at the time of writing: 0.32)
7365
iroh = { version = "0.nn", features = ["discovery-pkarr-dht"] }
7466
```
7567

7668
Then configure your endpoint to use DHT discovery concurrently with DNS discovery:
7769

7870
```rust
79-
use iroh::{
80-
discovery::{dns::DnsDiscovery, pkarr::dht::DhtDiscovery, ConcurrentDiscovery},
81-
Endpoint, SecretKey,
82-
};
83-
84-
let secret_key = SecretKey::generate(rand::rngs::OsRng);
85-
let discovery = ConcurrentDiscovery::from_services(vec![
86-
Box::new(DnsDiscovery::n0_dns()),
87-
Box::new(DhtDiscvoery::new(secret_key.public())?),
88-
]);
71+
use iroh::Endpoint;
8972

9073
let ep = Endpoint::builder()
91-
.secret_key(secret_key)
92-
.discovery(Box::new(discovery))
74+
.discovery_n0()
75+
.discovery_dht()
9376
.bind()
9477
.await?;
9578
```

src/app/docs/concepts/router/page.mdx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,12 @@ async fn main() -> Result<()> {
2121
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
2222

2323
// configure the blobs protocol to run in-memory
24-
let lp = LocalPool::default();
25-
let blobs = Blobs::memory()
26-
.build(lp.handle(), &endpoint);
24+
let blobs = Blobs::memory().build(&endpoint);
2725

2826
// Build our router and add the blobs protocol,
2927
// identified by its ALPN. Spawn the router to start listening.
3028
let router = Router::builder(endpoint)
31-
.accept(iroh_blobs::ALPN, blobs.clone())
29+
.accept(iroh_blobs::ALPN, blobs)
3230
.spawn()
3331
.await?;
3432

@@ -39,6 +37,11 @@ async fn main() -> Result<()> {
3937
// Wait for exit
4038
tokio::signal::ctrl_c().await?;
4139

40+
// Gracefully close the endpoint & protocols.
41+
// This makes sure that remote nodes are notified about possibly still open connections
42+
// and any data is written to disk fully (or any other shutdown procedure for protocols).
43+
router.shutdown().await?;
44+
4245
Ok(())
4346
}
4447
```

src/app/docs/concepts/tickets/page.mdx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,6 @@ It's worth point out this setup is considerably better than full peer-2-peer sys
4040

4141
When you create a document ticket, you're creating a secret that allows someone to read or write to a document. This means that you should be careful about sharing document tickets with people you don't trust. What's more, someone who has a document ticket can use it to create new tickets for the same document. This means that if you share a document ticket with someone, they can use it to create new tickets for the same document, and share those tickets with others.
4242

43-
## Creating Tickets
44-
45-
| Type | Command |
46-
| --- | --- |
47-
| `node` | [`dumbpipe listen`](https://dumbpipe.dev) |
48-
| `blob` | `iroh blob share` |
49-
| `doc` | [`iroh doc share`](/docs/api/doc-share) |
50-
51-
by default, tickets only include the nodeID If you still want to add relay and direct addresses to the ticket, you can pass `--addr-options RelayAndAddresses` to the ticket generation commands.
52-
5343
## Tickets in Apps
5444
Using tickets in your app comes down to what you're trying to accomplish. For short-lived sessions where both devices are online at the same time, tickets are an incredibly powerful way to bootstrap connections, and require no additinonal servers for coordination.
5545

src/app/docs/quickstart/page.mdx

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ In that case, you'll need to make sure you're not only dialing by `NodeId`, but
7575
</Note>
7676

7777

78-
## Using an existing protocol: [iroh-blobs](/proto/iroh-blobs)
78+
## Using an existing protocol: iroh-blobs
7979

80-
Instead of writing our own protocol from scratch, let's use iroh-blobs, which already does what we want:
80+
Instead of writing our own protocol from scratch, let's use [iroh-blobs](/proto/iroh-blobs), which already does what we want:
8181
It loads files from your file system and provides a protocol for seekable, resumable downloads of these files.
8282

8383
```rust
@@ -88,8 +88,7 @@ async fn main() -> anyhow::Result<()> {
8888
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
8989

9090
// We initialize the Blobs protocol in-memory
91-
let local_pool = LocalPool::default();
92-
let blobs = Blobs::memory().build(&local_pool, &endpoint);
91+
let blobs = Blobs::memory().build(&endpoint);
9392

9493
// ...
9594

@@ -118,8 +117,7 @@ async fn main() -> anyhow::Result<()> {
118117
let endpoint = Endpoint::builder().discovery_n0().bind().await?;
119118

120119
// We initialize the Blobs protocol in-memory
121-
let local_pool = LocalPool::default();
122-
let blobs = Blobs::memory().build(&local_pool, &endpoint);
120+
let blobs = Blobs::memory().build(&endpoint);
123121

124122
// Now we build a router that accepts blobs connections & routes them
125123
// to the blobs protocol.
@@ -133,19 +131,18 @@ async fn main() -> anyhow::Result<()> {
133131
// Gracefully shut down the router
134132
println!("Shutting down.");
135133
router.shutdown().await?;
136-
local_pool.shutdown().await;
137134

138135
Ok(())
139136
}
140137
```
141138

142-
I've also taken the liberty to make sure that we're gracefully shutting down the `Router` and all its protocols with it, as well as the `LocalPool` that the iroh-blobs library needs to operate.
139+
I've also taken the liberty to make sure that we're gracefully shutting down the `Router` and all its protocols with it, in this case that's only iroh-blobs.
143140

144141

145142
## Doing something
146143

147144
So far, this code works, but doesn't actually do anything besides spinning up a node and immediately shutting down.
148-
Even if we put in a `tokio::time::timeout` or `tokio::signal::ctrl_c().await` in there, it *would* actually respond to network requests for the blobs protocol, but even that is practically useless as we've stored no blobs to respond with.
145+
If we put in a `tokio::time::timeout` or `tokio::signal::ctrl_c().await` in there, although it *would* actually respond to network requests for the blobs protocol, these responses are practically useless as we've stored no blobs to respond with.
149146

150147
Here's our plan for turning this into a CLI that actually does what we set out to build:
151148
1. We'll grab a [`Blobs::client`](https://docs.rs/iroh-blobs/latest/iroh_blobs/net_protocol/struct.Blobs.html#method.client) to interact with the iroh-blobs node we're running locally.
@@ -162,18 +159,23 @@ Here's our plan for turning this into a CLI that actually does what we set out t
162159
Phew okay! Here's how we'll grab an iroh-blobs client and look at the CLI arguments:
163160

164161
```rust
165-
let blobs = blobs.client();
162+
// We use a blobs client to interact with the blobs protocol we're running locally:
163+
let blobs_client = blobs.client();
166164

167-
let args = std::env::args().collect::<Vec<_>>();
168-
match &args.iter().map(String::as_str).collect::<Vec<_>>()[..] {
169-
[_cmd, "send", path] => {
165+
// Grab all passed in arguments, the first one is the binary itself, so we skip it.
166+
let args: Vec<String> = std::env::args().skip(1).collect();
167+
// Convert to &str, so we can pattern-match easily:
168+
let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect();
169+
170+
match arg_refs.as_slice() {
171+
["send", filename] => {
170172
todo!();
171173
}
172-
[_cmd, "receive", ticket, path] => {
174+
["receive", ticket, filename] => {
173175
todo!();
174176
}
175177
_ => {
176-
println!("Couldn't parse command line arguments.");
178+
println!("Couldn't parse command line arguments: {args:?}");
177179
println!("Usage:");
178180
println!(" # to send:");
179181
println!(" cargo run --example transfer -- send [FILE]");
@@ -189,23 +191,26 @@ Now all we need to do is fill in the `todo!()`s one-by-one:
189191

190192
### Getting ready to send
191193

192-
If we want to make a file available over the network with iroh-blobs, we first need to index this file.
194+
If we want to make a file available over the network with iroh-blobs, we first need to hash this file.
193195

194196
<Note>
195197
What does this step do?
196198

197-
It hashes the file using BLAKE3 and stores a so-called "outboard" for that file.
198-
This outboard file contains information about hashes for parts of this file.
199+
It hashes the file using [BLAKE3](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) and stores a so-called ["outboard"](https://github.com/oconnor663/bao?tab=readme-ov-file#outboard-mode) for that file.
200+
This outboard file contains information about hashes of parts of this file.
199201
All of this enables some extra features with iroh-blobs like automatically verifying the integrity of the file *during* streaming, verified range downloads and download resumption.
200202
</Note>
201203

202204
```rust
203-
let abs_path = PathBuf::from_str(path)?.canonicalize()?;
205+
let filename: PathBuf = filename.parse()?;
206+
let abs_path = std::path::absolute(&filename)?;
204207

205-
println!("Indexing file.");
208+
println!("Hashing file.");
206209

207-
let blob = blobs
208-
.add_from_path(abs_path, true, SetTagOption::Auto, WrapOption::NoWrap)
210+
// keep the file in place and link it, instead of copying it into the in-memory blobs database
211+
let in_place = true;
212+
let blob = blobs_client
213+
.add_from_path(abs_path, in_place, SetTagOption::Auto, WrapOption::NoWrap)
209214
.await?
210215
.finish()
211216
.await?;
@@ -221,7 +226,7 @@ This ticket contains the `NodeId` of our `Endpoint` as well as the file's BLAKE3
221226
let node_id = router.endpoint().node_id();
222227
let ticket = BlobTicket::new(node_id.into(), blob.hash, blob.format)?;
223228

224-
println!("File analyzed. Fetch this file by running:");
229+
println!("File hashed. Fetch this file by running:");
225230
println!("cargo run --example transfer -- receive {ticket} {path}");
226231

227232
tokio::signal::ctrl_c().await?;
@@ -236,12 +241,13 @@ On the connection side, we got the `ticket` and the `path` from the CLI argument
236241
With them parsed, we can call `blobs.download` with the information contained in the ticket and wait for the download to finish:
237242

238243
```rust
239-
let path_buf = PathBuf::from_str(path)?;
240-
let ticket = BlobTicket::from_str(ticket)?;
244+
let filename: PathBuf = filename.parse()?;
245+
let abs_path = std::path::absolute(filename)?;
246+
let ticket: BlobTicket = ticket.parse()?;
241247

242248
println!("Starting download.");
243249

244-
blobs
250+
blobs_client
245251
.download(ticket.hash(), ticket.node_addr().clone())
246252
.await?
247253
.finish()
@@ -250,22 +256,29 @@ blobs
250256
println!("Finished download.");
251257
```
252258

253-
As a final step, we'll copy the file we just downloaded to the desired file path:
259+
As a final step, we'll export the file we just downloaded into our blobs database to the desired file path:
254260

255261
```rust
256262
println!("Copying to destination.");
257263

258-
let mut file = tokio::fs::File::create(path_buf).await?;
259-
let mut reader = blobs.read_at(ticket.hash(), 0, ReadAtLen::All).await?;
260-
tokio::io::copy(&mut reader, &mut file).await?;
264+
blobs_client
265+
.export(
266+
ticket.hash(),
267+
abs_path,
268+
ExportFormat::Blob,
269+
ExportMode::Copy,
270+
)
271+
.await?
272+
.finish()
273+
.await?;
261274

262275
println!("Finished copying.");
263276
```
264277

265278
<Note>
266-
This first download the file completely into memory, then copy that memory into a file in two steps.
279+
This first downloads the file completely into memory, then copies it from memory to file in a second step.
267280

268-
There's ways to make this work without having to store the whole file in memory, but that involves setting up `Blobs::persistent` instead of `Blobs::memory` and using `blobs.export` with `EntryMode::TryReference`.
281+
There's ways to make this work without having to store the whole file in memory, but those involve setting up `Blobs::persistent` instead of `Blobs::memory` and using `blobs.export` with `EntryMode::TryReference`.
269282
We'll leave these changes as an exercise to the reader 😉
270283
</Note>
271284

@@ -281,5 +294,3 @@ If you're hungry for more, check out
281294
- [other examples](/docs/examples),
282295
- other available [protocols](/proto) or
283296
- a longer guide on [how to write your own protocol](/docs/protocols/writing).
284-
285-
If rust is not actually your jam, make sure to check out the [language bindings](/docs/sdks)!

src/app/docs/tour/1-endpoints/page.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PageLink } from '@/components/PageNavigation';
22

3-
# 2. Endpoints
3+
# 1. Endpoints
44

55
The journey of a connection starts with an endpoint. An endpoint is one of the two termination points for a connection. It’s one of the tin cans that the wire is connected to. Because this is peer-2-peer, endpoints both _initiate_ *and* _accept_ connections. The endpoint handles both.
66

@@ -9,10 +9,10 @@ Let's first add iroh to our project. From the project root run `cargo add iroh`
99
```bash
1010
$ cargo add iroh
1111
Updating crates.io index
12-
Adding iroh v0.31.0 to dependencies
12+
Adding iroh v0.32.1 to dependencies
1313
Features:
14-
+ discovery-pkarr-dht
1514
+ metrics
15+
- discovery-pkarr-dht
1616
- discovery-local-network
1717
- examples
1818
- test-utils
@@ -31,7 +31,7 @@ In the end your `Cargo.toml` file's `[dependencies]` section should look somethi
3131
```toml
3232
[dependencies]
3333
anyhow = "1.0.95"
34-
iroh = "0.31.0"
34+
iroh = "0.32.1"
3535
rand = "0.8.5"
3636
tokio = "1.43.0"
3737
```

src/app/docs/tour/3-discovery/page.mdx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PageLink } from '@/components/PageNavigation';
22

3-
# Discovery
3+
# 3. Discovery
44

55
Discovery is the glue that connects a [Node Identifier](/docs/concepts/endpoint#node-identifiers) to something we can dial. There are a few different types of discovery services, but for all of them you put a `NodeID` in, and get back either the home relay of that node, or IP addresses to dial.
66

@@ -41,27 +41,22 @@ This will change our `Cargo.toml` file `[dependencies]` section to look like thi
4141
```toml
4242
[dependencies]
4343
anyhow = "1.0.95"
44-
iroh = { version = "0.31.0", features = ["discovery-local-network"] }
44+
iroh = { version = "0.32.1", features = ["discovery-local-network"] }
4545
rand = "0.8.5"
4646
tokio = "1.43.0"
4747
```
4848

49-
And with that we can set up local discovery. It does add some complexity to the endpoint setup:
49+
And with that we can set up local discovery:
5050

5151
```rust
52-
use iroh::discovery::local_swarm_discovery::LocalSwarmDiscovery;
5352
use iroh::{Endpoint, RelayMode, SecretKey};
5453

5554
#[tokio::main]
5655
async fn main() -> anyhow::Result<()> {
57-
let key = SecretKey::generate(rand::rngs::OsRng);
58-
let id = key.public();
59-
6056
let builder = Endpoint::builder()
61-
.secret_key(key)
6257
.relay_mode(RelayMode::Default)
6358
.discovery_n0()
64-
.discovery(Box::new(LocalSwarmDiscovery::new(id)?));
59+
.discovery_local_network()
6560

6661
let endpoint = builder.bind().await?;
6762
println!("node id: {:?}", endpoint.node_id());

0 commit comments

Comments
 (0)