mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-04-24 18:52:14 +00:00
Refine boxing during transport construction. (#1794)
* Rework boxing during transport construction. * Cleanup * Fix chat-tokio example. * Update changelogs and versions.
This commit is contained in:
parent
2dbf834d10
commit
dc56d44edb
30
Cargo.toml
30
Cargo.toml
@ -62,22 +62,22 @@ atomic = "0.5.0"
|
||||
bytes = "0.5"
|
||||
futures = "0.3.1"
|
||||
lazy_static = "1.2"
|
||||
libp2p-core = { version = "0.22.2", path = "core" }
|
||||
libp2p-core = { version = "0.23.0", path = "core" }
|
||||
libp2p-core-derive = { version = "0.20.2", path = "misc/core-derive" }
|
||||
libp2p-floodsub = { version = "0.23.0", path = "protocols/floodsub", optional = true }
|
||||
libp2p-gossipsub = { version = "0.22.1", path = "./protocols/gossipsub", optional = true }
|
||||
libp2p-identify = { version = "0.22.0", path = "protocols/identify", optional = true }
|
||||
libp2p-kad = { version = "0.23.1", path = "protocols/kad", optional = true }
|
||||
libp2p-gossipsub = { version = "0.23.0", path = "./protocols/gossipsub", optional = true }
|
||||
libp2p-identify = { version = "0.23.0", path = "protocols/identify", optional = true }
|
||||
libp2p-kad = { version = "0.24.0", path = "protocols/kad", optional = true }
|
||||
libp2p-mplex = { version = "0.23.0", path = "muxers/mplex", optional = true }
|
||||
libp2p-noise = { version = "0.24.1", path = "protocols/noise", optional = true }
|
||||
libp2p-ping = { version = "0.22.0", path = "protocols/ping", optional = true }
|
||||
libp2p-noise = { version = "0.25.0", path = "protocols/noise", optional = true }
|
||||
libp2p-ping = { version = "0.23.0", path = "protocols/ping", optional = true }
|
||||
libp2p-plaintext = { version = "0.23.0", path = "protocols/plaintext", optional = true }
|
||||
libp2p-pnet = { version = "0.19.2", path = "protocols/pnet", optional = true }
|
||||
libp2p-request-response = { version = "0.4.0", path = "protocols/request-response", optional = true }
|
||||
libp2p-swarm = { version = "0.22.1", path = "swarm" }
|
||||
libp2p-uds = { version = "0.22.0", path = "transports/uds", optional = true }
|
||||
libp2p-wasm-ext = { version = "0.22.0", path = "transports/wasm-ext", optional = true }
|
||||
libp2p-yamux = { version = "0.25.0", path = "muxers/yamux", optional = true }
|
||||
libp2p-swarm = { version = "0.23.0", path = "swarm" }
|
||||
libp2p-uds = { version = "0.23.0", path = "transports/uds", optional = true }
|
||||
libp2p-wasm-ext = { version = "0.23.0", path = "transports/wasm-ext", optional = true }
|
||||
libp2p-yamux = { version = "0.26.0", path = "muxers/yamux", optional = true }
|
||||
multiaddr = { package = "parity-multiaddr", version = "0.9.3", path = "misc/multiaddr" }
|
||||
multihash = "0.11.0"
|
||||
parking_lot = "0.11.0"
|
||||
@ -86,11 +86,11 @@ smallvec = "1.0"
|
||||
wasm-timer = "0.2.4"
|
||||
|
||||
[target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies]
|
||||
libp2p-deflate = { version = "0.22.0", path = "protocols/deflate", optional = true }
|
||||
libp2p-dns = { version = "0.22.0", path = "transports/dns", optional = true }
|
||||
libp2p-mdns = { version = "0.22.1", path = "protocols/mdns", optional = true }
|
||||
libp2p-tcp = { version = "0.22.1", path = "transports/tcp", optional = true }
|
||||
libp2p-websocket = { version = "0.23.1", path = "transports/websocket", optional = true }
|
||||
libp2p-deflate = { version = "0.23.0", path = "protocols/deflate", optional = true }
|
||||
libp2p-dns = { version = "0.23.0", path = "transports/dns", optional = true }
|
||||
libp2p-mdns = { version = "0.23.0", path = "protocols/mdns", optional = true }
|
||||
libp2p-tcp = { version = "0.23.0", path = "transports/tcp", optional = true }
|
||||
libp2p-websocket = { version = "0.24.0", path = "transports/websocket", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
async-std = "1.6.2"
|
||||
|
@ -1,4 +1,8 @@
|
||||
# 0.22.2 [unreleased]
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Rework transport boxing and move timeout configuration
|
||||
to the transport builder.
|
||||
[PR 1794](https://github.com/libp2p/rust-libp2p/pull/1794).
|
||||
|
||||
- Update dependencies.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-core"
|
||||
edition = "2018"
|
||||
description = "Core traits and structs of libp2p"
|
||||
version = "0.22.2"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
|
@ -25,11 +25,10 @@
|
||||
//! any desired protocols. The rest of the module defines combinators for
|
||||
//! modifying a transport through composition with other transports or protocol upgrades.
|
||||
|
||||
use crate::{ConnectedPoint, ConnectionInfo, muxing::{StreamMuxer, StreamMuxerBox}};
|
||||
use crate::ConnectedPoint;
|
||||
use futures::prelude::*;
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{error::Error, fmt};
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod and_then;
|
||||
pub mod choice;
|
||||
@ -129,24 +128,16 @@ pub trait Transport {
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Boxes an authenticated, multiplexed transport, including the
|
||||
/// `StreamMuxer` and transport errors.
|
||||
fn boxed<I, M>(self) -> boxed::Boxed<(I, StreamMuxerBox), std::io::Error>
|
||||
/// Boxes the transport, including custom transport errors.
|
||||
fn boxed(self) -> boxed::Boxed<Self::Output>
|
||||
where
|
||||
Self: Transport<Output = (I, M)> + Sized + Clone + Send + Sync + 'static,
|
||||
Self: Transport + Sized + Clone + Send + Sync + 'static,
|
||||
Self::Dial: Send + 'static,
|
||||
Self::Listener: Send + 'static,
|
||||
Self::ListenerUpgrade: Send + 'static,
|
||||
Self::Error: Send + Sync,
|
||||
I: ConnectionInfo,
|
||||
M: StreamMuxer + Send + Sync + 'static,
|
||||
M::Substream: Send + 'static,
|
||||
M::OutboundSubstream: Send + 'static
|
||||
|
||||
{
|
||||
boxed::boxed(
|
||||
self.map(|(i, m), _| (i, StreamMuxerBox::new(m)))
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)))
|
||||
boxed::boxed(self)
|
||||
}
|
||||
|
||||
/// Applies a function on the connections created by the transport.
|
||||
@ -198,33 +189,6 @@ pub trait Transport {
|
||||
and_then::AndThen::new(self, f)
|
||||
}
|
||||
|
||||
/// Adds a timeout to the connection setup (including upgrades) for all
|
||||
/// inbound and outbound connections established through the transport.
|
||||
fn timeout(self, timeout: Duration) -> timeout::TransportTimeout<Self>
|
||||
where
|
||||
Self: Sized
|
||||
{
|
||||
timeout::TransportTimeout::new(self, timeout)
|
||||
}
|
||||
|
||||
/// Adds a timeout to the connection setup (including upgrades) for all outbound
|
||||
/// connections established through the transport.
|
||||
fn outbound_timeout(self, timeout: Duration) -> timeout::TransportTimeout<Self>
|
||||
where
|
||||
Self: Sized
|
||||
{
|
||||
timeout::TransportTimeout::with_outgoing_timeout(self, timeout)
|
||||
}
|
||||
|
||||
/// Adds a timeout to the connection setup (including upgrades) for all inbound
|
||||
/// connections established through the transport.
|
||||
fn inbound_timeout(self, timeout: Duration) -> timeout::TransportTimeout<Self>
|
||||
where
|
||||
Self: Sized
|
||||
{
|
||||
timeout::TransportTimeout::with_ingoing_timeout(self, timeout)
|
||||
}
|
||||
|
||||
/// Begins a series of protocol upgrades via an
|
||||
/// [`upgrade::Builder`](upgrade::Builder).
|
||||
fn upgrade(self, version: upgrade::Version) -> upgrade::Builder<Self>
|
||||
|
@ -21,12 +21,13 @@
|
||||
use crate::transport::{ListenerEvent, Transport, TransportError};
|
||||
use futures::prelude::*;
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{error, fmt, pin::Pin, sync::Arc};
|
||||
use std::{error::Error, fmt, io, pin::Pin, sync::Arc};
|
||||
|
||||
/// See the `Transport::boxed` method.
|
||||
pub fn boxed<T>(transport: T) -> Boxed<T::Output, T::Error>
|
||||
/// Creates a new [`Boxed`] transport from the given transport.
|
||||
pub fn boxed<T>(transport: T) -> Boxed<T::Output>
|
||||
where
|
||||
T: Transport + Clone + Send + Sync + 'static,
|
||||
T::Error: Send + Sync,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
@ -36,49 +37,56 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// See the `Transport::boxed` method.
|
||||
pub struct Boxed<O, E> {
|
||||
inner: Arc<dyn Abstract<O, E> + Send + Sync>,
|
||||
/// A `Boxed` transport is a `Transport` whose `Dial`, `Listener`
|
||||
/// and `ListenerUpgrade` futures are `Box`ed and only the `Output`
|
||||
/// and `Error` types are captured in type variables.
|
||||
pub struct Boxed<O> {
|
||||
inner: Arc<dyn Abstract<O> + Send + Sync>,
|
||||
}
|
||||
|
||||
type Dial<O, E> = Pin<Box<dyn Future<Output = Result<O, E>> + Send>>;
|
||||
type Listener<O, E> = Pin<Box<dyn Stream<Item = Result<ListenerEvent<ListenerUpgrade<O, E>, E>, E>> + Send>>;
|
||||
type ListenerUpgrade<O, E> = Pin<Box<dyn Future<Output = Result<O, E>> + Send>>;
|
||||
type Dial<O> = Pin<Box<dyn Future<Output = io::Result<O>> + Send>>;
|
||||
type Listener<O> = Pin<Box<dyn Stream<Item = io::Result<ListenerEvent<ListenerUpgrade<O>, io::Error>>> + Send>>;
|
||||
type ListenerUpgrade<O> = Pin<Box<dyn Future<Output = io::Result<O>> + Send>>;
|
||||
|
||||
trait Abstract<O, E> {
|
||||
fn listen_on(&self, addr: Multiaddr) -> Result<Listener<O, E>, TransportError<E>>;
|
||||
fn dial(&self, addr: Multiaddr) -> Result<Dial<O, E>, TransportError<E>>;
|
||||
trait Abstract<O> {
|
||||
fn listen_on(&self, addr: Multiaddr) -> Result<Listener<O>, TransportError<io::Error>>;
|
||||
fn dial(&self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>>;
|
||||
}
|
||||
|
||||
impl<T, O, E> Abstract<O, E> for T
|
||||
impl<T, O> Abstract<O> for T
|
||||
where
|
||||
T: Transport<Output = O, Error = E> + Clone + 'static,
|
||||
E: error::Error,
|
||||
T: Transport<Output = O> + Clone + 'static,
|
||||
T::Error: Send + Sync,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
{
|
||||
fn listen_on(&self, addr: Multiaddr) -> Result<Listener<O, E>, TransportError<E>> {
|
||||
let listener = Transport::listen_on(self.clone(), addr)?;
|
||||
let fut = listener.map_ok(|event| event.map(|upgrade| {
|
||||
Box::pin(upgrade) as ListenerUpgrade<O, E>
|
||||
}));
|
||||
fn listen_on(&self, addr: Multiaddr) -> Result<Listener<O>, TransportError<io::Error>> {
|
||||
let listener = Transport::listen_on(self.clone(), addr).map_err(|e| e.map(box_err))?;
|
||||
let fut = listener.map_ok(|event|
|
||||
event.map(|upgrade| {
|
||||
let up = upgrade.map_err(box_err);
|
||||
Box::pin(up) as ListenerUpgrade<O>
|
||||
}).map_err(box_err)
|
||||
).map_err(box_err);
|
||||
Ok(Box::pin(fut))
|
||||
}
|
||||
|
||||
fn dial(&self, addr: Multiaddr) -> Result<Dial<O, E>, TransportError<E>> {
|
||||
let fut = Transport::dial(self.clone(), addr)?;
|
||||
Ok(Box::pin(fut) as Dial<_, _>)
|
||||
fn dial(&self, addr: Multiaddr) -> Result<Dial<O>, TransportError<io::Error>> {
|
||||
let fut = Transport::dial(self.clone(), addr)
|
||||
.map(|r| r.map_err(box_err))
|
||||
.map_err(|e| e.map(box_err))?;
|
||||
Ok(Box::pin(fut) as Dial<_>)
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, E> fmt::Debug for Boxed<O, E> {
|
||||
impl<O> fmt::Debug for Boxed<O> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "BoxedTransport")
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, E> Clone for Boxed<O, E> {
|
||||
impl<O> Clone for Boxed<O> {
|
||||
fn clone(&self) -> Self {
|
||||
Boxed {
|
||||
inner: self.inner.clone(),
|
||||
@ -86,14 +94,12 @@ impl<O, E> Clone for Boxed<O, E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<O, E> Transport for Boxed<O, E>
|
||||
where E: error::Error,
|
||||
{
|
||||
impl<O> Transport for Boxed<O> {
|
||||
type Output = O;
|
||||
type Error = E;
|
||||
type Listener = Listener<O, E>;
|
||||
type ListenerUpgrade = ListenerUpgrade<O, E>;
|
||||
type Dial = Dial<O, E>;
|
||||
type Error = io::Error;
|
||||
type Listener = Listener<O>;
|
||||
type ListenerUpgrade = ListenerUpgrade<O>;
|
||||
type Dial = Dial<O>;
|
||||
|
||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
self.inner.listen_on(addr)
|
||||
@ -103,3 +109,7 @@ where E: error::Error,
|
||||
self.inner.dial(addr)
|
||||
}
|
||||
}
|
||||
|
||||
fn box_err<E: Error + Send + Sync + 'static>(e: E) -> io::Error {
|
||||
io::Error::new(io::ErrorKind::Other, e)
|
||||
}
|
||||
|
@ -31,8 +31,10 @@ use crate::{
|
||||
TransportError,
|
||||
ListenerEvent,
|
||||
and_then::AndThen,
|
||||
boxed::boxed,
|
||||
timeout::TransportTimeout,
|
||||
},
|
||||
muxing::StreamMuxer,
|
||||
muxing::{StreamMuxer, StreamMuxerBox},
|
||||
upgrade::{
|
||||
self,
|
||||
OutboundUpgrade,
|
||||
@ -46,7 +48,13 @@ use crate::{
|
||||
};
|
||||
use futures::{prelude::*, ready};
|
||||
use multiaddr::Multiaddr;
|
||||
use std::{error::Error, fmt, pin::Pin, task::Context, task::Poll};
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
time::Duration
|
||||
};
|
||||
|
||||
/// A `Builder` facilitates upgrading of a [`Transport`] for use with
|
||||
/// a [`Network`].
|
||||
@ -54,14 +62,14 @@ use std::{error::Error, fmt, pin::Pin, task::Context, task::Poll};
|
||||
/// The upgrade process is defined by the following stages:
|
||||
///
|
||||
/// [`authenticate`](Builder::authenticate)`{1}`
|
||||
/// -> [`apply`](Builder::apply)`{*}`
|
||||
/// -> [`multiplex`](Builder::multiplex)`{1}`
|
||||
/// -> [`apply`](Authenticated::apply)`{*}`
|
||||
/// -> [`multiplex`](Authenticated::multiplex)`{1}`
|
||||
///
|
||||
/// It thus enforces the following invariants on every transport
|
||||
/// obtained from [`multiplex`](Builder::multiplex):
|
||||
/// obtained from [`multiplex`](Authenticated::multiplex):
|
||||
///
|
||||
/// 1. The transport must be [authenticated](Builder::authenticate)
|
||||
/// and [multiplexed](Builder::multiplex).
|
||||
/// and [multiplexed](Authenticated::multiplex).
|
||||
/// 2. Authentication must precede the negotiation of a multiplexer.
|
||||
/// 3. Applying a multiplexer is the last step in the upgrade process.
|
||||
/// 4. The [`Transport::Output`] conforms to the requirements of a [`Network`],
|
||||
@ -69,6 +77,7 @@ use std::{error::Error, fmt, pin::Pin, task::Context, task::Poll};
|
||||
/// [`StreamMuxer`] (from the multiplexing upgrade).
|
||||
///
|
||||
/// [`Network`]: crate::Network
|
||||
#[derive(Clone)]
|
||||
pub struct Builder<T> {
|
||||
inner: T,
|
||||
version: upgrade::Version,
|
||||
@ -97,7 +106,7 @@ where
|
||||
///
|
||||
/// * I/O upgrade: `C -> (I, D)`.
|
||||
/// * Transport output: `C -> (I, D)`
|
||||
pub fn authenticate<C, D, U, I, E>(self, upgrade: U) -> Builder<
|
||||
pub fn authenticate<C, D, U, I, E>(self, upgrade: U) -> Authenticated<
|
||||
AndThen<T, impl FnOnce(C, ConnectedPoint) -> Authenticate<C, U> + Clone>
|
||||
> where
|
||||
T: Transport<Output = C>,
|
||||
@ -109,95 +118,11 @@ where
|
||||
E: Error + 'static,
|
||||
{
|
||||
let version = self.version;
|
||||
Builder::new(self.inner.and_then(move |conn, endpoint| {
|
||||
Authenticated(Builder::new(self.inner.and_then(move |conn, endpoint| {
|
||||
Authenticate {
|
||||
inner: upgrade::apply(conn, upgrade, endpoint, version)
|
||||
}
|
||||
}), version)
|
||||
}
|
||||
|
||||
/// Applies an arbitrary upgrade on an authenticated, non-multiplexed
|
||||
/// transport.
|
||||
///
|
||||
/// The upgrade receives the I/O resource (i.e. connection) `C` and
|
||||
/// must produce a new I/O resource `D`. Any number of such upgrades
|
||||
/// can be performed.
|
||||
///
|
||||
/// ## Transitions
|
||||
///
|
||||
/// * I/O upgrade: `C -> D`.
|
||||
/// * Transport output: `(I, C) -> (I, D)`.
|
||||
pub fn apply<C, D, U, I, E>(self, upgrade: U) -> Builder<Upgrade<T, U>>
|
||||
where
|
||||
T: Transport<Output = (I, C)>,
|
||||
C: AsyncRead + AsyncWrite + Unpin,
|
||||
D: AsyncRead + AsyncWrite + Unpin,
|
||||
I: ConnectionInfo,
|
||||
U: InboundUpgrade<Negotiated<C>, Output = D, Error = E>,
|
||||
U: OutboundUpgrade<Negotiated<C>, Output = D, Error = E> + Clone,
|
||||
E: Error + 'static,
|
||||
{
|
||||
Builder::new(Upgrade::new(self.inner, upgrade), self.version)
|
||||
}
|
||||
|
||||
/// Upgrades the transport with a (sub)stream multiplexer.
|
||||
///
|
||||
/// The supplied upgrade receives the I/O resource `C` and must
|
||||
/// produce a [`StreamMuxer`] `M`. The transport must already be authenticated.
|
||||
/// This ends the (regular) transport upgrade process, yielding the underlying,
|
||||
/// configured transport.
|
||||
///
|
||||
/// ## Transitions
|
||||
///
|
||||
/// * I/O upgrade: `C -> M`.
|
||||
/// * Transport output: `(I, C) -> (I, M)`.
|
||||
pub fn multiplex<C, M, U, I, E>(self, upgrade: U)
|
||||
-> AndThen<T, impl FnOnce((I, C), ConnectedPoint) -> Multiplex<C, U, I> + Clone>
|
||||
where
|
||||
T: Transport<Output = (I, C)>,
|
||||
C: AsyncRead + AsyncWrite + Unpin,
|
||||
M: StreamMuxer,
|
||||
I: ConnectionInfo,
|
||||
U: InboundUpgrade<Negotiated<C>, Output = M, Error = E>,
|
||||
U: OutboundUpgrade<Negotiated<C>, Output = M, Error = E> + Clone,
|
||||
E: Error + 'static,
|
||||
{
|
||||
let version = self.version;
|
||||
self.inner.and_then(move |(i, c), endpoint| {
|
||||
let upgrade = upgrade::apply(c, upgrade, endpoint, version);
|
||||
Multiplex { info: Some(i), upgrade }
|
||||
})
|
||||
}
|
||||
|
||||
/// Like [`Builder::multiplex`] but accepts a function which returns the upgrade.
|
||||
///
|
||||
/// The supplied function is applied to [`ConnectionInfo`] and [`ConnectedPoint`]
|
||||
/// and returns an upgrade which receives the I/O resource `C` and must
|
||||
/// produce a [`StreamMuxer`] `M`. The transport must already be authenticated.
|
||||
/// This ends the (regular) transport upgrade process, yielding the underlying,
|
||||
/// configured transport.
|
||||
///
|
||||
/// ## Transitions
|
||||
///
|
||||
/// * I/O upgrade: `C -> M`.
|
||||
/// * Transport output: `(I, C) -> (I, M)`.
|
||||
pub fn multiplex_ext<C, M, U, I, E, F>(self, up: F)
|
||||
-> AndThen<T, impl FnOnce((I, C), ConnectedPoint) -> Multiplex<C, U, I> + Clone>
|
||||
where
|
||||
T: Transport<Output = (I, C)>,
|
||||
C: AsyncRead + AsyncWrite + Unpin,
|
||||
M: StreamMuxer,
|
||||
I: ConnectionInfo,
|
||||
U: InboundUpgrade<Negotiated<C>, Output = M, Error = E>,
|
||||
U: OutboundUpgrade<Negotiated<C>, Output = M, Error = E> + Clone,
|
||||
E: Error + 'static,
|
||||
F: for<'a> FnOnce(&'a I, &'a ConnectedPoint) -> U + Clone
|
||||
{
|
||||
let version = self.version;
|
||||
self.inner.and_then(move |(i, c), endpoint| {
|
||||
let upgrade = upgrade::apply(c, up(&i, &endpoint), endpoint, version);
|
||||
Multiplex { info: Some(i), upgrade }
|
||||
})
|
||||
}), version))
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,7 +159,7 @@ where
|
||||
/// An upgrade that negotiates a (sub)stream multiplexer on
|
||||
/// top of an authenticated transport.
|
||||
///
|
||||
/// Configured through [`Builder::multiplex`].
|
||||
/// Configured through [`Authenticated::multiplex`].
|
||||
#[pin_project::pin_project]
|
||||
pub struct Multiplex<C, U, I>
|
||||
where
|
||||
@ -265,10 +190,162 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// An transport with peer authentication, obtained from [`Builder::authenticate`].
|
||||
#[derive(Clone)]
|
||||
pub struct Authenticated<T>(Builder<T>);
|
||||
|
||||
impl<T> Authenticated<T>
|
||||
where
|
||||
T: Transport,
|
||||
T::Error: 'static
|
||||
{
|
||||
/// Applies an arbitrary upgrade.
|
||||
///
|
||||
/// The upgrade receives the I/O resource (i.e. connection) `C` and
|
||||
/// must produce a new I/O resource `D`. Any number of such upgrades
|
||||
/// can be performed.
|
||||
///
|
||||
/// ## Transitions
|
||||
///
|
||||
/// * I/O upgrade: `C -> D`.
|
||||
/// * Transport output: `(I, C) -> (I, D)`.
|
||||
pub fn apply<C, D, U, I, E>(self, upgrade: U) -> Authenticated<Upgrade<T, U>>
|
||||
where
|
||||
T: Transport<Output = (I, C)>,
|
||||
C: AsyncRead + AsyncWrite + Unpin,
|
||||
D: AsyncRead + AsyncWrite + Unpin,
|
||||
I: ConnectionInfo,
|
||||
U: InboundUpgrade<Negotiated<C>, Output = D, Error = E>,
|
||||
U: OutboundUpgrade<Negotiated<C>, Output = D, Error = E> + Clone,
|
||||
E: Error + 'static,
|
||||
{
|
||||
Authenticated(Builder::new(Upgrade::new(self.0.inner, upgrade), self.0.version))
|
||||
}
|
||||
|
||||
/// Upgrades the transport with a (sub)stream multiplexer.
|
||||
///
|
||||
/// The supplied upgrade receives the I/O resource `C` and must
|
||||
/// produce a [`StreamMuxer`] `M`. The transport must already be authenticated.
|
||||
/// This ends the (regular) transport upgrade process.
|
||||
///
|
||||
/// ## Transitions
|
||||
///
|
||||
/// * I/O upgrade: `C -> M`.
|
||||
/// * Transport output: `(I, C) -> (I, M)`.
|
||||
pub fn multiplex<C, M, U, I, E>(self, upgrade: U) -> Multiplexed<
|
||||
AndThen<T, impl FnOnce((I, C), ConnectedPoint) -> Multiplex<C, U, I> + Clone>
|
||||
> where
|
||||
T: Transport<Output = (I, C)>,
|
||||
C: AsyncRead + AsyncWrite + Unpin,
|
||||
M: StreamMuxer,
|
||||
I: ConnectionInfo,
|
||||
U: InboundUpgrade<Negotiated<C>, Output = M, Error = E>,
|
||||
U: OutboundUpgrade<Negotiated<C>, Output = M, Error = E> + Clone,
|
||||
E: Error + 'static,
|
||||
{
|
||||
let version = self.0.version;
|
||||
Multiplexed(self.0.inner.and_then(move |(i, c), endpoint| {
|
||||
let upgrade = upgrade::apply(c, upgrade, endpoint, version);
|
||||
Multiplex { info: Some(i), upgrade }
|
||||
}))
|
||||
}
|
||||
|
||||
/// Like [`Authenticated::multiplex`] but accepts a function which returns the upgrade.
|
||||
///
|
||||
/// The supplied function is applied to [`ConnectionInfo`] and [`ConnectedPoint`]
|
||||
/// and returns an upgrade which receives the I/O resource `C` and must
|
||||
/// produce a [`StreamMuxer`] `M`. The transport must already be authenticated.
|
||||
/// This ends the (regular) transport upgrade process.
|
||||
///
|
||||
/// ## Transitions
|
||||
///
|
||||
/// * I/O upgrade: `C -> M`.
|
||||
/// * Transport output: `(I, C) -> (I, M)`.
|
||||
pub fn multiplex_ext<C, M, U, I, E, F>(self, up: F) -> Multiplexed<
|
||||
AndThen<T, impl FnOnce((I, C), ConnectedPoint) -> Multiplex<C, U, I> + Clone>
|
||||
> where
|
||||
T: Transport<Output = (I, C)>,
|
||||
C: AsyncRead + AsyncWrite + Unpin,
|
||||
M: StreamMuxer,
|
||||
I: ConnectionInfo,
|
||||
U: InboundUpgrade<Negotiated<C>, Output = M, Error = E>,
|
||||
U: OutboundUpgrade<Negotiated<C>, Output = M, Error = E> + Clone,
|
||||
E: Error + 'static,
|
||||
F: for<'a> FnOnce(&'a I, &'a ConnectedPoint) -> U + Clone
|
||||
{
|
||||
let version = self.0.version;
|
||||
Multiplexed(self.0.inner.and_then(move |(i, c), endpoint| {
|
||||
let upgrade = upgrade::apply(c, up(&i, &endpoint), endpoint, version);
|
||||
Multiplex { info: Some(i), upgrade }
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// A authenticated and multiplexed transport, obtained from
|
||||
/// [`Authenticated::multiplex`].
|
||||
#[derive(Clone)]
|
||||
pub struct Multiplexed<T>(T);
|
||||
|
||||
impl<T> Multiplexed<T> {
|
||||
/// Boxes the authenticated, multiplexed transport, including
|
||||
/// the [`StreamMuxer`] and custom transport errors.
|
||||
pub fn boxed<I, M>(self) -> super::Boxed<(I, StreamMuxerBox)>
|
||||
where
|
||||
T: Transport<Output = (I, M)> + Sized + Clone + Send + Sync + 'static,
|
||||
T::Dial: Send + 'static,
|
||||
T::Listener: Send + 'static,
|
||||
T::ListenerUpgrade: Send + 'static,
|
||||
T::Error: Send + Sync,
|
||||
I: ConnectionInfo,
|
||||
M: StreamMuxer + Send + Sync + 'static,
|
||||
M::Substream: Send + 'static,
|
||||
M::OutboundSubstream: Send + 'static
|
||||
{
|
||||
boxed(self.map(|(i, m), _| (i, StreamMuxerBox::new(m))))
|
||||
}
|
||||
|
||||
/// Adds a timeout to the setup and protocol upgrade process for all
|
||||
/// inbound and outbound connections established through the transport.
|
||||
pub fn timeout(self, timeout: Duration) -> Multiplexed<TransportTimeout<T>> {
|
||||
Multiplexed(TransportTimeout::new(self.0, timeout))
|
||||
}
|
||||
|
||||
/// Adds a timeout to the setup and protocol upgrade process for all
|
||||
/// outbound connections established through the transport.
|
||||
pub fn outbound_timeout(self, timeout: Duration) -> Multiplexed<TransportTimeout<T>> {
|
||||
Multiplexed(TransportTimeout::with_outgoing_timeout(self.0, timeout))
|
||||
}
|
||||
|
||||
/// Adds a timeout to the setup and protocol upgrade process for all
|
||||
/// inbound connections established through the transport.
|
||||
pub fn inbound_timeout(self, timeout: Duration) -> Multiplexed<TransportTimeout<T>> {
|
||||
Multiplexed(TransportTimeout::with_ingoing_timeout(self.0, timeout))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Transport for Multiplexed<T>
|
||||
where
|
||||
T: Transport,
|
||||
{
|
||||
type Output = T::Output;
|
||||
type Error = T::Error;
|
||||
type Listener = T::Listener;
|
||||
type ListenerUpgrade = T::ListenerUpgrade;
|
||||
type Dial = T::Dial;
|
||||
|
||||
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
|
||||
self.0.dial(addr)
|
||||
}
|
||||
|
||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, TransportError<Self::Error>> {
|
||||
self.0.listen_on(addr)
|
||||
}
|
||||
}
|
||||
|
||||
/// An inbound or outbound upgrade.
|
||||
type EitherUpgrade<C, U> = future::Either<InboundUpgradeApply<C, U>, OutboundUpgradeApply<C, U>>;
|
||||
|
||||
/// An upgrade on an authenticated, non-multiplexed [`Transport`].
|
||||
/// A custom upgrade on an [`Authenticated`] transport.
|
||||
///
|
||||
/// See [`Transport::upgrade`]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
|
@ -40,7 +40,7 @@ use std::{io, task::Poll};
|
||||
use util::TestHandler;
|
||||
|
||||
type TestNetwork = Network<TestTransport, (), (), TestHandler>;
|
||||
type TestTransport = transport::Boxed<(PeerId, StreamMuxerBox), io::Error>;
|
||||
type TestTransport = transport::Boxed<(PeerId, StreamMuxerBox)>;
|
||||
|
||||
fn new_network(cfg: NetworkConfig) -> TestNetwork {
|
||||
let local_key = identity::Keypair::generate_ed25519();
|
||||
@ -50,6 +50,7 @@ fn new_network(cfg: NetworkConfig) -> TestNetwork {
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(libp2p_mplex::MplexConfig::new())
|
||||
.boxed()
|
||||
.and_then(|(peer, mplex), _| {
|
||||
// Gracefully close the connection to allow protocol
|
||||
// negotiation to complete.
|
||||
|
@ -77,7 +77,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
let transport = TokioTcpConfig::new().nodelay(true)
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(mplex::MplexConfig::new());
|
||||
.multiplex(mplex::MplexConfig::new())
|
||||
.boxed();
|
||||
|
||||
// Create a Floodsub topic
|
||||
let floodsub_topic = floodsub::Topic::new("chat");
|
||||
|
@ -34,7 +34,7 @@
|
||||
use async_std::{io, task};
|
||||
use futures::{future, prelude::*};
|
||||
use libp2p::{
|
||||
core::{either::EitherTransport, transport::upgrade::Version, StreamMuxer},
|
||||
core::{either::EitherTransport, transport, transport::upgrade::Version, muxing::StreamMuxerBox},
|
||||
gossipsub::{self, Gossipsub, GossipsubConfigBuilder, GossipsubEvent, MessageAuthenticity},
|
||||
identify::{Identify, IdentifyEvent},
|
||||
identity,
|
||||
@ -61,21 +61,8 @@ use std::{
|
||||
pub fn build_transport(
|
||||
key_pair: identity::Keypair,
|
||||
psk: Option<PreSharedKey>,
|
||||
) -> impl Transport<
|
||||
Output = (
|
||||
PeerId,
|
||||
impl StreamMuxer<
|
||||
OutboundSubstream = impl Send,
|
||||
Substream = impl Send,
|
||||
Error = impl Into<io::Error>,
|
||||
> + Send
|
||||
+ Sync,
|
||||
),
|
||||
Error = impl Error + Send,
|
||||
Listener = impl Send,
|
||||
Dial = impl Send,
|
||||
ListenerUpgrade = impl Send,
|
||||
> + Clone {
|
||||
) -> transport::Boxed<(PeerId, StreamMuxerBox)>
|
||||
{
|
||||
let noise_keys = noise::Keypair::<noise::X25519Spec>::new().into_authentic(&key_pair).unwrap();
|
||||
let noise_config = noise::NoiseConfig::xx(noise_keys).into_authenticated();
|
||||
let yamux_config = YamuxConfig::default();
|
||||
@ -92,6 +79,7 @@ pub fn build_transport(
|
||||
.authenticate(noise_config)
|
||||
.multiplex(yamux_config)
|
||||
.timeout(Duration::from_secs(20))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
/// Get the current ipfs repo path, either from the IPFS_PATH environment variable or
|
||||
|
@ -37,7 +37,7 @@ use futures::{channel::oneshot, ready, prelude::*};
|
||||
use rand::random;
|
||||
use std::{io, task::{Context, Poll}};
|
||||
|
||||
type TestTransport = transport::Boxed<(PeerId, StreamMuxerBox), io::Error>;
|
||||
type TestTransport = transport::Boxed<(PeerId, StreamMuxerBox)>;
|
||||
type TestNetwork = Network<TestTransport, (), (), TestHandler>;
|
||||
|
||||
fn mk_transport(up: upgrade::Version) -> (PeerId, TestTransport) {
|
||||
|
@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
bytes = "0.5"
|
||||
futures = "0.3.1"
|
||||
futures_codec = "0.4"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4"
|
||||
nohash-hasher = "0.2"
|
||||
parking_lot = "0.11"
|
||||
|
@ -1,3 +1,7 @@
|
||||
# 0.26.0 [unreleased]
|
||||
|
||||
- Update `libp2p-core`.
|
||||
|
||||
# 0.25.0 [2020-09-09]
|
||||
|
||||
- Update to `yamux-0.8.0`. Upgrade step 4 of 4. This version always implements
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-yamux"
|
||||
edition = "2018"
|
||||
description = "Yamux multiplexing protocol for libp2p"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -11,7 +11,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
parking_lot = "0.11"
|
||||
thiserror = "1.0"
|
||||
yamux = "0.8.0"
|
@ -1,3 +1,7 @@
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Bump `libp2p-core` dependency.
|
||||
|
||||
# 0.22.0 [2020-09-09]
|
||||
|
||||
- Bump `libp2p-core` dependency.
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-deflate"
|
||||
edition = "2018"
|
||||
description = "Deflate encryption protocol for libp2p"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -11,7 +11,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
flate2 = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -13,8 +13,8 @@ categories = ["network-programming", "asynchronous"]
|
||||
cuckoofilter = "0.5.0"
|
||||
fnv = "1.0"
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.22.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.23.0", path = "../../swarm" }
|
||||
log = "0.4"
|
||||
prost = "0.6.1"
|
||||
rand = "0.7"
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 0.22.1 [unreleased]
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update dependencies.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-gossipsub"
|
||||
edition = "2018"
|
||||
description = "Gossipsub protocol for libp2p"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0"
|
||||
authors = ["Age Manning <Age@AgeManning.com>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -10,8 +10,8 @@ keywords = ["peer-to-peer", "libp2p", "networking"]
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
libp2p-swarm = { version = "0.22.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.23.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
bytes = "0.5.4"
|
||||
byteorder = "1.3.2"
|
||||
fnv = "1.0.6"
|
||||
|
@ -150,7 +150,8 @@ fn build_node() -> (Multiaddr, Swarm<Gossipsub>) {
|
||||
.authenticate(PlainText2Config {
|
||||
local_public_key: public_key.clone(),
|
||||
})
|
||||
.multiplex(yamux::Config::default());
|
||||
.multiplex(yamux::Config::default())
|
||||
.boxed();
|
||||
|
||||
let peer_id = public_key.clone().into_peer_id();
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update `libp2p-swarm` and `libp2p-core`.
|
||||
|
||||
# 0.22.0 [2020-09-09]
|
||||
|
||||
- Update `libp2p-swarm` and `libp2p-core`.
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-identify"
|
||||
edition = "2018"
|
||||
description = "Nodes identifcation protocol for libp2p"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -11,8 +11,8 @@ categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.22.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.23.0", path = "../../swarm" }
|
||||
log = "0.4.1"
|
||||
prost = "0.6.1"
|
||||
smallvec = "1.0"
|
||||
|
@ -273,7 +273,8 @@ mod tests {
|
||||
use libp2p_core::{
|
||||
identity,
|
||||
PeerId,
|
||||
muxing::StreamMuxer,
|
||||
muxing::StreamMuxerBox,
|
||||
transport,
|
||||
Transport,
|
||||
upgrade
|
||||
};
|
||||
@ -281,15 +282,8 @@ mod tests {
|
||||
use libp2p_tcp::TcpConfig;
|
||||
use libp2p_swarm::{Swarm, SwarmEvent};
|
||||
use libp2p_mplex::MplexConfig;
|
||||
use std::{fmt, io};
|
||||
|
||||
fn transport() -> (identity::PublicKey, impl Transport<
|
||||
Output = (PeerId, impl StreamMuxer<Substream = impl Send, OutboundSubstream = impl Send, Error = impl Into<io::Error>>),
|
||||
Listener = impl Send,
|
||||
ListenerUpgrade = impl Send,
|
||||
Dial = impl Send,
|
||||
Error = impl fmt::Debug
|
||||
> + Clone) {
|
||||
fn transport() -> (identity::PublicKey, transport::Boxed<(PeerId, StreamMuxerBox)>) {
|
||||
let id_keys = identity::Keypair::generate_ed25519();
|
||||
let noise_keys = noise::Keypair::<noise::X25519Spec>::new().into_authentic(&id_keys).unwrap();
|
||||
let pubkey = id_keys.public();
|
||||
@ -297,7 +291,8 @@ mod tests {
|
||||
.nodelay(true)
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(MplexConfig::new());
|
||||
.multiplex(MplexConfig::new())
|
||||
.boxed();
|
||||
(pubkey, transport)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
# 0.23.1 [unreleased]
|
||||
# 0.24.0 [unreleased]
|
||||
|
||||
- Update `libp2p-core` and `libp2p-swarm`.
|
||||
|
||||
- Update `sha2` dependency.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-kad"
|
||||
edition = "2018"
|
||||
description = "Kademlia protocol for libp2p"
|
||||
version = "0.23.1"
|
||||
version = "0.24.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -17,8 +17,8 @@ fnv = "1.0"
|
||||
futures_codec = "0.4"
|
||||
futures = "0.3.1"
|
||||
log = "0.4"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.22.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.23.0", path = "../../swarm" }
|
||||
multihash = "0.11.0"
|
||||
prost = "0.6.1"
|
||||
rand = "0.7.2"
|
||||
|
@ -61,7 +61,8 @@ fn build_node_with_config(cfg: KademliaConfig) -> (Multiaddr, TestSwarm) {
|
||||
let transport = MemoryTransport::default()
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(yamux::Config::default());
|
||||
.multiplex(yamux::Config::default())
|
||||
.boxed();
|
||||
|
||||
let local_id = local_public_key.clone().into_peer_id();
|
||||
let store = MemoryStore::new(local_id.clone());
|
||||
|
@ -1,4 +1,6 @@
|
||||
# 0.22.1 [unreleased]
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update `libp2p-swarm` and `libp2p-core`.
|
||||
|
||||
- Double receive buffer to 4KiB. [PR 1779](https://github.com/libp2p/rust-libp2p/pull/1779/files).
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "libp2p-mdns"
|
||||
edition = "2018"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0"
|
||||
description = "Implementation of the libp2p mDNS discovery method"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
@ -16,8 +16,8 @@ dns-parser = "0.8"
|
||||
either = "1.5.3"
|
||||
futures = "0.3.1"
|
||||
lazy_static = "1.2"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.22.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.23.0", path = "../../swarm" }
|
||||
log = "0.4"
|
||||
net2 = "0.2"
|
||||
rand = "0.7"
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 0.24.1 [unreleased]
|
||||
# 0.25.0 [unreleased]
|
||||
|
||||
- Update dependencies.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "libp2p-noise"
|
||||
description = "Cryptographic handshake protocol using the noise framework."
|
||||
version = "0.24.1"
|
||||
version = "0.25.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -12,7 +12,7 @@ bytes = "0.5"
|
||||
curve25519-dalek = "3.0.0"
|
||||
futures = "0.3.1"
|
||||
lazy_static = "1.2"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4"
|
||||
prost = "0.6.1"
|
||||
rand = "0.7.2"
|
||||
|
@ -1,4 +1,6 @@
|
||||
# 0.22.1 [unreleased]
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update `libp2p-swarm` and `libp2p-core`.
|
||||
|
||||
- Ensure the outbound ping is flushed before awaiting
|
||||
the response. Otherwise the behaviour depends on
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-ping"
|
||||
edition = "2018"
|
||||
description = "Ping protocol for libp2p"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -11,8 +11,8 @@ categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.22.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.23.0", path = "../../swarm" }
|
||||
log = "0.4.1"
|
||||
rand = "0.7.2"
|
||||
void = "1.0"
|
||||
|
@ -37,7 +37,7 @@ use libp2p_yamux as yamux;
|
||||
use futures::{prelude::*, channel::mpsc};
|
||||
use quickcheck::*;
|
||||
use rand::prelude::*;
|
||||
use std::{io, num::NonZeroU8, time::Duration};
|
||||
use std::{num::NonZeroU8, time::Duration};
|
||||
|
||||
#[test]
|
||||
fn ping_pong() {
|
||||
@ -196,10 +196,7 @@ fn max_failures() {
|
||||
|
||||
fn mk_transport(muxer: MuxerChoice) -> (
|
||||
PeerId,
|
||||
transport::Boxed<
|
||||
(PeerId, StreamMuxerBox),
|
||||
io::Error
|
||||
>
|
||||
transport::Boxed<(PeerId, StreamMuxerBox)>
|
||||
) {
|
||||
let id_keys = identity::Keypair::generate_ed25519();
|
||||
let peer_id = id_keys.public().into_peer_id();
|
||||
|
@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
bytes = "0.5"
|
||||
futures = "0.3.1"
|
||||
futures_codec = "0.4.0"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4.8"
|
||||
prost = "0.6.1"
|
||||
unsigned-varint = { version = "0.5.1", features = ["futures-codec"] }
|
||||
|
@ -13,8 +13,8 @@ categories = ["network-programming", "asynchronous"]
|
||||
async-trait = "0.1"
|
||||
bytes = "0.5.6"
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.22.0", path = "../../swarm" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
libp2p-swarm = { version = "0.23.0", path = "../../swarm" }
|
||||
log = "0.4.11"
|
||||
lru = "0.6"
|
||||
minicbor = { version = "0.6", features = ["std", "derive"] }
|
||||
|
@ -213,7 +213,7 @@ fn ping_protocol_throttled() {
|
||||
let () = async_std::task::block_on(peer2);
|
||||
}
|
||||
|
||||
fn mk_transport() -> (PeerId, transport::Boxed<(PeerId, StreamMuxerBox), io::Error>) {
|
||||
fn mk_transport() -> (PeerId, transport::Boxed<(PeerId, StreamMuxerBox)>) {
|
||||
let id_keys = identity::Keypair::generate_ed25519();
|
||||
let peer_id = id_keys.public().into_peer_id();
|
||||
let noise_keys = Keypair::<X25519Spec>::new().into_authentic(&id_keys).unwrap();
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 0.22.1 [unreleased]
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update dependencies.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-secio"
|
||||
edition = "2018"
|
||||
description = "Secio encryption protocol for libp2p"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -19,7 +19,7 @@ ctr = "0.3"
|
||||
futures = "0.3.1"
|
||||
hmac = "0.9.0"
|
||||
lazy_static = "1.2.0"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4.6"
|
||||
prost = "0.6.1"
|
||||
pin-project = "1.0.0"
|
||||
|
@ -271,7 +271,7 @@ pub use self::transport_ext::TransportExt;
|
||||
#[cfg(all(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")), any(feature = "tcp-async-std", feature = "tcp-tokio"), feature = "websocket", feature = "noise", feature = "mplex", feature = "yamux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")), any(feature = "tcp-async-std", feature = "tcp-tokio"), feature = "websocket", feature = "noise", feature = "mplex", feature = "yamux"))))]
|
||||
pub fn build_development_transport(keypair: identity::Keypair)
|
||||
-> std::io::Result<impl Transport<Output = (PeerId, impl core::muxing::StreamMuxer<OutboundSubstream = impl Send, Substream = impl Send, Error = impl Into<std::io::Error>> + Send + Sync), Error = impl std::error::Error + Send, Listener = impl Send, Dial = impl Send, ListenerUpgrade = impl Send> + Clone>
|
||||
-> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>>
|
||||
{
|
||||
build_tcp_ws_noise_mplex_yamux(keypair)
|
||||
}
|
||||
@ -283,7 +283,7 @@ pub fn build_development_transport(keypair: identity::Keypair)
|
||||
#[cfg(all(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")), any(feature = "tcp-async-std", feature = "tcp-tokio"), feature = "websocket", feature = "noise", feature = "mplex", feature = "yamux"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")), any(feature = "tcp-async-std", feature = "tcp-tokio"), feature = "websocket", feature = "noise", feature = "mplex", feature = "yamux"))))]
|
||||
pub fn build_tcp_ws_noise_mplex_yamux(keypair: identity::Keypair)
|
||||
-> std::io::Result<impl Transport<Output = (PeerId, impl core::muxing::StreamMuxer<OutboundSubstream = impl Send, Substream = impl Send, Error = impl Into<std::io::Error>> + Send + Sync), Error = impl std::error::Error + Send, Listener = impl Send, Dial = impl Send, ListenerUpgrade = impl Send> + Clone>
|
||||
-> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>>
|
||||
{
|
||||
let transport = {
|
||||
#[cfg(feature = "tcp-async-std")]
|
||||
@ -314,7 +314,7 @@ pub fn build_tcp_ws_noise_mplex_yamux(keypair: identity::Keypair)
|
||||
#[cfg(all(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")), any(feature = "tcp-async-std", feature = "tcp-tokio"), feature = "websocket", feature = "noise", feature = "mplex", feature = "yamux", feature = "pnet"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")), any(feature = "tcp-async-std", feature = "tcp-tokio"), feature = "websocket", feature = "noise", feature = "mplex", feature = "yamux", feature = "pnet"))))]
|
||||
pub fn build_tcp_ws_pnet_noise_mplex_yamux(keypair: identity::Keypair, psk: PreSharedKey)
|
||||
-> std::io::Result<impl Transport<Output = (PeerId, impl core::muxing::StreamMuxer<OutboundSubstream = impl Send, Substream = impl Send, Error = impl Into<std::io::Error>> + Send + Sync), Error = impl std::error::Error + Send, Listener = impl Send, Dial = impl Send, ListenerUpgrade = impl Send> + Clone>
|
||||
-> std::io::Result<core::transport::Boxed<(PeerId, core::muxing::StreamMuxerBox)>>
|
||||
{
|
||||
let transport = {
|
||||
#[cfg(feature = "tcp-async-std")]
|
||||
|
@ -1,4 +1,9 @@
|
||||
# 0.22.1 [unreleased]
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Require a `Boxed` transport to be given to the `Swarm`
|
||||
or `SwarmBuilder` to avoid unnecessary double-boxing of
|
||||
transports and simplify API bounds.
|
||||
[PR 1794](https://github.com/libp2p/rust-libp2p/pull/1794)
|
||||
|
||||
- Respect inbound timeouts and upgrade versions in the `MultiHandler`.
|
||||
[PR 1786](https://github.com/libp2p/rust-libp2p/pull/1786).
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-swarm"
|
||||
edition = "2018"
|
||||
description = "The libp2p swarm"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
[dependencies]
|
||||
either = "1.6.0"
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../core" }
|
||||
log = "0.4"
|
||||
rand = "0.7"
|
||||
smallvec = "1.0"
|
||||
|
@ -111,7 +111,7 @@ use libp2p_core::{
|
||||
Substream
|
||||
},
|
||||
transport::{self, TransportError},
|
||||
muxing::{StreamMuxer, StreamMuxerBox},
|
||||
muxing::StreamMuxerBox,
|
||||
network::{
|
||||
Network,
|
||||
NetworkInfo,
|
||||
@ -261,7 +261,7 @@ where
|
||||
TConnInfo: ConnectionInfo<PeerId = PeerId>,
|
||||
{
|
||||
network: Network<
|
||||
transport::Boxed<(TConnInfo, StreamMuxerBox), io::Error>,
|
||||
transport::Boxed<(TConnInfo, StreamMuxerBox)>,
|
||||
TInEvent,
|
||||
TOutEvent,
|
||||
NodeHandlerWrapperBuilder<THandler>,
|
||||
@ -335,20 +335,12 @@ where TBehaviour: NetworkBehaviour<ProtocolsHandler = THandler>,
|
||||
THandleErr: error::Error + Send + 'static,
|
||||
{
|
||||
/// Builds a new `Swarm`.
|
||||
pub fn new<TTransport, TMuxer>(transport: TTransport, behaviour: TBehaviour, local_peer_id: PeerId) -> Self
|
||||
where
|
||||
TMuxer: StreamMuxer + Send + Sync + 'static,
|
||||
TMuxer::OutboundSubstream: Send + 'static,
|
||||
<TMuxer as StreamMuxer>::OutboundSubstream: Send + 'static,
|
||||
<TMuxer as StreamMuxer>::Substream: Send + 'static,
|
||||
TTransport: Transport<Output = (TConnInfo, TMuxer)> + Clone + Send + Sync + 'static,
|
||||
TTransport::Error: Send + Sync + 'static,
|
||||
TTransport::Listener: Send + 'static,
|
||||
TTransport::ListenerUpgrade: Send + 'static,
|
||||
TTransport::Dial: Send + 'static,
|
||||
{
|
||||
SwarmBuilder::new(transport, behaviour, local_peer_id)
|
||||
.build()
|
||||
pub fn new(
|
||||
transport: transport::Boxed<(TConnInfo, StreamMuxerBox)>,
|
||||
behaviour: TBehaviour,
|
||||
local_peer_id: PeerId
|
||||
) -> Self {
|
||||
SwarmBuilder::new(transport, behaviour, local_peer_id).build()
|
||||
}
|
||||
|
||||
/// Returns information about the [`Network`] underlying the `Swarm`.
|
||||
@ -972,7 +964,7 @@ impl<'a> PollParameters for SwarmPollParameters<'a> {
|
||||
/// including the underlying [`Network`].
|
||||
pub struct SwarmBuilder<TBehaviour, TConnInfo> {
|
||||
local_peer_id: PeerId,
|
||||
transport: transport::Boxed<(TConnInfo, StreamMuxerBox), io::Error>,
|
||||
transport: transport::Boxed<(TConnInfo, StreamMuxerBox)>,
|
||||
behaviour: TBehaviour,
|
||||
network_config: NetworkConfig,
|
||||
}
|
||||
@ -984,21 +976,14 @@ where TBehaviour: NetworkBehaviour,
|
||||
/// Creates a new `SwarmBuilder` from the given transport, behaviour and
|
||||
/// local peer ID. The `Swarm` with its underlying `Network` is obtained
|
||||
/// via [`SwarmBuilder::build`].
|
||||
pub fn new<TTrans, TMuxer>(transport: TTrans, behaviour: TBehaviour, local_peer_id: PeerId) -> Self
|
||||
where
|
||||
TMuxer: StreamMuxer + Send + Sync + 'static,
|
||||
TMuxer::OutboundSubstream: Send + 'static,
|
||||
<TMuxer as StreamMuxer>::OutboundSubstream: Send + 'static,
|
||||
<TMuxer as StreamMuxer>::Substream: Send + 'static,
|
||||
TTrans: Transport<Output = (TConnInfo, TMuxer)> + Clone + Send + Sync + 'static,
|
||||
TTrans::Error: Send + Sync + 'static,
|
||||
TTrans::Listener: Send + 'static,
|
||||
TTrans::ListenerUpgrade: Send + 'static,
|
||||
TTrans::Dial: Send + 'static,
|
||||
{
|
||||
pub fn new(
|
||||
transport: transport::Boxed<(TConnInfo, StreamMuxerBox)>,
|
||||
behaviour: TBehaviour,
|
||||
local_peer_id: PeerId
|
||||
) -> Self {
|
||||
SwarmBuilder {
|
||||
local_peer_id,
|
||||
transport: transport.boxed(),
|
||||
transport: transport,
|
||||
behaviour,
|
||||
network_config: Default::default(),
|
||||
}
|
||||
@ -1193,16 +1178,11 @@ mod tests {
|
||||
identity,
|
||||
upgrade,
|
||||
multiaddr,
|
||||
transport::{self, dummy::*}
|
||||
transport
|
||||
};
|
||||
use libp2p_mplex::Multiplex;
|
||||
use libp2p_noise as noise;
|
||||
use super::*;
|
||||
|
||||
fn get_random_id() -> identity::PublicKey {
|
||||
identity::Keypair::generate_ed25519().public()
|
||||
}
|
||||
|
||||
fn new_test_swarm<T, O>(handler_proto: T) -> Swarm<CallTraceBehaviour<MockBehaviour<T, O>>>
|
||||
where
|
||||
T: ProtocolsHandler + Clone,
|
||||
@ -1215,30 +1195,12 @@ mod tests {
|
||||
let transport = transport::MemoryTransport::default()
|
||||
.upgrade(upgrade::Version::V1)
|
||||
.authenticate(noise::NoiseConfig::xx(noise_keys).into_authenticated())
|
||||
.multiplex(libp2p_mplex::MplexConfig::new());
|
||||
.multiplex(libp2p_mplex::MplexConfig::new())
|
||||
.boxed();
|
||||
let behaviour = CallTraceBehaviour::new(MockBehaviour::new(handler_proto));
|
||||
SwarmBuilder::new(transport, behaviour, pubkey.into()).build()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_swarm() {
|
||||
let id = get_random_id();
|
||||
let transport = DummyTransport::<(PeerId, Multiplex<DummyStream>)>::new();
|
||||
let behaviour = DummyBehaviour {};
|
||||
let swarm = SwarmBuilder::new(transport, behaviour, id.into())
|
||||
.incoming_connection_limit(4)
|
||||
.build();
|
||||
assert_eq!(swarm.network.incoming_limit(), Some(4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_swarm_with_max_listeners_none() {
|
||||
let id = get_random_id();
|
||||
let transport = DummyTransport::<(PeerId, Multiplex<DummyStream>)>::new();
|
||||
let swarm = SwarmBuilder::new(transport, DummyBehaviour {}, id.into()).build();
|
||||
assert!(swarm.network.incoming_limit().is_none())
|
||||
}
|
||||
|
||||
/// Establishes a number of connections between two peers,
|
||||
/// after which one peer bans the other.
|
||||
///
|
||||
|
@ -1,3 +1,7 @@
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Bump `libp2p-core` dependency.
|
||||
|
||||
# 0.22.0 [2020-09-09]
|
||||
|
||||
- Bump `libp2p-core` dependency.
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-dns"
|
||||
edition = "2018"
|
||||
description = "DNS transport implementation for libp2p"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -10,6 +10,6 @@ keywords = ["peer-to-peer", "libp2p", "networking"]
|
||||
categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4.1"
|
||||
futures = "0.3.1"
|
||||
|
@ -1,4 +1,6 @@
|
||||
# 0.22.1 [unreleased]
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update `libp2p-core`.
|
||||
|
||||
- Replace `get_if_addrs` with `if-addrs`.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-tcp"
|
||||
edition = "2018"
|
||||
description = "TCP/IP transport protocol for libp2p"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -15,7 +15,7 @@ futures = "0.3.1"
|
||||
futures-timer = "3.0"
|
||||
if-addrs = "0.6.4"
|
||||
ipnet = "2.0.0"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4.1"
|
||||
socket2 = "0.3.12"
|
||||
tokio = { version = "0.2", default-features = false, features = ["tcp"], optional = true }
|
||||
|
@ -1,3 +1,7 @@
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update `libp2p-core` dependency.
|
||||
|
||||
# 0.22.0 [2020-09-09]
|
||||
|
||||
- Update `libp2p-core` dependency.
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-uds"
|
||||
edition = "2018"
|
||||
description = "Unix domain sockets transport for libp2p"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -11,7 +11,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "emscripten")))'.dependencies]
|
||||
async-std = { version = "1.6.2", optional = true }
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4.1"
|
||||
futures = "0.3.1"
|
||||
tokio = { version = "0.2", default-features = false, features = ["uds"], optional = true }
|
||||
|
@ -1,3 +1,7 @@
|
||||
# 0.23.0 [unreleased]
|
||||
|
||||
- Update `libp2p-core` dependency.
|
||||
|
||||
# 0.22.0 [2020-09-09]
|
||||
|
||||
- Update `libp2p-core` dependency.
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libp2p-wasm-ext"
|
||||
version = "0.22.0"
|
||||
version = "0.23.0"
|
||||
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
||||
edition = "2018"
|
||||
description = "Allows passing in an external transport in a WASM environment"
|
||||
@ -12,7 +12,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
[dependencies]
|
||||
futures = "0.3.1"
|
||||
js-sys = "0.3.19"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
parity-send-wrapper = "0.1.0"
|
||||
wasm-bindgen = "0.2.42"
|
||||
wasm-bindgen-futures = "0.4.4"
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 0.23.1 [unreleased]
|
||||
# 0.24.0 [unreleased]
|
||||
|
||||
- Update dependencies.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "libp2p-websocket"
|
||||
edition = "2018"
|
||||
description = "WebSocket transport for libp2p"
|
||||
version = "0.23.1"
|
||||
version = "0.24.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/libp2p/rust-libp2p"
|
||||
@ -13,7 +13,7 @@ categories = ["network-programming", "asynchronous"]
|
||||
async-tls = "0.10.0"
|
||||
either = "1.5.3"
|
||||
futures = "0.3.1"
|
||||
libp2p-core = { version = "0.22.0", path = "../../core" }
|
||||
libp2p-core = { version = "0.23.0", path = "../../core" }
|
||||
log = "0.4.8"
|
||||
quicksink = "0.1"
|
||||
rustls = "0.18.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user