mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-26 08:11:39 +00:00
Switch to stable futures (#1196)
* Switch to stable futures * Remove from_fn * Fix secio * Fix core --lib tests
This commit is contained in:
@ -27,10 +27,9 @@ use libp2p_swarm::{
|
||||
ProtocolsHandlerUpgrErr,
|
||||
ProtocolsHandlerEvent
|
||||
};
|
||||
use std::{error::Error, io, fmt, num::NonZeroU32, time::Duration};
|
||||
use std::{error::Error, io, fmt, num::NonZeroU32, pin::Pin, task::Context, task::Poll, time::Duration};
|
||||
use std::collections::VecDeque;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use wasm_timer::{Delay, Instant};
|
||||
use wasm_timer::Delay;
|
||||
use void::Void;
|
||||
|
||||
/// The configuration for outbound pings.
|
||||
@ -176,7 +175,7 @@ impl<TSubstream> PingHandler<TSubstream> {
|
||||
pub fn new(config: PingConfig) -> Self {
|
||||
PingHandler {
|
||||
config,
|
||||
next_ping: Delay::new(Instant::now()),
|
||||
next_ping: Delay::new(Duration::new(0, 0)),
|
||||
pending_results: VecDeque::with_capacity(2),
|
||||
failures: 0,
|
||||
_marker: std::marker::PhantomData
|
||||
@ -186,7 +185,7 @@ impl<TSubstream> PingHandler<TSubstream> {
|
||||
|
||||
impl<TSubstream> ProtocolsHandler for PingHandler<TSubstream>
|
||||
where
|
||||
TSubstream: AsyncRead + AsyncWrite,
|
||||
TSubstream: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
type InEvent = Void;
|
||||
type OutEvent = PingResult;
|
||||
@ -228,36 +227,36 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&mut self) -> Poll<ProtocolsHandlerEvent<protocol::Ping, (), PingResult>, Self::Error> {
|
||||
fn poll(&mut self, cx: &mut Context) -> Poll<ProtocolsHandlerEvent<protocol::Ping, (), PingResult, Self::Error>> {
|
||||
if let Some(result) = self.pending_results.pop_back() {
|
||||
if let Ok(PingSuccess::Ping { .. }) = result {
|
||||
let next_ping = Instant::now() + self.config.interval;
|
||||
self.failures = 0;
|
||||
self.next_ping.reset(next_ping);
|
||||
self.next_ping.reset(self.config.interval);
|
||||
}
|
||||
if let Err(e) = result {
|
||||
self.failures += 1;
|
||||
if self.failures >= self.config.max_failures.get() {
|
||||
return Err(e)
|
||||
return Poll::Ready(ProtocolsHandlerEvent::Close(e))
|
||||
} else {
|
||||
return Ok(Async::Ready(ProtocolsHandlerEvent::Custom(Err(e))))
|
||||
return Poll::Ready(ProtocolsHandlerEvent::Custom(Err(e)))
|
||||
}
|
||||
}
|
||||
return Ok(Async::Ready(ProtocolsHandlerEvent::Custom(result)))
|
||||
return Poll::Ready(ProtocolsHandlerEvent::Custom(result))
|
||||
}
|
||||
|
||||
match self.next_ping.poll() {
|
||||
Ok(Async::Ready(())) => {
|
||||
self.next_ping.reset(Instant::now() + self.config.timeout);
|
||||
match Future::poll(Pin::new(&mut self.next_ping), cx) {
|
||||
Poll::Ready(Ok(())) => {
|
||||
self.next_ping.reset(self.config.timeout);
|
||||
let protocol = SubstreamProtocol::new(protocol::Ping)
|
||||
.with_timeout(self.config.timeout);
|
||||
Ok(Async::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
|
||||
Poll::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
|
||||
protocol,
|
||||
info: (),
|
||||
}))
|
||||
})
|
||||
},
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Err(e) => Err(PingFailure::Other { error: Box::new(e) })
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Err(e)) =>
|
||||
Poll::Ready(ProtocolsHandlerEvent::Close(PingFailure::Other { error: Box::new(e) }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,7 +284,7 @@ mod tests {
|
||||
ProtocolsHandlerEvent<protocol::Ping, (), PingResult>,
|
||||
PingFailure
|
||||
> {
|
||||
Runtime::new().unwrap().block_on(future::poll_fn(|| h.poll() ))
|
||||
futures::executor::block_on(future::poll_fn(|| h.poll() ))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -50,9 +50,7 @@ use handler::PingHandler;
|
||||
use futures::prelude::*;
|
||||
use libp2p_core::{ConnectedPoint, Multiaddr, PeerId};
|
||||
use libp2p_swarm::{NetworkBehaviour, NetworkBehaviourAction, PollParameters};
|
||||
use std::collections::VecDeque;
|
||||
use std::marker::PhantomData;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use std::{collections::VecDeque, marker::PhantomData, task::Context, task::Poll};
|
||||
use void::Void;
|
||||
|
||||
/// `Ping` is a [`NetworkBehaviour`] that responds to inbound pings and
|
||||
@ -95,7 +93,7 @@ impl<TSubstream> Default for Ping<TSubstream> {
|
||||
|
||||
impl<TSubstream> NetworkBehaviour for Ping<TSubstream>
|
||||
where
|
||||
TSubstream: AsyncRead + AsyncWrite,
|
||||
TSubstream: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
type ProtocolsHandler = PingHandler<TSubstream>;
|
||||
type OutEvent = PingEvent;
|
||||
@ -116,12 +114,13 @@ where
|
||||
self.events.push_front(PingEvent { peer, result })
|
||||
}
|
||||
|
||||
fn poll(&mut self, _: &mut impl PollParameters) -> Async<NetworkBehaviourAction<Void, PingEvent>>
|
||||
fn poll(&mut self, _: &mut Context, _: &mut impl PollParameters)
|
||||
-> Poll<NetworkBehaviourAction<Void, PingEvent>>
|
||||
{
|
||||
if let Some(e) = self.events.pop_back() {
|
||||
Async::Ready(NetworkBehaviourAction::GenerateEvent(e))
|
||||
Poll::Ready(NetworkBehaviourAction::GenerateEvent(e))
|
||||
} else {
|
||||
Async::NotReady
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,11 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use futures::{prelude::*, future, try_ready};
|
||||
use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, upgrade::Negotiated};
|
||||
use futures::prelude::*;
|
||||
use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, Negotiated};
|
||||
use log::debug;
|
||||
use rand::{distributions, prelude::*};
|
||||
use std::{io, iter, time::Duration};
|
||||
use tokio_io::{io as nio, AsyncRead, AsyncWrite};
|
||||
use std::{io, iter, pin::Pin, time::Duration};
|
||||
use wasm_timer::Instant;
|
||||
|
||||
/// Represents a prototype for an upgrade to handle the ping protocol.
|
||||
@ -54,126 +53,50 @@ impl UpgradeInfo for Ping {
|
||||
}
|
||||
}
|
||||
|
||||
type RecvPing<T> = nio::ReadExact<Negotiated<T>, [u8; 32]>;
|
||||
type SendPong<T> = nio::WriteAll<Negotiated<T>, [u8; 32]>;
|
||||
type Flush<T> = nio::Flush<Negotiated<T>>;
|
||||
type Shutdown<T> = nio::Shutdown<Negotiated<T>>;
|
||||
|
||||
impl<TSocket> InboundUpgrade<TSocket> for Ping
|
||||
where
|
||||
TSocket: AsyncRead + AsyncWrite,
|
||||
TSocket: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
type Output = ();
|
||||
type Error = io::Error;
|
||||
type Future = future::Map<
|
||||
future::AndThen<
|
||||
future::AndThen<
|
||||
future::AndThen<
|
||||
RecvPing<TSocket>,
|
||||
SendPong<TSocket>, fn((Negotiated<TSocket>, [u8; 32])) -> SendPong<TSocket>>,
|
||||
Flush<TSocket>, fn((Negotiated<TSocket>, [u8; 32])) -> Flush<TSocket>>,
|
||||
Shutdown<TSocket>, fn(Negotiated<TSocket>) -> Shutdown<TSocket>>,
|
||||
fn(Negotiated<TSocket>) -> ()>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<(), io::Error>>>>;
|
||||
|
||||
#[inline]
|
||||
fn upgrade_inbound(self, socket: Negotiated<TSocket>, _: Self::Info) -> Self::Future {
|
||||
nio::read_exact(socket, [0; 32])
|
||||
.and_then::<fn(_) -> _, _>(|(sock, buf)| nio::write_all(sock, buf))
|
||||
.and_then::<fn(_) -> _, _>(|(sock, _)| nio::flush(sock))
|
||||
.and_then::<fn(_) -> _, _>(|sock| nio::shutdown(sock))
|
||||
.map(|_| ())
|
||||
fn upgrade_inbound(self, mut socket: Negotiated<TSocket>, _: Self::Info) -> Self::Future {
|
||||
Box::pin(async move {
|
||||
let mut payload = [0u8; 32];
|
||||
socket.read_exact(&mut payload).await?;
|
||||
socket.write_all(&payload).await?;
|
||||
socket.close().await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<TSocket> OutboundUpgrade<TSocket> for Ping
|
||||
where
|
||||
TSocket: AsyncRead + AsyncWrite,
|
||||
TSocket: AsyncRead + AsyncWrite + Unpin + 'static,
|
||||
{
|
||||
type Output = Duration;
|
||||
type Error = io::Error;
|
||||
type Future = PingDialer<Negotiated<TSocket>>;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Duration, io::Error>>>>;
|
||||
|
||||
#[inline]
|
||||
fn upgrade_outbound(self, socket: Negotiated<TSocket>, _: Self::Info) -> Self::Future {
|
||||
fn upgrade_outbound(self, mut socket: Negotiated<TSocket>, _: Self::Info) -> Self::Future {
|
||||
let payload: [u8; 32] = thread_rng().sample(distributions::Standard);
|
||||
debug!("Preparing ping payload {:?}", payload);
|
||||
|
||||
PingDialer {
|
||||
state: PingDialerState::Write {
|
||||
inner: nio::write_all(socket, payload),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Box::pin(async move {
|
||||
socket.write_all(&payload).await?;
|
||||
socket.close().await?;
|
||||
let started = Instant::now();
|
||||
|
||||
/// A `PingDialer` is a future that sends a ping and expects to receive a pong.
|
||||
pub struct PingDialer<TSocket> {
|
||||
state: PingDialerState<TSocket>
|
||||
}
|
||||
|
||||
enum PingDialerState<TSocket> {
|
||||
Write {
|
||||
inner: nio::WriteAll<TSocket, [u8; 32]>,
|
||||
},
|
||||
Flush {
|
||||
inner: nio::Flush<TSocket>,
|
||||
payload: [u8; 32],
|
||||
},
|
||||
Read {
|
||||
inner: nio::ReadExact<TSocket, [u8; 32]>,
|
||||
payload: [u8; 32],
|
||||
started: Instant,
|
||||
},
|
||||
Shutdown {
|
||||
inner: nio::Shutdown<TSocket>,
|
||||
rtt: Duration,
|
||||
},
|
||||
}
|
||||
|
||||
impl<TSocket> Future for PingDialer<TSocket>
|
||||
where
|
||||
TSocket: AsyncRead + AsyncWrite,
|
||||
{
|
||||
type Item = Duration;
|
||||
type Error = io::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
loop {
|
||||
self.state = match self.state {
|
||||
PingDialerState::Write { ref mut inner } => {
|
||||
let (socket, payload) = try_ready!(inner.poll());
|
||||
PingDialerState::Flush {
|
||||
inner: nio::flush(socket),
|
||||
payload,
|
||||
}
|
||||
},
|
||||
PingDialerState::Flush { ref mut inner, payload } => {
|
||||
let socket = try_ready!(inner.poll());
|
||||
let started = Instant::now();
|
||||
PingDialerState::Read {
|
||||
inner: nio::read_exact(socket, [0; 32]),
|
||||
payload,
|
||||
started,
|
||||
}
|
||||
},
|
||||
PingDialerState::Read { ref mut inner, payload, started } => {
|
||||
let (socket, payload_received) = try_ready!(inner.poll());
|
||||
let rtt = started.elapsed();
|
||||
if payload_received != payload {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData, "Ping payload mismatch"));
|
||||
}
|
||||
PingDialerState::Shutdown {
|
||||
inner: nio::shutdown(socket),
|
||||
rtt,
|
||||
}
|
||||
},
|
||||
PingDialerState::Shutdown { ref mut inner, rtt } => {
|
||||
try_ready!(inner.poll());
|
||||
return Ok(Async::Ready(rtt));
|
||||
},
|
||||
let mut recv_payload = [0u8; 32];
|
||||
socket.read_exact(&mut recv_payload).await?;
|
||||
if recv_payload == payload {
|
||||
Ok(started.elapsed())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "Ping payload mismatch"))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,7 +122,7 @@ mod tests {
|
||||
let mut listener = MemoryTransport.listen_on(mem_addr).unwrap();
|
||||
|
||||
let listener_addr =
|
||||
if let Ok(Async::Ready(Some(ListenerEvent::NewAddress(a)))) = listener.poll() {
|
||||
if let Ok(Poll::Ready(Some(ListenerEvent::NewAddress(a)))) = listener.poll() {
|
||||
a
|
||||
} else {
|
||||
panic!("MemoryTransport not listening on an address!");
|
||||
|
Reference in New Issue
Block a user