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

Add an example showcasing how to implement a custom network behavior and access streams #4983

Closed
wants to merge 9 commits into from

Conversation

eserilev
Copy link
Contributor

@eserilev eserilev commented Dec 5, 2023

Description

#4457

An example that serves as a copy past-able snippet for users that want to access a stream. Also documents how to implement a custom network behavior.

The example should:

  • Have a binary and a library component
  • Binary listens on a random port and prints listen address
  • Binary accepts an address to dial and connects to it
  • Binary opens a stream, send 32 random bytes, waits for the echo and closes again

Notes & open questions

This is currently a draft PR, I will add more details as my work progresses

Change checklist

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • A changelog entry has been made in the appropriate crates

@eserilev eserilev changed the title Feature/escape hatch example Add an example showcasing how to implement a custom network behavior and access streams Dec 5, 2023
@eserilev
Copy link
Contributor Author

eserilev commented Dec 6, 2023

I'm trying to understand how to implement Control.

A control acts as a "remote" that allows users to request streams without interacting with the Swarm directly.

open_stream should open a new 'stream' and return it, without needing to interact with the swarm directly. I'm taking this to mean that we shouldn't be using the Swarm abstraction at all in this example were building. Therefore I have a snippet of code that just creates a TcpStream and returns it. I'm not really sure what to do with the PeerId though, how were you envisioning this function should look like?

@thomaseizinger
Copy link
Contributor

A control acts as a "remote" that allows users to request streams without interacting with the Swarm directly.

open_stream should open a new 'stream' and return it, without needing to interact with the swarm directly. I'm taking this to mean that we shouldn't be using the Swarm abstraction at all in this example were building.

We still want to use Swarm or to be precise, the NetworkBehaviour interface:

  • Behaviour needs to implement NetworkBehaviour
  • Control should use channels to talk to the NetworkBehaviour and / or ConnectionHandler for requests such as open_stream

Something along the lines of:

  • When the user calls open_stream on Control, we need to send a message into a channel that gets read by the NetworkBehaviour within its poll function.
  • This request then needs to be forwarded to an appropriate ConnectionHandler, i.e. one that is connected to a peer with the PeerId provided by the user.
    • If we are not connected to this peer, we probably want to return an error through a oneshot back to the future that we returned from Control::open_stream
    • If we are connected, we can forward the oneshot to the appropriate ConnectionHandler and have it open a stream. The stream can then be sent back to the Control.

The main thing we want to achieve is not having users use the Swarm APIs as those are synchronous but we want to offer an async/await based interface (without re-implementing all of rust-libp2p). Thus, the example you are working on can be seen as a "adapter" that bridges between the async/await world and the synchronous state machine world of rust-libp2p.

Let me know if that makes sense! :)


impl Behaviour {
pub fn new(protocol: StreamProtocol) -> (Self, Control, IncomingStreams) {
let (sender, receiver) = mpsc::channel::<StreamMessage>();
Copy link
Contributor

Choose a reason for hiding this comment

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

The receiver needs to go into Behaviour so you can call poll_next on it and actually act on the message from the Control.

Comment on lines +73 to +77
if let Some(e) = self.events.pop_back() {
} else {
}

todo!()
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to Control::open_stream, this needs to listen on an mpsc::Receiver where the mpsc::Sender lives in Behaviour. Any inbound streams from the ConnectionHandler need to be sent this one.

@thomaseizinger
Copy link
Contributor

@eserilev Let me know what your appetite is for continuing to work on this. I'll be stepping down as a maintainer soon and offering this capability is something that would be great to land as a final action. If you are okay with it, I'd be happy to take over from here :)

@eserilev
Copy link
Contributor Author

@thomaseizinger feel free to take it from here, thanks for all the help!!

@thomaseizinger
Copy link
Contributor

@thomaseizinger feel free to take it from here, thanks for all the help!!

Okay, thanks!

@thomaseizinger
Copy link
Contributor

Going to close this for now and start my own branch.

@thomaseizinger
Copy link
Contributor

Continuing here: #5027.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants