Skip to content

Commit d77a3ea

Browse files
authored
fix remaining typos in IRPC blog post (#363)
1 parent e18632a commit d77a3ea

File tree

1 file changed

+11
-11
lines changed

1 file changed

+11
-11
lines changed

src/app/blog/irpc/page.mdx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ impl Client {
7676
}
7777
```
7878

79-
If you want to have some more complex requests, no problem. Here is what a request that adds and entry from a stream would look like:
79+
If you want to have some more complex requests, no problem. Here is what a request that adds an entry from a stream would look like:
8080

8181
```rust
8282
enum Request {
8383
...
84-
SetFromStrean {
84+
SetFromStream {
8585
key: String,
8686
value: mpsc::Receiver<String>,
8787
response: oneshot::Sender<()>,
@@ -170,7 +170,7 @@ async fn server(connection: Connection, store: BTreeMap<String, String>) -> Resu
170170
}
171171
```
172172

173-
This works well for simple requests where there is no update channel and just a single response. But we also want to support requests with updates like `SetFromStrean` and requests with stream responses like `GetAsStream`.
173+
This works well for simple requests where there is no update channel and just a single response. But we also want to support requests with updates like `SetFromStream` and requests with stream responses like `GetAsStream`.
174174

175175
To support this efficiently, it is best to length prefix both the initial request, subsequent updates, and responses. Even if a `Request` "knows" its own size, deserializing from an async stream is very inefficient.
176176

@@ -197,7 +197,7 @@ impl Client {
197197
Ok(rx.await??)
198198
}
199199
Self::Remote(conn) => {
200-
let (send, recv) = connection.open_bi().await?;
200+
let (send, recv) = conn.open_bi().await?;
201201
send.write_all(postcard::to_stdvec(request)?).await?;
202202
let res = recv.read_to_end(1024).await?;
203203
let res = postcard::from_bytes(&res)?;
@@ -222,7 +222,7 @@ But what about all this boilerplate?
222222

223223
It does *not* abstract over the connection type - it only supports [iroh-quinn] send and receive streams out of the box, so the only two possible connection types are `iroh` p2p QUIC connections and normal QUIC connections. It also does not abstract over the local channel type - a local channel is always a `tokio::sync::mpsc` channel. Serialization is always using postcard and length prefixes are always postcard varints.
224224

225-
So let's see what our kv service looks using `irpc`:
225+
So let's see what our kv service looks like using `irpc`:
226226

227227
The service definition contains just what is absolutely needed. For each request type we have to define what the response item type is (in this case `String` or `()`), and what the response channel type is (none, oneshot or mpsc).
228228

@@ -232,7 +232,7 @@ The `rpc_requests` macro will store this information and also create the `Reques
232232
use irpc::channel::oneshot;
233233

234234
struct KvService {}
235-
impl Service for KvStoreService {}
235+
impl Service for KvService {}
236236

237237
#[rpc_requests(KvService, message = RequestWithChannels)]
238238
#[derive(Serialize, Deserialize)]
@@ -265,7 +265,7 @@ use irpc::channel::mpsc;
265265
struct EchoService {}
266266
impl Service for EchoService {}
267267

268-
#[rpc_requests(KvService, message = RequestWithChannels)]
268+
#[rpc_requests(EchoService, message = RequestWithChannels)]
269269
#[derive(Serialize, Deserialize)]
270270
enum Request {
271271
#[rpc(rx=mpsc::Receiver<String>, tx=mpsc::Sender<String>)]
@@ -284,13 +284,13 @@ impl Client {
284284
}
285285
```
286286

287-
Calling echo will write the initial request to the remote, then return a handle `irpc::channel::mpsc::Sender<String>` that can be used to send updates, and a handle `irpc::channel::mpsc::Receiver<String>` to receive the echos.
287+
Calling echo will write the initial request to the remote, then return a handle `irpc::channel::mpsc::Sender<String>` that can be used to send updates, and a handle `irpc::channel::mpsc::Receiver<String>` to receive the echoes.
288288

289-
In the in-process case, sender and receiver are just wrappers around tokio channels. In the networking case, a receiver is a wrapper around a [RecvStream] that reads and deserializes length prefixed messsages, and a sender is a wrapper around a [SendStream] that serializes and writes length prefixed messages.
289+
In the in-process case, sender and receiver are just wrappers around tokio channels. In the networking case, a receiver is a wrapper around a [RecvStream] that reads and deserializes length prefixed messages, and a sender is a wrapper around a [SendStream] that serializes and writes length prefixed messages.
290290

291291
The client fn can then add helper functions that transform these two handles for the update and response end to make the result more convenient, e.g. by converting the result into a futures [Stream] or the updates into a futures [Sink]. But the purpose of irpc is to reduce the boilerplate for defining services that can be used in-process or across processes, not to provide an opinionated high level API.
292292

293-
For stream based rpc calls, there is an issue you should be aware of. The quinn [SendStream] will send a finish message when dropped. So if you have a finite stream, you might want to have an explicit end marker that you send before dropping the sender to allow the remote side to distinguish between successful termination and abnormal termination. E.g. the `SetFromStrean` request from above should look like this, and you should explicitly send a `Done` request after the last item.
293+
For stream based rpc calls, there is an issue you should be aware of. The quinn [SendStream] will send a finish message when dropped. So if you have a finite stream, you might want to have an explicit end marker that you send before dropping the sender to allow the remote side to distinguish between successful termination and abnormal termination. E.g. the `SetFromStream` request from above should look like this, and you should explicitly send a `Done` request after the last item.
294294

295295
```rust
296296
use irpc::channel::{oneshot, mpsc};
@@ -340,7 +340,7 @@ When used purely in-memory, irpc is extremely lightweight when it comes to [depe
340340

341341
## Try it out
342342

343-
If you are writing an `iroh` protocol and have run into the same tedious boiler plate issues around RPC as we have, give [`irpc`](https://docs.rs/irpc/latest/irpc/) a shot. We've spent a lot of time iterating on this issue, in fact this is the second crate we've published that takes a stable at easing the RPC burden. Take a look at the [`quic-rpc`](https://github.com/n0-computer/quic-rpc) if you are curious.
343+
If you are writing an `iroh` protocol and have run into the same tedious boiler plate issues around RPC as we have, give [`irpc`](https://docs.rs/irpc/latest/irpc/) a shot. We've spent a lot of time iterating on this issue, in fact this is the second crate we've published that takes a stab at easing the RPC burden. Take a look at the [`quic-rpc`](https://github.com/n0-computer/quic-rpc) if you are curious.
344344

345345
Because of this extensive experience, we are confident that `irpc` is a good solution for doing both in-process, cross-process, and cross-machine RPC, especially if you are building an `iroh` protocol. Check it out and you will see why we at number0 use it for all of the `iroh` protocols that we have created and maintained.
346346

0 commit comments

Comments
 (0)