fix: poll swarm first, use SwarmEvents
polling swarm first seems important, otherwise there'll be a race to first listening endpoint getting up at least.
This commit is contained in:
parent
cd7a416528
commit
307a724b1a
146
src/lib.rs
146
src/lib.rs
@ -414,84 +414,94 @@ impl<Types: SwarmTypes> Future for IpfsFuture<Types> {
|
|||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use libp2p::Swarm;
|
use libp2p::{Swarm, swarm::SwarmEvent};
|
||||||
|
|
||||||
|
// begin by polling the swarm so that initially it'll first have chance to bind listeners
|
||||||
|
// and such. TODO: this no longer needs to be a swarm event but perhaps we should
|
||||||
|
// consolidate logging of these events here, if necessary?
|
||||||
loop {
|
loop {
|
||||||
// temporary pinning of the receivers should be safe as we are pinning through the
|
let inner = {
|
||||||
// already pinned self. with the receivers we can also safely ignore exhaustion
|
let next = self.swarm.next_event();
|
||||||
// as those are fused.
|
futures::pin_mut!(next);
|
||||||
loop {
|
match next.poll(ctx) {
|
||||||
let inner = match Pin::new(&mut self.from_facade).poll_next(ctx) {
|
Poll::Ready(inner) => inner,
|
||||||
Poll::Ready(Some(evt)) => evt,
|
|
||||||
// doing teardown also after the `Ipfs` has been dropped
|
|
||||||
Poll::Ready(None) => IpfsEvent::Exit,
|
|
||||||
Poll::Pending => break,
|
Poll::Pending => break,
|
||||||
};
|
|
||||||
|
|
||||||
match inner {
|
|
||||||
IpfsEvent::Connect(addr, ret) => {
|
|
||||||
let fut = self.swarm.connect(addr);
|
|
||||||
task::spawn(async move {
|
|
||||||
let res = fut.await.map_err(|err| format_err!("{}", err));
|
|
||||||
ret.send(res).ok();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
IpfsEvent::Addresses(ret) => {
|
|
||||||
let addrs = self.swarm.addrs();
|
|
||||||
ret.send(Ok(addrs)).ok();
|
|
||||||
}
|
|
||||||
IpfsEvent::Listeners(ret) => {
|
|
||||||
let listeners = Swarm::listeners(&self.swarm).cloned().collect();
|
|
||||||
ret.send(Ok(listeners)).ok();
|
|
||||||
}
|
|
||||||
IpfsEvent::Connections(ret) => {
|
|
||||||
let connections = self.swarm.connections();
|
|
||||||
ret.send(Ok(connections)).ok();
|
|
||||||
}
|
|
||||||
IpfsEvent::Disconnect(addr, ret) => {
|
|
||||||
if let Some(disconnector) = self.swarm.disconnect(addr) {
|
|
||||||
disconnector.disconnect(&mut self.swarm);
|
|
||||||
}
|
|
||||||
ret.send(Ok(())).ok();
|
|
||||||
}
|
|
||||||
IpfsEvent::GetAddresses(ret) => {
|
|
||||||
// perhaps this could be moved under `IpfsEvent` or free functions?
|
|
||||||
let mut addresses = Vec::new();
|
|
||||||
addresses.extend(Swarm::listeners(&self.swarm).cloned());
|
|
||||||
addresses.extend(Swarm::external_addresses(&self.swarm).cloned());
|
|
||||||
// ignore error, perhaps caller went away already
|
|
||||||
let _ = ret.send(addresses);
|
|
||||||
}
|
|
||||||
IpfsEvent::Exit => {
|
|
||||||
// FIXME: we could do a proper teardown
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
match inner {
|
||||||
|
SwarmEvent::Behaviour(()) => {},
|
||||||
|
SwarmEvent::Connected(_peer_id) => {},
|
||||||
|
SwarmEvent::Disconnected(_peer_id) => {},
|
||||||
|
SwarmEvent::NewListenAddr(_addr) => {},
|
||||||
|
SwarmEvent::ExpiredListenAddr(_addr) => {},
|
||||||
|
SwarmEvent::UnreachableAddr { peer_id: _peer_id, address: _address, error: _error } => {},
|
||||||
|
SwarmEvent::StartConnect(_peer_id) => {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Poll::Ready(None) and Poll::Pending can be used to break out of the loop, clippy
|
// temporary pinning of the receivers should be safe as we are pinning through the
|
||||||
// wants this to be written with a `while let`.
|
// already pinned self. with the receivers we can also safely ignore exhaustion
|
||||||
while let Poll::Ready(Some(evt)) = Pin::new(&mut self.repo_events).poll_next(ctx) {
|
// as those are fused.
|
||||||
match evt {
|
loop {
|
||||||
RepoEvent::WantBlock(cid) => self.swarm.want_block(cid),
|
let inner = match Pin::new(&mut self.from_facade).poll_next(ctx) {
|
||||||
RepoEvent::ProvideBlock(cid) => self.swarm.provide_block(cid),
|
Poll::Ready(Some(evt)) => evt,
|
||||||
RepoEvent::UnprovideBlock(cid) => self.swarm.stop_providing_block(&cid),
|
// doing teardown also after the `Ipfs` has been dropped
|
||||||
|
Poll::Ready(None) => IpfsEvent::Exit,
|
||||||
|
Poll::Pending => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
match inner {
|
||||||
|
IpfsEvent::Connect(addr, ret) => {
|
||||||
|
let fut = self.swarm.connect(addr);
|
||||||
|
task::spawn(async move {
|
||||||
|
let res = fut.await.map_err(|err| format_err!("{}", err));
|
||||||
|
ret.send(res).ok();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
IpfsEvent::Addresses(ret) => {
|
||||||
|
let addrs = self.swarm.addrs();
|
||||||
{
|
ret.send(Ok(addrs)).ok();
|
||||||
let poll = Pin::new(&mut self.swarm).poll_next(ctx);
|
}
|
||||||
match poll {
|
IpfsEvent::Listeners(ret) => {
|
||||||
Poll::Ready(Some(_)) => {}
|
let listeners = Swarm::listeners(&self.swarm).cloned().collect();
|
||||||
Poll::Ready(None) => {
|
ret.send(Ok(listeners)).ok();
|
||||||
// this should never happen with libp2p swarm
|
}
|
||||||
return Poll::Ready(());
|
IpfsEvent::Connections(ret) => {
|
||||||
}
|
let connections = self.swarm.connections();
|
||||||
Poll::Pending => {
|
ret.send(Ok(connections)).ok();
|
||||||
return Poll::Pending;
|
}
|
||||||
|
IpfsEvent::Disconnect(addr, ret) => {
|
||||||
|
if let Some(disconnector) = self.swarm.disconnect(addr) {
|
||||||
|
disconnector.disconnect(&mut self.swarm);
|
||||||
}
|
}
|
||||||
|
ret.send(Ok(())).ok();
|
||||||
|
}
|
||||||
|
IpfsEvent::GetAddresses(ret) => {
|
||||||
|
// perhaps this could be moved under `IpfsEvent` or free functions?
|
||||||
|
let mut addresses = Vec::new();
|
||||||
|
addresses.extend(Swarm::listeners(&self.swarm).cloned());
|
||||||
|
addresses.extend(Swarm::external_addresses(&self.swarm).cloned());
|
||||||
|
// ignore error, perhaps caller went away already
|
||||||
|
let _ = ret.send(addresses);
|
||||||
|
}
|
||||||
|
IpfsEvent::Exit => {
|
||||||
|
// FIXME: we could do a proper teardown
|
||||||
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll::Ready(None) and Poll::Pending can be used to break out of the loop, clippy
|
||||||
|
// wants this to be written with a `while let`.
|
||||||
|
while let Poll::Ready(Some(evt)) = Pin::new(&mut self.repo_events).poll_next(ctx) {
|
||||||
|
match evt {
|
||||||
|
RepoEvent::WantBlock(cid) => self.swarm.want_block(cid),
|
||||||
|
RepoEvent::ProvideBlock(cid) => self.swarm.provide_block(cid),
|
||||||
|
RepoEvent::UnprovideBlock(cid) => self.swarm.stop_providing_block(&cid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user