Simplify trait bounds on NetworkBehaviour (#1405)

* Simplify trait bounds requirements

* More work

* Moar

* Finish

* Fix final tests

* More simplification

* Use separate traits for Inbound/Outbound

* Update gossipsub and remove warnings

* Add documentation to swarm

* Remove BoxSubstream

* Fix tests not compiling

* Fix stack overflow

* Address concerns

* For some reason my IDE ignored libp2p-kad
This commit is contained in:
Pierre Krieger
2020-02-07 16:29:30 +01:00
committed by GitHub
parent 69852a580b
commit 1eff4b9823
32 changed files with 580 additions and 652 deletions

View File

@ -25,6 +25,7 @@ use crate::protocol::{
use crate::record::{self, Record};
use futures::prelude::*;
use libp2p_swarm::{
NegotiatedSubstream,
KeepAlive,
SubstreamProtocol,
ProtocolsHandler,
@ -33,7 +34,7 @@ use libp2p_swarm::{
};
use libp2p_core::{
either::EitherOutput,
upgrade::{self, InboundUpgrade, OutboundUpgrade, Negotiated}
upgrade::{self, InboundUpgrade, OutboundUpgrade}
};
use log::trace;
use std::{borrow::Cow, error, fmt, io, pin::Pin, task::Context, task::Poll, time::Duration};
@ -45,10 +46,7 @@ use wasm_timer::Instant;
/// make.
///
/// It also handles requests made by the remote.
pub struct KademliaHandler<TSubstream, TUserData>
where
TSubstream: AsyncRead + AsyncWrite + Unpin,
{
pub struct KademliaHandler<TUserData> {
/// Configuration for the Kademlia protocol.
config: KademliaProtocolConfig,
@ -59,51 +57,45 @@ where
next_connec_unique_id: UniqueConnecId,
/// List of active substreams with the state they are in.
substreams: Vec<SubstreamState<TSubstream, TUserData>>,
substreams: Vec<SubstreamState<TUserData>>,
/// Until when to keep the connection alive.
keep_alive: KeepAlive,
}
/// State of an active substream, opened either by us or by the remote.
enum SubstreamState<TSubstream, TUserData>
where
TSubstream: AsyncRead + AsyncWrite + Unpin,
{
enum SubstreamState<TUserData> {
/// We haven't started opening the outgoing substream yet.
/// Contains the request we want to send, and the user data if we expect an answer.
OutPendingOpen(KadRequestMsg, Option<TUserData>),
/// Waiting to send a message to the remote.
OutPendingSend(
KadOutStreamSink<Negotiated<TSubstream>>,
KadOutStreamSink<NegotiatedSubstream>,
KadRequestMsg,
Option<TUserData>,
),
/// Waiting to flush the substream so that the data arrives to the remote.
OutPendingFlush(KadOutStreamSink<Negotiated<TSubstream>>, Option<TUserData>),
OutPendingFlush(KadOutStreamSink<NegotiatedSubstream>, Option<TUserData>),
/// Waiting for an answer back from the remote.
// TODO: add timeout
OutWaitingAnswer(KadOutStreamSink<Negotiated<TSubstream>>, TUserData),
OutWaitingAnswer(KadOutStreamSink<NegotiatedSubstream>, TUserData),
/// An error happened on the substream and we should report the error to the user.
OutReportError(KademliaHandlerQueryErr, TUserData),
/// The substream is being closed.
OutClosing(KadOutStreamSink<Negotiated<TSubstream>>),
OutClosing(KadOutStreamSink<NegotiatedSubstream>),
/// Waiting for a request from the remote.
InWaitingMessage(UniqueConnecId, KadInStreamSink<Negotiated<TSubstream>>),
InWaitingMessage(UniqueConnecId, KadInStreamSink<NegotiatedSubstream>),
/// Waiting for the user to send a `KademliaHandlerIn` event containing the response.
InWaitingUser(UniqueConnecId, KadInStreamSink<Negotiated<TSubstream>>),
InWaitingUser(UniqueConnecId, KadInStreamSink<NegotiatedSubstream>),
/// Waiting to send an answer back to the remote.
InPendingSend(UniqueConnecId, KadInStreamSink<Negotiated<TSubstream>>, KadResponseMsg),
InPendingSend(UniqueConnecId, KadInStreamSink<NegotiatedSubstream>, KadResponseMsg),
/// Waiting to flush an answer back to the remote.
InPendingFlush(UniqueConnecId, KadInStreamSink<Negotiated<TSubstream>>),
InPendingFlush(UniqueConnecId, KadInStreamSink<NegotiatedSubstream>),
/// The substream is being closed.
InClosing(KadInStreamSink<Negotiated<TSubstream>>),
InClosing(KadInStreamSink<NegotiatedSubstream>),
}
impl<TSubstream, TUserData> SubstreamState<TSubstream, TUserData>
where
TSubstream: AsyncRead + AsyncWrite + Unpin,
{
impl<TUserData> SubstreamState<TUserData> {
/// Tries to close the substream.
///
/// If the substream is not ready to be closed, returns it back.
@ -379,10 +371,7 @@ pub struct KademliaRequestId {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct UniqueConnecId(u64);
impl<TSubstream, TUserData> KademliaHandler<TSubstream, TUserData>
where
TSubstream: AsyncRead + AsyncWrite + Unpin,
{
impl<TUserData> KademliaHandler<TUserData> {
/// Create a `KademliaHandler` that only allows sending messages to the remote but denying
/// incoming connections.
pub fn dial_only() -> Self {
@ -415,25 +404,20 @@ where
}
}
impl<TSubstream, TUserData> Default for KademliaHandler<TSubstream, TUserData>
where
TSubstream: AsyncRead + AsyncWrite + Unpin,
{
impl<TUserData> Default for KademliaHandler<TUserData> {
#[inline]
fn default() -> Self {
KademliaHandler::dial_and_listen()
}
}
impl<TSubstream, TUserData> ProtocolsHandler for KademliaHandler<TSubstream, TUserData>
impl<TUserData> ProtocolsHandler for KademliaHandler<TUserData>
where
TSubstream: AsyncRead + AsyncWrite + Unpin,
TUserData: Clone,
TUserData: Clone + Send + 'static,
{
type InEvent = KademliaHandlerIn<TUserData>;
type OutEvent = KademliaHandlerEvent<TUserData>;
type Error = io::Error; // TODO: better error type?
type Substream = TSubstream;
type InboundProtocol = upgrade::EitherUpgrade<KademliaProtocolConfig, upgrade::DeniedUpgrade>;
type OutboundProtocol = KademliaProtocolConfig;
// Message of the request to send to the remote, and user data if we expect an answer.
@ -450,7 +434,7 @@ where
fn inject_fully_negotiated_outbound(
&mut self,
protocol: <Self::OutboundProtocol as OutboundUpgrade<Negotiated<TSubstream>>>::Output,
protocol: <Self::OutboundProtocol as OutboundUpgrade<NegotiatedSubstream>>::Output,
(msg, user_data): Self::OutboundOpenInfo,
) {
self.substreams
@ -459,7 +443,7 @@ where
fn inject_fully_negotiated_inbound(
&mut self,
protocol: <Self::InboundProtocol as InboundUpgrade<Negotiated<TSubstream>>>::Output,
protocol: <Self::InboundProtocol as InboundUpgrade<NegotiatedSubstream>>::Output,
) {
// If `self.allow_listening` is false, then we produced a `DeniedUpgrade` and `protocol`
// is a `Void`.
@ -695,12 +679,12 @@ where
///
/// Returns the new state for that substream, an event to generate, and whether the substream
/// should be polled again.
fn advance_substream<TSubstream, TUserData>(
state: SubstreamState<TSubstream, TUserData>,
fn advance_substream<TUserData>(
state: SubstreamState<TUserData>,
upgrade: KademliaProtocolConfig,
cx: &mut Context,
) -> (
Option<SubstreamState<TSubstream, TUserData>>,
Option<SubstreamState<TUserData>>,
Option<
ProtocolsHandlerEvent<
KademliaProtocolConfig,
@ -711,8 +695,6 @@ fn advance_substream<TSubstream, TUserData>(
>,
bool,
)
where
TSubstream: AsyncRead + AsyncWrite + Unpin,
{
match state {
SubstreamState::OutPendingOpen(msg, user_data) => {