Skip to content
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

Merged
merged 8 commits into from
Oct 25, 2024
Merged

feat!: introduce iroh-router crate #2832

merged 8 commits into from
Oct 25, 2024

Conversation

dignifiedquire
Copy link
Contributor

@dignifiedquire dignifiedquire commented Oct 23, 2024

The general goal is to have a single place to deal with custom protocols.

Breaking Changes

  • moved
    • iroh::node::ProtocolHandler -> iroh::router::ProtocolHandler

Copy link

github-actions bot commented Oct 23, 2024

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

Copy link

github-actions bot commented Oct 23, 2024

Netsim report & logs for this PR have been generated and is available at: LOGS
This report will remain available for 3 days.

Last updated for commit: 2255227

@rklaehn
Copy link
Contributor

rklaehn commented Oct 24, 2024

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?

@rklaehn
Copy link
Contributor

rklaehn commented Oct 24, 2024

Alternative to the add/remove stuff.

add(alpn: Vec, proto: ...) returns a handle. The handle is not cloneable. Get takes a &handle, remove - if we ever do it - takes a handle. The handle is a newtype for an u64.

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.

@dignifiedquire
Copy link
Contributor Author

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.

@dignifiedquire
Copy link
Contributor Author

The biggest "decision" I made, is currently the endpoint is constructed on its own, rather than by the RouterBuilder. This makes this PR simpler, but we probably want to change that down the line 🤷 to be more like the current NodeBuilder.

@rklaehn
Copy link
Contributor

rklaehn commented Oct 24, 2024

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.

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.

@rklaehn
Copy link
Contributor

rklaehn commented Oct 24, 2024

The biggest "decision" I made, is currently the endpoint is constructed on its own, rather than by the RouterBuilder. This makes this PR simpler, but we probably want to change that down the line 🤷 to be more like the current NodeBuilder.

I don't hate it, especially now that iroh-router is a separte crate.

iroh-router/Cargo.toml Show resolved Hide resolved
Comment on lines 158 to 161
// 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?;
Copy link
Contributor

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;

Copy link
Contributor Author

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

Copy link
Contributor

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!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 192 to 195
// 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?;
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

Copy link
Contributor Author

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.
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ups

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

iroh-router/examples/custom-protocol.rs Show resolved Hide resolved
iroh-router/src/router.rs Outdated Show resolved Hide resolved
}
}
Some(Ok(Err(inner))) => {
debug!("Task errored: {inner:?}");
Copy link
Contributor

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.

let cancel = CancellationToken::new();
let cancel_token = cancel.clone();

let fut = async move {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let fut = async move {
let run_loop_fut = async move {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines +181 to +185
endpoint
.clone()
.close(error_code.into(), b"provider terminating"),
// Shutdown protocol handlers.
protocols.shutdown(),
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@dignifiedquire dignifiedquire marked this pull request as ready for review October 24, 2024 09:48
@flub
Copy link
Contributor

flub commented Oct 24, 2024

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.

@dignifiedquire
Copy link
Contributor Author

But I do think the router has to figure out some bits that I bring up before 1.0.

yes, this is not meant as any form of final API

Cargo.toml Outdated
@@ -7,7 +7,7 @@ members = [
"iroh-net",
"iroh-test",
"iroh-net/bench",
"iroh-cli",
"iroh-cli", "iroh-router",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting is weird btw

Copy link
Contributor Author

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).
Copy link
Contributor

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...

@dignifiedquire dignifiedquire changed the title feat: introduce iroh-router crate feat!: introduce iroh-router crate Oct 24, 2024
@dignifiedquire dignifiedquire added this pull request to the merge queue Oct 25, 2024
Merged via the queue into main with commit 8f75005 Oct 25, 2024
27 of 29 checks passed
@dignifiedquire dignifiedquire deleted the feat-router branch October 25, 2024 11:43
matheus23 pushed a commit that referenced this pull request Nov 14, 2024
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants