-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat!: introduce iroh-router crate #2832
Conversation
Documentation for this PR has been generated and is available at: https://n0-computer.github.io/iroh/pr/2832/docs/iroh/ Last updated: 2024-10-24T11:52:11Z |
As an extraction of the router api this looks fine. We can bikeshed the router API, but I guess that is for the next PR. Generated the router docs, and it is a very nice small API. However, I don't like that getting a protocol handler can fail. We could change the API to return a typed handle so you can be sure that the get succeeds. However, that would make the builder API slightly more annoying. Also, should we allow adding removing ALPNs dynamically? |
Alternative to the add/remove stuff. add(alpn: Vec, proto: ...) returns a handle. The handle is not cloneable. Get takes a Upside: get can be made to return a Thing instead of an Option. You can mount the same protocol multiple times under different ALPNs (perfectly valid IMHO). Downside: complicates the builder API since you need to return the handle and the new version of the builder, or do a mutable builder API. |
There will be quite a few cases, eg with dependent protocols, where you will not have a handle available, (without very annoying handling) and in the ffi world this becomes even more painful, so I don't think these handles are worth it. |
The biggest "decision" I made, is currently the endpoint is constructed on its own, rather than by the |
You can just pass in the handle when constructing the protocol. It's just an int64 newtype. Regarding ffi I don't know how that looks, so I can't properly answer. Can you describe the problem? Anyway, as I mentioned this discussion is for later. |
I don't hate it, especially now that iroh-router is a separte crate. |
// By calling stopped we wait until the remote iroh Endpoint has acknowledged | ||
// all data. This does not mean the remote application has received all data | ||
// from the Endpoint. | ||
send.stopped().await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is helpful. This handles the entire connection, so this should be waiting until the remote closes the connection:
// Wait until the remote closes the connection, which it does once it
// received the response.
connection.closed().await;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is copied from the other custom-protocol example, so no idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, let's improve our examples!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
// By calling stopped we wait until the remote iroh Endpoint has acknowledged all | ||
// data. This does not mean the remote application has received all data from the | ||
// Endpoint. | ||
send.stopped().await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think adding this is helpful. The protocol requires a response anyway, you should go straight to reading that response. Adding this does no harm but I think it confuses people, we should keep examples as minimal to be correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
Err(err) => return Err(err.into()), | ||
Ok(_) => {} | ||
}; | ||
// Upcast the raw bytes to the `Hash` type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're casting to a u64, not to Hash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ups
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
} | ||
} | ||
Some(Ok(Err(inner))) => { | ||
debug!("Task errored: {inner:?}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an anyhow::Error
I think, should use alt formatting for those when logging: {inner:#}
.
Possibly the others are also better at alt formatting? But I'm not sure, would have to try it. For the Task panicked
we certainly want to make sure to log the backtrace.
iroh-router/src/router.rs
Outdated
let cancel = CancellationToken::new(); | ||
let cancel_token = cancel.clone(); | ||
|
||
let fut = async move { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let fut = async move { | |
let run_loop_fut = async move { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
endpoint | ||
.clone() | ||
.close(error_code.into(), b"provider terminating"), | ||
// Shutdown protocol handlers. | ||
protocols.shutdown(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By doing this in a join you're making it a bit non-deterministic whether the protocol handlers will still have an endpoint when their .shutdown()
is being called.
I'm in two minds on whether the router should be closing the endpoint (given the earlier API/commen of how you pass a clone of the endpoint to the router which makes it seem like you still own it). If it does however I think it might be best to do this at the very end once all other tasks from this router are stopped. This would give protocols the possibility of doing a much cleaner shutdown themselves. Maybe a protocol still wants to exchange some messages with the peer saying "i'm going to close now" or something similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the exact some shutdown routine that we currently have in the iroh
node, I am okay in changing it if we think this is needed, but lets do this separately please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed that we shouldn't change this in this PR, but want to comment on this:
Is this where we should implement a endpoint.all_closed().await
instead?
iroh/src/node.rs
Outdated
@@ -112,10 +110,10 @@ pub struct Node<D> { | |||
// So we need | |||
// - `Shared` so we can `task.await` from all `Node` clones | |||
// - `MapErr` to map the `JoinError` to a `String`, because `JoinError` is `!Clone` | |||
// - `AbortOnDropHandle` to make sure that the `task` is cancelled when all `Node`s are dropped | |||
// - `AbortOnDropHandle` to make sure that the `task` is cancelled when all `Node`s are droppedo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
If the goal is just to move code around, I'm fine with this. But I do think the router has to figure out some bits that I bring up before 1.0. |
Co-authored-by: Floris Bruynooghe <flub@n0.computer>
yes, this is not meant as any form of final API |
6c277b2
to
01de8db
Compare
Cargo.toml
Outdated
@@ -7,7 +7,7 @@ members = [ | |||
"iroh-net", | |||
"iroh-test", | |||
"iroh-net/bench", | |||
"iroh-cli", | |||
"iroh-cli", "iroh-router", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
formatting is weird btw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks cargo
...
// - `Shared` so we can `task.await` from all `Node` clones | ||
// - `MapErr` to map the `JoinError` to a `String`, because `JoinError` is `!Clone` | ||
// - `AbortOnDropHandle` to make sure that the `task` is cancelled when all `Node`s are dropped | ||
// (`Shared` acts like an `Arc` around its inner future). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which would prevent shutdown
from being called as it consumes self
...
The general goal is to have a single place to deal with custom protocols. ## Breaking Changes - moved - `iroh::node::ProtocolHandler` -> `iroh::router::ProtocolHandler` --------- Co-authored-by: Floris Bruynooghe <flub@n0.computer>
The general goal is to have a single place to deal with custom protocols.
Breaking Changes
iroh::node::ProtocolHandler
->iroh::router::ProtocolHandler