-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Document and/or improve swarm event handling #1876
Comments
While it's not documented, this is indeed the intention. |
Thanks, that's good enough for us right now, I think. It'd still be nice to have it documented (I do realize the whole Rust ecosystem is lacking on that front though). |
I don't think this is a good idea. If my understanding is correct then precisely the fact that I am not sure if that would be possible if |
@tomaka Would it be an acceptable change to make |
Would To reduce the complexity of
The former |
@mxinden yes, I like you suggested changes for |
That would be very much appreciated @elenaf9! |
I'm integrating libp2p into bevy and having some troubles with it. Because bevy uses ECS, I have a system that poll swarm event every frame. However, it doesn't connect when I try to dial another swarm in localhost. I managed to reproduce the issue without bevy by polling swarm event in a loop like this:
loop {
match swarm.next_event().now_or_never() {
Some(event) => println!("Event: {:?}", event),
None => (),
}
thread::sleep(Duration::from_secs_f32(0.01));
}
loop {
let waker = futures::task::noop_waker();
let mut cx = Context::from_waker(&waker);
match swarm.poll_next_unpin(&mut cx) {
Poll::Ready(Some(event)) => println!("Event: {:?}", event),
_ => (),
}
thread::sleep(Duration::from_secs_f32(0.01));
} I'm putting Is this an issue or am I doing something wrong with the code? |
Currently we have an issue with the
Swarm
API (or to be more exact,ExpandedSwarm
), as we try to run a swarm, process all of its events (not just behavior but the fullSwarmEvent
) and still react to external stimuli, such as a user requesting dialing a new connection.Our problem can thus be summarized as follows: Given a swarm and a future or stream that represents external user input that requires mutable access to the
ExpandedSwarm
instance, how can we react to both swarm events and the future itself?I did not find an obvious solution for this, so any advice is appreciated. Looking at the examples in the meantime, we did see some patterns, none of which seem applicable here:
future::select
This is similar to what was suggested in #682: Call
future::select(swarm.next(), some_other_action).await
, then react to either future.If
some_other_action
is the one returning aT
and finishing first, this would return something close toEither::Right((T, impl Future<Output=Self::OutEvent>))
. The second half of that tuple is the "leftover" future from callingswarm.next()
, thus my understand isswarm
is still borrowed, thus we cannot dialswarm.dial()
right there.We can of course drop the future, but that ends up with the same issue as the
tokio::select!
approach describe further below.Manual polling
From what I understand, the
chat.rs
example polls manually atrust-libp2p/examples/chat.rs
Lines 150 to 173 in 3edc467
try_poll_next_unpin
is called for both futures/streams we want to react to, and this works, as the swarm is not borrowed afterwards. Unfortunately this can only be used to react to behavior events, as theStream
implementation discards all others:rust-libp2p/swarm/src/lib.rs
Lines 918 to 923 in 3edc467
This makes it impossible to get to the
SwarmEvent
s.tokio::select!
Calling
tokio::select!
will appear to work and is used inrust-libp2p/examples/chat-tokio.rs
Lines 156 to 161 in 3edc467
However, I am not even 100% sure that the example is correct. Someone sending a very long line at a very slow rate might lose parts of it as data is already buffered when the
event
is triggered.In general, using
select!
seems a bit iffy, since it requires all futures to be cancellation correct, otherweise we run into issues, a good summary of which is available at https://gist.github.com/Matthias247/ffc0f189742abf6aa41a226fe07398a8.Even if we ensure that our own logic is cancellation safe, there is no indication that libp2p's
next_event
future is, so if that is the case, it should at least be documented, giving a modest guarantee that that will be the case in the future as well.Some possible fixes?
If I understand the code correctly, these are possible fixes:
next_event()
is cancellation-correct, similar to how tokio does it. This would enable the use oftokio::select!
.ExtendedSwarm
handle mutability/queuing internally, making all methods take&self
instead of&mut self
instead. I don't know if this is in the cards at all, but I imagine this would solve a lot of issues for users.Stream
implementation onExpandedSwarm
returnSwarmEvent
s, or offer an equivalent stream. This enables manual polling.ExpandedSwarm::poll_next_event
. This function is used internally by others, but offers a way of polling without having to create a new future that borrows the swarm, also enabling manual polling.Otherwise we are grateful for any advice and potential improvements to the documentation.
The text was updated successfully, but these errors were encountered: