WEBVTT

NOTE
This file was generated by Descript <www.descript.com>

00:00:13.817 --> 00:00:15.507
<v Amanda Majorowicz>This
is Self-Directed Research.

00:00:15.677 --> 00:00:19.267
Our hosts, Amos and James, get really
hyped about stuff, and each week they

00:00:19.267 --> 00:00:22.157
take turns presenting their ideas
to each other, usually for longer

00:00:22.157 --> 00:00:23.587
than the 20 minute allotted time.

00:00:23.973 --> 00:00:24.693
Guess what?

00:00:24.833 --> 00:00:27.623
All presentations are now available
for the previous episodes.

00:00:27.853 --> 00:00:33.283
Check it out at sdr-podcast.com/episodes
to see the slide deck for each topic, as

00:00:33.283 --> 00:00:36.803
well as the show notes and transcripts,
which we work hard on to make correct.

00:00:37.023 --> 00:00:38.663
New episodes drop every Wednesday.

00:00:39.178 --> 00:00:42.158
Thank you to Ladybird web browser
for sponsoring this episode too.

00:00:42.418 --> 00:00:45.198
For more information, listen to the
end of the episode and check out

00:00:45.198 --> 00:00:46.558
the description and our show notes.

00:00:47.170 --> 00:00:51.620
This week, James presents, "Talking to
Microcontrollers with Postcard-RPC."

00:00:56.837 --> 00:01:00.617
<v James Munns>Okay, so last time
I mentioned that Postcard-RPC is

00:01:00.617 --> 00:01:05.197
a protocol on top of Postcard,
which is an encoding library.

00:01:05.577 --> 00:01:08.917
And I mentioned that one, it's
called Postcard-RPC, and that there's

00:01:08.917 --> 00:01:10.477
basically two things that it can do.

00:01:10.967 --> 00:01:15.457
But my point this week, and at least
what I figured out from figuring out

00:01:15.467 --> 00:01:19.827
how much I can take away from everything
and still be useful: I found that if you

00:01:19.827 --> 00:01:26.817
have two building blocks, RPC and topics
that you can do almost everything that

00:01:26.827 --> 00:01:28.447
you might want to do with communication.

00:01:28.817 --> 00:01:34.447
I'm excited if you have counterpoints,
or whether this actually is complete,

00:01:34.447 --> 00:01:37.757
but I'm gonna explain what I mean
by these two different pieces.

00:01:38.085 --> 00:01:38.505
<v Amos Wenger>Please do.

00:01:38.787 --> 00:01:41.356
<v James Munns>So RPC is remote
procedure call, which basically

00:01:41.356 --> 00:01:44.706
means pretend that we're doing
a function call over a network.

00:01:45.416 --> 00:01:50.436
This actually has a lot of connotations
into it, like we have a specific client

00:01:50.456 --> 00:01:54.246
and server role, that there's a certain
kind of message that goes from client

00:01:54.256 --> 00:01:58.076
to server, we call that the request,
that there's a certain kind of message

00:01:58.076 --> 00:02:01.286
that goes from the server to the
client, and we call that a response,

00:02:01.716 --> 00:02:04.666
and that every request has a response.

00:02:05.286 --> 00:02:09.776
And this sounds really fundamental, but
it's actually a lot of important little

00:02:09.776 --> 00:02:12.616
pieces that make it easier to think about.

00:02:13.713 --> 00:02:16.603
You can have a bunch of these
in parallel or concurrently or

00:02:16.603 --> 00:02:17.723
however you want to think about it.

00:02:17.913 --> 00:02:21.423
Usually there's some way to say this is
the response that goes with this request.

00:02:21.683 --> 00:02:24.203
There's some way to unwind that
usually with sequence numbers.

00:02:24.323 --> 00:02:28.743
But the goal is that every request
gets its own unique response.

00:02:29.364 --> 00:02:31.864
And the reason that we typically
call it remote procedure call is just

00:02:31.864 --> 00:02:35.764
because it looks like a function call
and we're making it over the network

00:02:35.764 --> 00:02:38.844
and we're pretending that the network
doesn't necessarily exist because

00:02:38.844 --> 00:02:43.804
we want to do the same kind of async
function,  "I give you something, you

00:02:43.814 --> 00:02:45.704
give me back something kind of thing."

00:02:46.144 --> 00:02:51.124
This is used in a ton of different
places like gRPC or JSON-RPC or

00:02:51.534 --> 00:02:57.804
Postcard-RPC, but there's a huge amount
of communication that can be modeled.

00:02:57.834 --> 00:03:00.744
Not that this is the only way of
communicating, but you can reasonably

00:03:00.744 --> 00:03:05.394
address a lot of problems with this
kind of pattern, not everything,

00:03:05.424 --> 00:03:06.414
and I'll get to that, but...

00:03:07.221 --> 00:03:10.531
A lot of stuff really assumes that
you're doing something transactionally.

00:03:10.561 --> 00:03:14.787
And this is something that I think gets
lost in a lot of pub sub or other data

00:03:14.787 --> 00:03:19.497
models or communication models, or even
when you're trying to figure out how

00:03:19.497 --> 00:03:23.237
to get two things inside of your same
program to talk to each other, that

00:03:23.247 --> 00:03:28.257
having sort of this transactionality
and a defined role and the defined

00:03:28.267 --> 00:03:33.221
pieces of this communication is
really useful more often than not.

00:03:33.724 --> 00:03:37.445
I'm interested because you've mentioned
RPC last time and were like, "Ugh, RPC?"

00:03:37.595 --> 00:03:39.182
I'm interested why you
have that, "Ugh, RPC?"

00:03:40.794 --> 00:03:40.956
it.

00:03:42.049 --> 00:03:43.904
<v Amos Wenger>I may have emitted
the wrong "ugh", I was going

00:03:43.954 --> 00:03:45.994
to say you misinterpreted the
"ugh", but it's probably on me.

00:03:46.364 --> 00:03:46.584
No, no, no.

00:03:46.734 --> 00:03:48.544
I've done a lot of RPC before.

00:03:48.901 --> 00:03:52.664
I'm interested specifically- I don't
know how many more slides you've

00:03:52.664 --> 00:03:56.674
got, but the "We are pretending
the network doesn't exist" bit is

00:03:56.674 --> 00:04:01.744
load bearing and there's a lot of
questions of like, "What happens if?"

00:04:01.844 --> 00:04:04.864
And I'm looking forward to ask
them to you, but this can wait

00:04:04.864 --> 00:04:05.984
for later in the presentation.

00:04:05.984 --> 00:04:07.054
If you have more slides.

00:04:07.767 --> 00:04:11.087
<v James Munns>I have some more, but I don't
have the slide that you're looking for.

00:04:11.281 --> 00:04:13.881
It's funny that you mentioned that,
because  in other languages like

00:04:13.931 --> 00:04:18.211
Python or C++ you might, like you said,
just pretend that the network doesn't

00:04:18.211 --> 00:04:20.991
exist and model it as a blocking call.

00:04:21.241 --> 00:04:24.741
But Rust has two pieces that make
it possible to actually bring

00:04:24.741 --> 00:04:26.851
that reality into the code base.

00:04:27.001 --> 00:04:28.071
One is async.

00:04:28.516 --> 00:04:31.526
The fact that this is going to
transactionally take some amount

00:04:31.526 --> 00:04:33.036
of time to get there and back.

00:04:33.706 --> 00:04:37.056
And actually in Postcard-RPC, I
say in this slide that there's

00:04:37.056 --> 00:04:38.646
just returning a response.

00:04:38.956 --> 00:04:42.926
It's actually returning something like
a result, result, result response.

00:04:43.066 --> 00:04:47.212
The first result is, " Is our connection
to that remote thing still live?"

00:04:48.032 --> 00:04:54.036
The second result is, " Did that
foreign entity understand our request?"

00:04:54.056 --> 00:04:56.696
Or did they just say, "I don't even
know what you're asking me about?"

00:04:57.136 --> 00:05:02.026
And then the third result is,
"Did that request succeed and give

00:05:02.026 --> 00:05:03.602
you back a successful response?"

00:05:03.602 --> 00:05:08.197
And because we have nested types
like results, which you might still

00:05:08.197 --> 00:05:11.647
flatten or just want to flatten all
those results down into one result

00:05:11.677 --> 00:05:14.597
and then unwrap it because you
say, I don't care if it goes wrong.

00:05:14.817 --> 00:05:18.757
So you can still pretend if you'd like,
but in Rust we can actually model both

00:05:18.757 --> 00:05:23.047
of those uncanny valley points that
I feel like RPC gets a lot of flack

00:05:23.047 --> 00:05:26.817
for in other languages, where you
have to pretend that it's an immediate

00:05:26.817 --> 00:05:30.797
thing, but it's really blocking until
the request and response comes back.

00:05:31.147 --> 00:05:32.747
But in Rust, we just say that's async.

00:05:32.787 --> 00:05:35.657
We don't know, it could be the
same locally if we're waiting for a

00:05:35.657 --> 00:05:39.607
mutex or waiting for some channel or
waiting for something like that, we

00:05:39.607 --> 00:05:42.537
just know it's going to take a non
zero amount of time, or it's allowed

00:05:42.537 --> 00:05:44.077
to take a non zero amount of time.

00:05:44.427 --> 00:05:48.347
And then because we return a result,
we can model, "Hey, this can fail in

00:05:48.347 --> 00:05:53.287
a bunch of different ways, and you can
decide how granular you want to handle

00:05:53.297 --> 00:05:55.557
all of those different sources of error.

00:05:55.667 --> 00:06:00.644
So actually I think that's a very good
point, but I think Rust with async and

00:06:00.644 --> 00:06:05.446
results, you can care as much as you
want, which is a nice balance to take.

00:06:06.192 --> 00:06:09.042
<v Amos Wenger>I guess I'm
immediately thinking of HTTP and

00:06:09.052 --> 00:06:12.032
for example idempotent requests.

00:06:12.132 --> 00:06:15.332
I was thinking of retrying because
like connections drop, things happen.

00:06:15.676 --> 00:06:18.906
So my first question is where do you put
the responsibility of retrying requests?

00:06:19.441 --> 00:06:23.341
And if it's not on the caller, the end
user of the library, how do you know

00:06:23.341 --> 00:06:25.131
which requests are even safe to retry?

00:06:25.351 --> 00:06:27.711
How do you, you know, communicate that?

00:06:27.721 --> 00:06:28.701
Do you have nonces?

00:06:29.151 --> 00:06:32.198
I hate that this is a word in
British English that doesn't mean the

00:06:32.238 --> 00:06:34.018
same thing as in protocols at all.

00:06:34.175 --> 00:06:34.865
Do you model it?

00:06:34.875 --> 00:06:36.295
Do you just not care
and it's on the caller?

00:06:36.295 --> 00:06:38.765
And if it's on the caller, then
it's not really as transparent as

00:06:38.765 --> 00:06:40.485
like just using an API, then is it?

00:06:40.788 --> 00:06:42.578
<v James Munns>So this is another one
of those where I said that I had to

00:06:42.578 --> 00:06:46.188
realize that  Postcard-RPC should
be a protocol and not an encoding.

00:06:46.748 --> 00:06:50.448
I think there is one more layer
in there, which is network stack.

00:06:50.463 --> 00:06:54.243
And I think I am getting towards this
where the answer is: Postcard-RPC doesn't.

00:06:54.243 --> 00:06:57.213
Right now it's sort of assumes that
every message losslessly gets there

00:06:57.213 --> 00:07:01.623
and back, which is true sometimes,
especially like over USB, it's

00:07:01.623 --> 00:07:05.333
unlikely to lose-lose a message like
you would over a multi-hop network.

00:07:05.843 --> 00:07:08.343
But there are other links like
serial ports that I want to

00:07:08.343 --> 00:07:09.553
support where that's not true.

00:07:09.553 --> 00:07:12.773
You could have corruption of
messages and you need to handle

00:07:12.773 --> 00:07:13.883
retries and things like that.

00:07:14.533 --> 00:07:19.043
I will likely in future episodes
start talking about my research around

00:07:19.053 --> 00:07:23.273
networks . And part of that is looking
at the past of like when the OSI model

00:07:23.273 --> 00:07:27.593
was introduced and contemporaries of
like the 80s and 90s, like AppleTalk,

00:07:27.963 --> 00:07:31.093
which are networking protocols that
are meant to run on, let's say Apple

00:07:31.093 --> 00:07:34.303
machines, which at the time were about
as powerful as today's microcontrollers.

00:07:34.583 --> 00:07:37.293
So we know that they're designed
in a way that is reasonable to

00:07:37.293 --> 00:07:40.573
handle on this amount of computing
and still do everything else

00:07:40.583 --> 00:07:41.573
that they're supposed to do.

00:07:42.263 --> 00:07:45.873
And that's one of my longer term
research items here is to find

00:07:46.273 --> 00:07:49.903
a network stack that I can bring
to a bunch of different devices.

00:07:50.338 --> 00:07:55.428
To get TCP like guarantees of:  Oh, if a
message is lost or corrupted, it's resent.

00:07:55.468 --> 00:07:57.598
There's some way of
doing service discovery.

00:07:57.598 --> 00:07:59.608
There's some way of doing
all of these things.

00:07:59.608 --> 00:08:04.298
So the answer is Postcard-RPC does not
and should not in my opinion, but in

00:08:04.298 --> 00:08:08.098
the same way that I have Postcard-RPC,
which stacks neatly on top of Postcard,

00:08:08.428 --> 00:08:13.218
I should have a network stack that
stacks neatly on top of Postcard-RPC.

00:08:13.428 --> 00:08:17.018
If you go: Well, I'm talking to these
different microcontrollers over a

00:08:17.018 --> 00:08:20.878
bunch of different interfaces and none
of them look like Ethernet or Wi-Fi.

00:08:21.238 --> 00:08:25.908
I want something that feels like TCP
that I can run Postcard-RPC on top

00:08:25.908 --> 00:08:32.598
of, but is much lighter weight or
less burdened with history as TCP is.

00:08:32.995 --> 00:08:33.265
<v Amos Wenger>Yeah.

00:08:33.545 --> 00:08:38.715
I think specifically in the context of
RPC, it makes sense to, again, you're

00:08:38.715 --> 00:08:42.305
going to think all I think about is
HTTP and it's true- boys only want

00:08:42.305 --> 00:08:45.485
one thing and it's a it's an HTTP
implementation fast on top of io_uring.

00:08:45.555 --> 00:08:46.555
And I'm doing that right now.

00:08:46.908 --> 00:08:47.483
<v James Munns>Disgusting.

00:08:47.505 --> 00:08:51.165
<v Amos Wenger>I know, and it's
important to think about: headers

00:08:51.165 --> 00:08:53.935
versus body and head-of-line blocking.

00:08:54.155 --> 00:08:57.735
So I will explain both of these, even
though it's your half I'm taking over.

00:08:58.075 --> 00:09:02.115
So headers versus body is important
because if you think of a server

00:09:02.115 --> 00:09:05.155
processing a request, and this is
very much in the request response

00:09:05.195 --> 00:09:06.985
model you have here on the slides.

00:09:07.615 --> 00:09:10.875
It may have already done the side effect.

00:09:11.295 --> 00:09:12.395
Just reading the headers.

00:09:12.445 --> 00:09:15.795
And even though like there might not be
any request body or there might be one,

00:09:15.795 --> 00:09:19.035
but it's discarding it, or it's just, I
don't know, the effect is already there.

00:09:19.235 --> 00:09:22.925
It's already started doing something
like creating a record with that ID.

00:09:22.925 --> 00:09:25.525
And if you do it again, if you retry,
then it'll fail because that record

00:09:25.525 --> 00:09:28.045
already exists, even though it may
be partial or corrupted because

00:09:28.045 --> 00:09:29.645
the request body actually dropped.

00:09:29.673 --> 00:09:31.293
<v James Munns>I think this
is a semantic of HTTP.

00:09:31.333 --> 00:09:33.243
I think you are absolutely right for HTTP.

00:09:33.613 --> 00:09:36.053
But, I don't think that's
inherent to protocols.

00:09:36.053 --> 00:09:37.723
I think that's inherent to HTTP.

00:09:37.983 --> 00:09:40.623
For example, Postcard-RPC
does have a header.

00:09:40.973 --> 00:09:42.173
It's got two things in it.

00:09:42.243 --> 00:09:46.073
One is a key, which is a hash
of the endpoint name and schema.

00:09:46.883 --> 00:09:48.633
And the second thing is a sequence number.

00:09:49.033 --> 00:09:54.573
There are no verbs in Postcard-RPC's
header like HTTP has, where you

00:09:54.573 --> 00:09:57.873
might have create, delete, whatever.

00:09:58.053 --> 00:10:00.023
The only verbs are within the body itself.

00:10:00.063 --> 00:10:05.563
And this was a choice that I made of not
defining the verbs in the protocol itself.

00:10:05.913 --> 00:10:08.653
So in that case, you would
have to get to the body.

00:10:08.683 --> 00:10:13.003
Like there are, there is a chance in
Postcard-RPC where if you give it a

00:10:13.003 --> 00:10:16.863
key or a sequence number that it's not
expecting, the protocol stack itself

00:10:16.863 --> 00:10:19.823
might not even give that to user space.

00:10:19.843 --> 00:10:23.623
It might immediately say, look, we
have no handlers for that request type.

00:10:23.853 --> 00:10:24.693
So just go away.

00:10:24.873 --> 00:10:26.853
And that was that second result
that I was talking about.

00:10:26.903 --> 00:10:30.963
I think it is important to define
like you were saying, but I think

00:10:30.963 --> 00:10:35.883
what you're describing is a property
of HTTP, not protocols in general.

00:10:35.980 --> 00:10:38.230
<v Amos Wenger>That's definitely,
I'm talking about how HTTP

00:10:38.230 --> 00:10:39.560
solved a specific problem.

00:10:39.560 --> 00:10:45.790
But if we're thinking about Postcard-RPC,
how would you implement something,

00:10:45.820 --> 00:10:48.560
an interface, a service, let's say,
because service is kind of a generic

00:10:48.560 --> 00:10:51.610
RPC term that lets you upload something.

00:10:51.640 --> 00:10:53.840
I can imagine that being
rather than even an embedded.

00:10:53.870 --> 00:10:56.610
Cause like, I don't know, you're, you're
enrolling fingerprints and then you have

00:10:56.610 --> 00:10:58.730
to upload the images scan or something.

00:10:58.980 --> 00:11:02.640
I can see your bias here is that the
payload is small enough that it could

00:11:02.650 --> 00:11:06.370
be all in the request and it's fine,
but I'm thinking, what if it's too big?

00:11:06.470 --> 00:11:08.190
What if it blocks all the other requests?

00:11:08.200 --> 00:11:10.080
Do you have quality of
service going on here?

00:11:10.601 --> 00:11:13.531
<v James Munns>So let me get to the other
primitive cause then I'm going to start

00:11:13.531 --> 00:11:15.421
talking about how I would combine these.

00:11:15.431 --> 00:11:16.721
Cause I, yeah.

00:11:16.971 --> 00:11:18.461
So the first one I've talked about is RPC.

00:11:18.521 --> 00:11:23.851
I think most things will fit in the
RPC box request response, but there are

00:11:23.851 --> 00:11:25.341
a couple of things that super don't.

00:11:25.811 --> 00:11:27.581
And they're opposites of each other.

00:11:27.641 --> 00:11:31.821
And I described these last week as the
stuff you would use WebSockets for.

00:11:32.141 --> 00:11:34.181
Which ends up being about
two different things.

00:11:34.671 --> 00:11:39.051
Either streaming, where you're sending so
much data that it doesn't make sense to

00:11:39.051 --> 00:11:43.051
double the number of packets that you're
going through, that you are just like:

00:11:43.091 --> 00:11:46.421
I'm blasting multiple parts of a transfer.

00:11:47.176 --> 00:11:51.846
Or things that happen very,
very rarely, like notifications.

00:11:52.036 --> 00:11:54.586
So instead of polling,
"Has this event happened?"

00:11:54.816 --> 00:11:57.676
You just leave the connection
open and then 30 seconds in the

00:11:57.676 --> 00:11:59.526
future, you get a, "It happened!"

00:12:00.096 --> 00:12:02.686
And you just send one packet,
like you maybe have some keep

00:12:02.686 --> 00:12:04.466
alive for keeping the socket open.

00:12:04.726 --> 00:12:05.016
But.

00:12:05.511 --> 00:12:08.351
In general, you're not polling like that.

00:12:08.681 --> 00:12:11.811
So the way this works in Postcard-RPC
is again, there's a specific

00:12:11.871 --> 00:12:14.091
type that goes with that message.

00:12:14.301 --> 00:12:17.621
So Postcard-RPC is very opinionated that
everything should be strongly typed.

00:12:18.061 --> 00:12:21.751
And these topic messages
can go in one direction.

00:12:21.981 --> 00:12:26.041
They can either go PC to microcontroller,
or  they can go microcontroller to PC.

00:12:26.311 --> 00:12:30.551
They're always in one direction and
they're always of a given type and there's

00:12:30.581 --> 00:12:33.041
never any chance to respond to these ever.

00:12:33.446 --> 00:12:36.546
They are totally unsolicited,
unidirectional, with no

00:12:36.546 --> 00:12:37.746
acknowledgement or whatever.

00:12:37.786 --> 00:12:42.176
This is more Pub/Sub-y, and the
word topics comes from MQTT,

00:12:42.256 --> 00:12:43.886
which is a Pub/Sub protocol.

00:12:44.176 --> 00:12:47.326
But I really just stole the name more
than semantics or anything like that.

00:12:47.466 --> 00:12:51.006
And at least in Rust, the way we modeled
this is you publish kind of like you would

00:12:51.006 --> 00:12:57.036
send over a channel and you receive by
first subscribing to that topic so that

00:12:57.036 --> 00:13:01.326
you buffer up all the incoming messages
and then you pop them off like messages

00:13:01.336 --> 00:13:03.386
in a bounded channel more or less.

00:13:03.723 --> 00:13:07.153
So these are the only two
primitives in Postcard-RPC.

00:13:07.353 --> 00:13:11.863
These topics have the same header
that RPC endpoints have, in

00:13:11.863 --> 00:13:15.923
that they have the schema of the
message and a sequence number.

00:13:16.243 --> 00:13:19.373
But the idea is that essentially
you can make a lot of other

00:13:19.833 --> 00:13:23.823
fundamental communication
structures by combining these.

00:13:24.223 --> 00:13:28.620
So for example, in a, a demo that I
gave during one of my workshops was

00:13:29.020 --> 00:13:33.090
if you want to start listening to
live streaming data- like you want to

00:13:33.090 --> 00:13:34.650
start listening to an accelerometer-

00:13:34.980 --> 00:13:40.220
you might send an RPC request to start
streaming, that starts the streaming,

00:13:40.570 --> 00:13:43.250
and then you immediately get a response
that says 'I started streaming.'

00:13:43.890 --> 00:13:47.630
And then later you say, 'stop streaming.'
And then you get a response that says

00:13:47.650 --> 00:13:49.680
'I stopped.' And then the stream stops.

00:13:50.270 --> 00:13:55.435
For things like file uploads: you might
say, 'I am going to start a file upload.

00:13:55.465 --> 00:13:59.895
Please give me the stream ID, or
give me some unique ID for this.'

00:14:00.165 --> 00:14:04.055
And then the server says, 'Okay, I am
now listening for that.' And it gives

00:14:04.055 --> 00:14:08.035
you back, 'This is upload number 27.'
You can then start doing a multi part

00:14:08.075 --> 00:14:13.315
upload over topic messages, which
you just include that ID in there,

00:14:13.535 --> 00:14:15.135
and then you just broadcast back.

00:14:15.145 --> 00:14:16.765
And at the end you go, 'I'm done.

00:14:16.865 --> 00:14:20.220
Are you happy or would you like me to
retransmit anything?' And I'm sort of

00:14:20.220 --> 00:14:24.020
saying: well, you can build it yourself
out of sticks and rocks, which is true,

00:14:24.190 --> 00:14:28.920
but at least in embedded, a lot of the
time, people will only need one or two

00:14:28.990 --> 00:14:35.380
fancy things outside of the two basic
structures and having a whole protocol

00:14:35.380 --> 00:14:37.280
library doesn't necessarily make sense.

00:14:37.540 --> 00:14:42.476
I was really inspired by ZeroMQ, which
has a similar sort of approach where

00:14:42.476 --> 00:14:47.816
they say we've got like four or five
messaging and concurrency primitives and

00:14:47.816 --> 00:14:51.606
then we have a cookbook that says: look
if you combine these primitives in this

00:14:51.606 --> 00:14:54.201
way, it will have these characteristics.

00:14:54.211 --> 00:14:55.051
It will do these things.

00:14:55.051 --> 00:14:59.511
And I think I would like to have some
support library items that say like: are

00:14:59.511 --> 00:15:01.141
you going to do this multi part upload?

00:15:01.431 --> 00:15:05.371
Here's a function that does that for
you or a handler that does that for you.

00:15:05.751 --> 00:15:10.001
But the only fundamental building
blocks of the protocol itself are the

00:15:10.001 --> 00:15:16.131
two endpoint and topic items because it
makes the protocol easier to customize

00:15:16.131 --> 00:15:21.181
and easier to reason about when you only
have a couple of fundamental pieces.

00:15:21.536 --> 00:15:23.136
<v Amos Wenger>I have an
immediate question, because

00:15:23.136 --> 00:15:26.186
I'm looking at the code sample that's
been on the screen for a while and

00:15:26.186 --> 00:15:30.906
it has like the publish and subscribe
methods are, how do I pronounce this?

00:15:30.906 --> 00:15:33.006
Parameterized?

00:15:33.006 --> 00:15:33.176
They're

00:15:33.176 --> 00:15:33.686
generic.

00:15:33.994 --> 00:15:35.066
<v James Munns>They're turbofished.

00:15:35.196 --> 00:15:36.056
<v Amos Wenger>They're turbofished.

00:15:36.076 --> 00:15:36.656
Exactly.

00:15:36.886 --> 00:15:37.966
Much easier to pronounce.

00:15:38.216 --> 00:15:42.052
They're turbofished with like
my TX topic and my RX topic.

00:15:42.292 --> 00:15:46.092
This makes it seem like you have a finite
amount of topics, because you have to

00:15:46.092 --> 00:15:47.772
declare all the types ahead of time.

00:15:47.772 --> 00:15:51.167
But you're talking about stream IDs,
because you might want to upload multiple

00:15:51.167 --> 00:15:54.687
files, and not have a fixed number of
upload slots, so how would that work?

00:15:54.983 --> 00:15:59.238
<v James Munns>So endpoints and messages
have what's called this, I call it

00:15:59.288 --> 00:16:03.698
a metadata trait because I realized
that traits are an easy way to couple

00:16:03.998 --> 00:16:06.168
types and constants with each other.

00:16:06.528 --> 00:16:09.648
So when we have an endpoint, they
have a type that is the request, a

00:16:09.648 --> 00:16:12.918
type that it is the response, the
path, which is sort of like the URI.

00:16:13.893 --> 00:16:17.403
And then these keys, which are
that like pre calculated hash

00:16:17.443 --> 00:16:19.883
of essentially schemas and path.

00:16:20.413 --> 00:16:24.443
And the reason that all those functions
get monomorphized like that, or they

00:16:24.443 --> 00:16:29.333
get turbofished like that, is because
if you give it this one marker trait,

00:16:29.918 --> 00:16:31.738
it's got all the information it needs.

00:16:31.758 --> 00:16:35.838
It knows what the request type is,
the response type is, the key that

00:16:35.838 --> 00:16:38.838
it should include in every outgoing
message, the key that it should expect

00:16:38.838 --> 00:16:43.288
in every incoming message, and how to
recreate these keys if they needed to.

00:16:43.658 --> 00:16:46.588
So the answer is you would do it in
user space, in that you would just

00:16:46.588 --> 00:16:50.998
have to have a struct that had a field
that was like 'Upload ID whatever.' So

00:16:51.008 --> 00:16:52.578
it wouldn't be at the protocol level.

00:16:53.098 --> 00:16:54.988
Postcard-RPC wouldn't think about it.

00:16:55.198 --> 00:16:58.058
It would just know: well, if the request
type is this and the response type is

00:16:58.058 --> 00:17:03.280
this, that means that if you subscribe
to this message, I know that it's always

00:17:03.300 --> 00:17:05.620
incoming messages of this specific type.

00:17:05.820 --> 00:17:11.030
So I will just deserialize every incoming
message with that key in this way.

00:17:11.716 --> 00:17:14.156
<v Amos Wenger>So, if we're
thinking about this in terms of

00:17:14.196 --> 00:17:17.611
I guess, existing message buses.

00:17:17.611 --> 00:17:20.271
Cause I've been looking at
this for reasons myself.

00:17:20.281 --> 00:17:23.311
So something like Apache
Kafka or something like this.

00:17:23.971 --> 00:17:28.971
In your case, there's one topic per
like, how do you call it, per key?

00:17:29.161 --> 00:17:32.681
If there's multiple streams, it's
all the user space, like you said,

00:17:32.681 --> 00:17:35.762
it's in the struct, that's in the
body of the messages this topic.

00:17:36.152 --> 00:17:38.552
So again, you're going to
think, all I think about is

00:17:38.552 --> 00:17:40.352
HTTP and that may well be true.

00:17:40.642 --> 00:17:45.242
But one nice feature of HTTP/2
for all sins is that if you don't

00:17:45.242 --> 00:17:49.832
care about a stream anymore, you
can tell the other peer to stop.

00:17:50.812 --> 00:17:53.482
Cause you've made it very clear
that like topics are unidirectional.

00:17:53.862 --> 00:17:58.032
So in a world where everyone's
well behaved, and I think that's

00:17:58.052 --> 00:18:00.562
also an assumption you're making
because I think in your line of

00:18:00.562 --> 00:18:03.422
work, you control both ends of the
connection, but in my world, we don't.

00:18:03.442 --> 00:18:04.937
In my world, the peer is the enemy.

00:18:05.031 --> 00:18:06.361
<v James Munns>Yeah, that's a good point.

00:18:06.597 --> 00:18:09.207
<v Amos Wenger>It's important when
there's an upload coming in and

00:18:09.207 --> 00:18:11.577
you're like: no, no, no, you can
stop, you just reset the stream.

00:18:11.577 --> 00:18:13.462
And you say, don't- don't
send me this anymore.

00:18:13.472 --> 00:18:17.052
And if they don't stop at that,
then it's a protocol error.

00:18:17.052 --> 00:18:19.284
You can just sever the
underlying connection.

00:18:19.284 --> 00:18:21.514
<v James Munns>That's also a layer that
I don't have, but is a good point

00:18:21.514 --> 00:18:24.409
that I'm going to have to have is
the difference between- like when

00:18:24.409 --> 00:18:28.719
you have a fixed USB connection,
there's no hanging up the socket.

00:18:28.739 --> 00:18:29.889
There's actually no socket.

00:18:29.899 --> 00:18:31.459
There's just messages coming in.

00:18:31.679 --> 00:18:34.319
There's an implicit bi directional socket.

00:18:34.319 --> 00:18:36.999
And this is one of those things I have
to start getting into once you want

00:18:37.279 --> 00:18:39.879
routing or passing the messages on.

00:18:39.879 --> 00:18:43.779
Like if I'm connected over USB, but
then I have someone connected to me

00:18:43.789 --> 00:18:47.669
and I want to forward messages on,
you start needing that concept of a

00:18:47.669 --> 00:18:49.969
socket that I don't have right now.

00:18:50.029 --> 00:18:52.013
In a lot of embedded
systems it isn't relevant.

00:18:52.043 --> 00:18:55.553
You're just directly connected, like
you said, you control both sides,

00:18:55.823 --> 00:18:58.693
which I'm cheating by ignoring a lot.

00:18:58.693 --> 00:19:02.573
And I think that's a really good point
on the difference between HTTP and what

00:19:02.573 --> 00:19:04.693
I would typically use Postcard-RPC for.

00:19:05.254 --> 00:19:08.934
<v Amos Wenger>Yeah, and like you said, I
keep bringing up HTTP semantics, but I

00:19:08.944 --> 00:19:13.174
think those are useful to have, because,
you know, there's a standard way to

00:19:13.174 --> 00:19:16.844
signify, you know, if you have a 2XX
status code, things probably went well.

00:19:17.154 --> 00:19:21.074
If it's 100, you got something else to do,
400, it's your fault, 500, it's my fault.

00:19:21.374 --> 00:19:27.119
And then, you know, in terms of caching-
I think caching is probably the thing

00:19:27.119 --> 00:19:30.629
I'm going to have the hardest time
selling you- but at least retrying or

00:19:30.629 --> 00:19:34.939
like migrating ongoing streams to another
connection or transport or something.

00:19:35.349 --> 00:19:37.009
Yeah, so those semantics
are here for a reason.

00:19:37.009 --> 00:19:40.560
I think specifically you're making  g the
extreme choice of like leaving as much

00:19:40.560 --> 00:19:46.163
as possible to user space, but that will
make it harder to implement something

00:19:46.163 --> 00:19:48.273
on- well, I, yeah, I guess maybe not.

00:19:48.273 --> 00:19:48.543
Yeah.

00:19:48.671 --> 00:19:50.094
<v James Munns>Have you ever heard of CoAP?

00:19:50.146 --> 00:19:51.396
<v Amos Wenger>No, what is that?

00:19:51.656 --> 00:19:57.420
<v James Munns>CoAP is a really cool
protocol that is like HTTP light.

00:19:57.900 --> 00:20:00.580
It's a little binary focused
in that they use CBOR instead

00:20:00.580 --> 00:20:02.080
of text for a lot of things.

00:20:02.080 --> 00:20:06.620
But it's funny because if you read
how CoAP is specified, it's an

00:20:06.630 --> 00:20:10.970
interesting midpoint between where
Postcard-RPC is and HTTP is, in that

00:20:10.970 --> 00:20:13.260
it has a lot of the semantics of HTTP.

00:20:13.440 --> 00:20:17.470
It has the binary interfaces
of Postcard-RPC with a

00:20:17.470 --> 00:20:18.480
slightly different encoding.

00:20:18.480 --> 00:20:21.550
But you can tell that there's
CoAP sort of in the middle.

00:20:21.550 --> 00:20:25.480
And I looked at that and I thought
about making a CoAP library to pick HTTP

00:20:25.500 --> 00:20:29.670
semantics because it gives you out of
the box answers of what happens when I

00:20:29.670 --> 00:20:34.000
want to do caching, what  happens when I
want to do proxying or reverse proxying?

00:20:34.280 --> 00:20:37.850
Because you can just say, "Well, we do it
like HTTP," and people will understand it.

00:20:37.860 --> 00:20:41.445
And I think that is a very
worthwhile approach to it.

00:20:41.775 --> 00:20:44.875
And I think like you said
I've made a different choice.

00:20:45.115 --> 00:20:46.895
I don't know if that's a good one yet.

00:20:47.165 --> 00:20:50.455
And I think everyone who I show it to
like Tef or whoever, I explained to them

00:20:50.455 --> 00:20:53.775
what I'm doing with Postcard-RPC and they
go, "You realize you're just making like

00:20:53.775 --> 00:20:55.645
a more limited version of CoAP, right?"

00:20:55.675 --> 00:20:57.885
And I go, "Yes on purpose."

00:20:57.955 --> 00:21:01.935
and this is why I got so surprised when
people asked me if I could do Postcard-RPC

00:21:01.955 --> 00:21:06.145
over HTTP, which is something someone
asked me at RustNL, and I go, " The

00:21:06.145 --> 00:21:10.755
whole point of Postcard-RPC is to be
the minimal rope bridge to cross a

00:21:10.755 --> 00:21:12.335
chasm when there's nothing there."

00:21:12.555 --> 00:21:17.655
Like, if there's no roads or bridges
or infrastructure crossing a chasm, I

00:21:17.655 --> 00:21:21.300
want it to be something that you can
just throw over, tie it off on both

00:21:21.300 --> 00:21:24.640
sides and it will work, and as long as
you're just walking back and forth, it

00:21:24.640 --> 00:21:28.090
will be everything you need and it will
be so lightweight and so easy to use.

00:21:28.420 --> 00:21:34.340
When you want a performant server
interface, or if you already have like

00:21:34.340 --> 00:21:39.010
a paved road from here to there, there's
no point in putting Postcard-RPC on top

00:21:39.010 --> 00:21:42.250
of it because you're better served by
the infrastructure that's already there.

00:21:42.625 --> 00:21:46.525
But I do a lot of that, like 'throw
the ropes over a chasm that has nothing

00:21:46.525 --> 00:21:48.175
built across it yet' sort of thing.

00:21:48.415 --> 00:21:52.535
Or I need to draw up blueprints of a
bridge and it's faster to just chuck

00:21:52.535 --> 00:21:56.005
the rope across the chasm, than draw
up the blueprints for a bridge and

00:21:56.005 --> 00:21:59.115
making sure that both sides are load
bearing, you know, it's a weird extended

00:21:59.115 --> 00:22:04.873
metaphor now, but the goal is to be
the dumbest, simplest working thing

00:22:05.533 --> 00:22:07.473
that works reliably and predictably.

00:22:07.673 --> 00:22:10.563
And if you need more than that, I will
probably say, "Either do it in user

00:22:10.563 --> 00:22:12.743
space or don't do it with Postcard-RPC."

00:22:13.133 --> 00:22:16.803
But the goal is to have something that
like, if you have nothing, I will give you

00:22:16.823 --> 00:22:19.493
minimum viable semantics for a protocol.

00:22:19.770 --> 00:22:23.860
<v Amos Wenger>I guess the question of
'can we do Postcard-RPC on top of HTTP'

00:22:23.870 --> 00:22:30.260
is not that weird because people do
gRPC on top of HTTP, which makes me

00:22:30.300 --> 00:22:34.320
really sad and I thought I was going
to be able to ignore all my life.

00:22:34.585 --> 00:22:38.315
As you do, but then I dealt with
Docker and they do exactly that.

00:22:38.345 --> 00:22:41.245
Like you make an HTTP/1 connection, then
you switch protocols and then, "Ta da!

00:22:41.245 --> 00:22:42.245
It's gRPC now!"

00:22:42.935 --> 00:22:44.184
<v James Munns>over HTTP/2.

00:22:44.674 --> 00:22:45.945
<v Amos Wenger>I think it was just a HTTP/1.

00:22:46.278 --> 00:22:48.684
Cause like the switching protocols
thing is an HTTP/1 thing.

00:22:48.684 --> 00:22:49.304
HTTP/2

00:22:50.894 --> 00:22:51.634
why would you do-

00:22:51.672 --> 00:22:52.782
<v James Munns>It's ALPN.

00:22:52.802 --> 00:22:57.252
So then you switch to either HTTP/2 or
gRPC, but there's definitely people doing

00:22:57.252 --> 00:23:01.912
gRPC over HTTP/2, because they want the
multiplex streams and they want to be able

00:23:01.912 --> 00:23:03.502
to do those kinds of things over there.

00:23:03.502 --> 00:23:06.693
Where I know it was a question
that came up for River of: will

00:23:06.693 --> 00:23:11.643
River do regular TCP proxying, but
also gRPC proxying specifically.

00:23:11.913 --> 00:23:16.033
You could just pretend that it's just
HTTP/2, but there's some stuff where

00:23:16.033 --> 00:23:21.223
if you wanted to be able to peek
specifically into gRPC structures and

00:23:21.223 --> 00:23:25.193
things like that, you may not want
to pretend that it's strictly HTTP/2.

00:23:25.684 --> 00:23:26.284
<v Amos Wenger>Yeah, exactly.

00:23:26.304 --> 00:23:29.004
You can either like pass through,
but then you don't have any

00:23:29.004 --> 00:23:31.244
insights on what's going on, or
you can deserialize everything

00:23:31.244 --> 00:23:32.924
and then reserialize it whatever.

00:23:32.924 --> 00:23:34.254
And then you pay the cost of that.

00:23:34.514 --> 00:23:39.991
I guess a better competition
for Postcard-RPC is tarpc.

00:23:40.014 --> 00:23:41.034
I don't know if you're aware of it?

00:23:41.164 --> 00:23:43.001
<v James Munns>I've heard of it
before, but I'm not familiar with it.

00:23:43.682 --> 00:23:46.032
<v Amos Wenger>You should check
it out before next week.

00:23:46.032 --> 00:23:50.242
No, I don't assign a work to
you but I could, I should!

00:23:50.762 --> 00:23:53.922
I think, for the record, I haven't
read through the entire Postcard-RPC

00:23:53.942 --> 00:23:55.862
README, but I really liked the ZeroMQ.

00:23:55.882 --> 00:23:58.132
Maybe it only speaks to me
because I know what ZeroMQ is.

00:23:58.132 --> 00:24:01.902
I was really hyped about it back when
I wrote bindings for several languages.

00:24:01.971 --> 00:24:05.107
<v James Munns>I didn't steal anything
specifically from ZeroMQ, other than

00:24:05.137 --> 00:24:09.047
that concept of have a couple primitives
and then a cookbook, rather than

00:24:09.057 --> 00:24:13.507
trying to specify the long tail of
every possible usage of your protocol.

00:24:13.567 --> 00:24:17.188
<v Amos Wenger>Right, but starting with like
what it's not is A really good strategy

00:24:17.188 --> 00:24:22.708
for open source, because since one of
the working names for the podcast is like

00:24:22.708 --> 00:24:24.358
"open source research hype" or whatever.

00:24:24.768 --> 00:24:29.758
The best piece of advice I can tell anyone
who's looking to like gather hype around

00:24:29.758 --> 00:24:33.518
a project is be extremely honest about
what it's not what it's not doing yet.

00:24:33.868 --> 00:24:35.988
Don't put your wishlist on the README.

00:24:35.988 --> 00:24:37.677
Keep it on your wishlist.

00:24:38.025 --> 00:24:39.425
<v James Munns>Expectation management.

00:24:39.765 --> 00:24:40.255
<v Amos Wenger>Exactly.

00:24:40.675 --> 00:24:44.622
Because people will get excited about
even reasonably sized miracles, but

00:24:44.682 --> 00:24:48.872
it's really hard to over promise and
deliver later in open source land.

00:24:48.932 --> 00:24:51.532
I think specifically for this
one, yeah: all those questions

00:24:51.532 --> 00:24:52.332
are going to keep coming up.

00:24:52.342 --> 00:24:55.852
There's dozens of people who are into
HTTP semantics, I'll have you know.

00:24:55.852 --> 00:24:58.022
So you will get those questions
from other people again.

00:24:58.825 --> 00:25:00.305
<v James Munns>And I'm looking for the
people who are interested in TCP and

00:25:00.305 --> 00:25:05.325
UDP semantics because when I start doing
the exact same treatment to a network

00:25:05.325 --> 00:25:08.835
stack that I'm doing to a protocol
stack right now, where I go, "How little

00:25:08.845 --> 00:25:13.305
of a protocol can I get away with and
still call it a protocol that works?"

00:25:13.545 --> 00:25:17.250
And there will be those comparisons
of: why didn't you do it like TCP,

00:25:17.250 --> 00:25:21.520
or why didn't you do it like UDP,
or why didn't you do it like TCP/IP.

00:25:21.560 --> 00:25:24.810
And I have no answer for that at
all right now, because I haven't

00:25:24.810 --> 00:25:26.520
even figured how minimal I can get.

00:25:26.540 --> 00:25:28.668
And I think that's the baseline
that I'm going to have to play with.

00:25:28.942 --> 00:25:34.133
In Embedded Rust, we have a TCP/IP stack
called smoltcp, which is really good and

00:25:34.133 --> 00:25:37.273
very performant, and has some limitations.

00:25:37.273 --> 00:25:41.618
Like, it doesn't really address
networking necessarily, like having two

00:25:41.628 --> 00:25:44.388
interfaces and doing routing between them.

00:25:44.568 --> 00:25:48.758
It's more like I've set up one specific
interface that's Wi-Fi or Ethernet

00:25:49.038 --> 00:25:51.668
or whatever and I'm talking to it.

00:25:51.928 --> 00:25:55.708
And really that's sort of my baseline
of does what I've actually produced:

00:25:55.708 --> 00:26:00.248
is it smaller, and is it faster and is
it more resource efficient than just

00:26:00.248 --> 00:26:05.088
doing TCP over a weird interface, like
there's SLIP for serial ports, there's

00:26:05.088 --> 00:26:07.628
a bunch of different serial ports or
buses that I could implement it for.

00:26:07.628 --> 00:26:11.928
I could implement just weird
PHY level stuff and pretend that

00:26:11.928 --> 00:26:15.838
it's just weird Ethernet over
some weird thing like SLIP is.

00:26:16.378 --> 00:26:19.848
And that's what I really have to
sort of test myself against of: would

00:26:19.848 --> 00:26:25.663
I have been better off just doing
IPv4 with UDP over my weird esoteric

00:26:25.663 --> 00:26:28.493
serial ports than trying to come up
with a whole new network protocol.

00:26:28.863 --> 00:26:32.433
Like you asked in our last
conversation: would I do this again?

00:26:32.913 --> 00:26:35.563
And the answer is: I'm always going
to reinvent wheels just for fun,

00:26:35.583 --> 00:26:37.143
because that's what I enjoy doing.

00:26:37.243 --> 00:26:41.299
So I'm going to reinvent this wheel,
but I give myself maybe happily a 50

00:26:41.299 --> 00:26:44.539
50 shot at the end of me just going,
"Oh, I've made a worse version of this.

00:26:44.569 --> 00:26:44.869
Okay.

00:26:44.869 --> 00:26:46.599
Well, that was very instructive,"
and I'm going to put it on a

00:26:46.599 --> 00:26:47.819
shelf and never use it again.

00:26:48.434 --> 00:26:51.314
Or use some of the ideas for
something else, but I think

00:26:51.314 --> 00:26:52.484
I'm going to see it through.

00:26:52.504 --> 00:26:54.334
I don't know whether it's actually
going to be better than the

00:26:54.334 --> 00:26:59.144
baseline of TCP/IP, but, uh, that's
what the research is for, right?

00:26:59.741 --> 00:27:01.141
<v Amos Wenger>Yeah, well,
I'm looking forward to it.

00:27:06.492 --> 00:27:08.832
This episode is sponsored
by Ladybird browser.

00:27:09.252 --> 00:27:13.552
Today, every major web browser is funded
or powered by Google's advertising empire.

00:27:13.752 --> 00:27:15.812
Choice is good, but your
only choice is Google.

00:27:16.152 --> 00:27:18.662
The Ladybird browser wants
to do something about this.

00:27:19.062 --> 00:27:22.142
Ladybird is a brand new browser and
web engine written from scratch and

00:27:22.142 --> 00:27:23.992
free of the influences of Big Tech.

00:27:24.552 --> 00:27:27.052
Driven by web standards first
approach, Ladybird aims to

00:27:27.052 --> 00:27:30.762
render the modern web with good
performance, stability, and security.

00:27:31.004 --> 00:27:34.854
From its humble beginnings as an HTML
viewer for the SerenityOS hobby operating

00:27:34.854 --> 00:27:38.814
system project, Ladybird has since grown
into a cross-platform browser supporting

00:27:38.814 --> 00:27:41.384
Linux, macOS, and other Unix like systems.

00:27:41.974 --> 00:27:45.644
In July, Ladybird launched a non-profit
to support development and announced a

00:27:45.644 --> 00:27:49.674
first Alpha for early adopters targeting
2026, but you can support the project

00:27:49.674 --> 00:27:51.804
on GitHub or via donations today.

00:27:52.304 --> 00:27:55.514
Visit ladybird.org for more information
and to join the mailing list.

00:27:56.154 --> 00:27:59.034
Thanks to Ladybird for
sponsoring today's episode.

