Skip to content

Commit

Permalink
Make transports optional (#192)
Browse files Browse the repository at this point in the history
Put extra transports behind feature flags to make some dependencies
optional.

While at it, also made sure no warnings are emitted on the recent rust
version.

Resolves #161.
  • Loading branch information
dmitry-markin authored Aug 6, 2024
1 parent 1e46373 commit 3b664f7
Show file tree
Hide file tree
Showing 30 changed files with 581 additions and 827 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:
cache-all-crates: true

- name: Cargo check
run: cargo check
run: cargo check --all-features

doc:
name: Check documentation
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:
cache-all-crates: true

- name: Run clippy
run: cargo clippy
run: cargo clippy --all-features

test:
name: Test
Expand All @@ -147,4 +147,4 @@ jobs:
cache-all-crates: true

- name: Run tests
run: cargo test
run: cargo test --all-features
19 changes: 15 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ network-interface = "1.1.1"
parking_lot = "0.12.3"
pin-project = "1.1.0"
prost = "0.12.6"
quinn = { version = "0.9.3", default-features = false, features = ["tls-rustls", "runtime-tokio"] }
quinn = { version = "0.9.3", default-features = false, features = ["tls-rustls", "runtime-tokio"], optional = true }
rand = { version = "0.8.0", features = ["getrandom"] }
rcgen = "0.10.0"
ring = "0.16.20"
Expand All @@ -36,18 +36,18 @@ simple-dns = "0.7.0"
smallvec = "1.13.2"
snow = { version = "0.9.3", features = ["ring-resolver"], default-features = false }
socket2 = { version = "0.5.7", features = ["all"] }
str0m = "0.5.1"
str0m = { version = "0.5.1", optional = true }
thiserror = "1.0.61"
tokio-stream = "0.1.12"
tokio-tungstenite = { version = "0.20.0", features = ["rustls-tls-native-roots"] }
tokio-tungstenite = { version = "0.20.0", features = ["rustls-tls-native-roots"], optional = true }
tokio-util = { version = "0.7.11", features = ["compat", "io", "codec"] }
tokio = { version = "1.26.0", features = ["rt", "net", "io-util", "time", "macros", "sync", "parking_lot"] }
tracing = { version = "0.1.40", features = ["log"] }
trust-dns-resolver = "0.23.2"
uint = "0.9.5"
unsigned-varint = { version = "0.8.0", features = ["codec"] }
url = "2.4.0"
webpki = "0.22.4"
webpki = { version = "0.22.4", optional = true }
x25519-dalek = "2.0.0"
x509-parser = "0.16.0"
yasna = "0.5.0"
Expand Down Expand Up @@ -87,6 +87,17 @@ futures_ringbuf = "0.4.0"

[features]
custom_sc_network = []
quic = ["dep:webpki", "dep:quinn"]
webrtc = ["dep:str0m"]
websocket = ["dep:tokio-tungstenite"]

[profile.release]
debug = true

[[example]]
name = "echo_notification"
required-features = ["quic"]

[[example]]
name = "syncing"
required-features = ["quic"]
27 changes: 24 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,20 @@ use crate::{
notification, request_response, UserProtocol,
},
transport::{
manager::limits::ConnectionLimitsConfig, quic::config::Config as QuicConfig,
tcp::config::Config as TcpConfig, webrtc::config::Config as WebRtcConfig,
websocket::config::Config as WebSocketConfig, MAX_PARALLEL_DIALS,
manager::limits::ConnectionLimitsConfig, tcp::config::Config as TcpConfig,
MAX_PARALLEL_DIALS,
},
types::protocol::ProtocolName,
PeerId,
};

#[cfg(feature = "quic")]
use crate::transport::quic::config::Config as QuicConfig;
#[cfg(feature = "webrtc")]
use crate::transport::webrtc::config::Config as WebRtcConfig;
#[cfg(feature = "websocket")]
use crate::transport::websocket::config::Config as WebSocketConfig;

use multiaddr::Multiaddr;

use std::{collections::HashMap, sync::Arc};
Expand Down Expand Up @@ -66,12 +72,15 @@ pub struct ConfigBuilder {
tcp: Option<TcpConfig>,

/// QUIC transport config.
#[cfg(feature = "quic")]
quic: Option<QuicConfig>,

/// WebRTC transport config.
#[cfg(feature = "webrtc")]
webrtc: Option<WebRtcConfig>,

/// WebSocket transport config.
#[cfg(feature = "websocket")]
websocket: Option<WebSocketConfig>,

/// Keypair.
Expand Down Expand Up @@ -125,8 +134,11 @@ impl ConfigBuilder {
pub fn new() -> Self {
Self {
tcp: None,
#[cfg(feature = "quic")]
quic: None,
#[cfg(feature = "webrtc")]
webrtc: None,
#[cfg(feature = "websocket")]
websocket: None,
keypair: None,
ping: None,
Expand All @@ -151,18 +163,21 @@ impl ConfigBuilder {
}

/// Add QUIC transport configuration, enabling the transport.
#[cfg(feature = "quic")]
pub fn with_quic(mut self, config: QuicConfig) -> Self {
self.quic = Some(config);
self
}

/// Add WebRTC transport configuration, enabling the transport.
#[cfg(feature = "webrtc")]
pub fn with_webrtc(mut self, config: WebRtcConfig) -> Self {
self.webrtc = Some(config);
self
}

/// Add WebSocket transport configuration, enabling the transport.
#[cfg(feature = "websocket")]
pub fn with_websocket(mut self, config: WebSocketConfig) -> Self {
self.websocket = Some(config);
self
Expand Down Expand Up @@ -264,8 +279,11 @@ impl ConfigBuilder {
keypair,
tcp: self.tcp.take(),
mdns: self.mdns.take(),
#[cfg(feature = "quic")]
quic: self.quic.take(),
#[cfg(feature = "webrtc")]
webrtc: self.webrtc.take(),
#[cfg(feature = "websocket")]
websocket: self.websocket.take(),
ping: self.ping.take(),
identify: self.identify.take(),
Expand All @@ -288,12 +306,15 @@ pub struct Litep2pConfig {
pub(crate) tcp: Option<TcpConfig>,

/// QUIC transport config.
#[cfg(feature = "quic")]
pub(crate) quic: Option<QuicConfig>,

/// WebRTC transport config.
#[cfg(feature = "webrtc")]
pub(crate) webrtc: Option<WebRtcConfig>,

/// WebSocket transport config.
#[cfg(feature = "websocket")]
pub(crate) websocket: Option<WebSocketConfig>,

/// Keypair.
Expand Down
5 changes: 3 additions & 2 deletions src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::{error::*, peer_id::*};

pub mod ed25519;
pub(crate) mod noise;
#[cfg(feature = "quic")]
pub(crate) mod tls;
pub(crate) mod keys_proto {
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs"));
Expand Down Expand Up @@ -94,8 +95,8 @@ impl TryFrom<keys_proto::PublicKey> for PublicKey {
type Error = Error;

fn try_from(pubkey: keys_proto::PublicKey) -> Result<Self, Self::Error> {
let key_type = keys_proto::KeyType::from_i32(pubkey.r#type)
.ok_or_else(|| Error::Other(format!("Unknown key type: {}", pubkey.r#type)))?;
let key_type = keys_proto::KeyType::try_from(pubkey.r#type)
.map_err(|_| Error::Other(format!("Unknown key type: {}", pubkey.r#type)))?;

match key_type {
keys_proto::KeyType::Ed25519 =>
Expand Down
2 changes: 2 additions & 0 deletions src/crypto/noise/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ impl NoiseContext {
}

/// Create new [`NoiseContext`] with prologue.
#[cfg(feature = "webrtc")]
pub fn with_prologue(id_keys: &Keypair, prologue: Vec<u8>) -> crate::Result<Self> {
let noise: Builder<'_> = Builder::with_resolver(
NOISE_PARAMETERS.parse().expect("qed; Valid noise pattern"),
Expand All @@ -160,6 +161,7 @@ impl NoiseContext {
}

/// Get remote public key from the received Noise payload.
#[cfg(feature = "webrtc")]
pub fn get_remote_public_key(&mut self, reply: &[u8]) -> crate::Result<PublicKey> {
let (len_slice, reply) = reply.split_at(2);
let len = u16::from_be_bytes(len_slice.try_into().map_err(|_| error::Error::InvalidData)?)
Expand Down
12 changes: 1 addition & 11 deletions src/crypto/noise/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::crypto::{self, noise::x25519_spec};
use crate::crypto::noise::x25519_spec;

use rand::SeedableRng;
use zeroize::Zeroize;
Expand All @@ -30,16 +30,6 @@ pub struct Keypair<T: Zeroize> {
pub public: PublicKey<T>,
}

/// The associated public identity of a DH keypair.
#[derive(Clone)]
pub struct KeypairIdentity {
/// The public identity key.
pub public: crypto::PublicKey,

/// The signature over the public DH key.
pub signature: Option<Vec<u8>>,
}

/// DH secret key.
#[derive(Clone)]
pub struct SecretKey<T: Zeroize>(pub T);
Expand Down
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,21 @@ pub enum Error {
DnsAddressResolutionFailed,
#[error("Transport error: `{0}`")]
TransportError(String),
#[cfg(feature = "quic")]
#[error("Failed to generate certificate: `{0}`")]
CertificateGeneration(#[from] crate::crypto::tls::certificate::GenError),
#[error("Invalid data")]
InvalidData,
#[error("Input rejected")]
InputRejected,
#[cfg(feature = "websocket")]
#[error("WebSocket error: `{0}`")]
WebSocket(#[from] tokio_tungstenite::tungstenite::error::Error),
#[error("Insufficient peers")]
InsufficientPeers,
#[error("Substream doens't exist")]
SubstreamDoesntExist,
#[cfg(feature = "webrtc")]
#[error("`str0m` error: `{0}`")]
WebRtc(#[from] str0m::RtcError),
#[error("Remote peer disconnected")]
Expand All @@ -109,6 +112,7 @@ pub enum Error {
NoAddressAvailable(PeerId),
#[error("Connection closed")]
ConnectionClosed,
#[cfg(feature = "quic")]
#[error("Quinn error: `{0}`")]
Quinn(quinn::ConnectionError),
#[error("Invalid certificate")]
Expand Down Expand Up @@ -237,6 +241,7 @@ impl From<prost::EncodeError> for Error {
}
}

#[cfg(feature = "quic")]
impl From<quinn::ConnectionError> for Error {
fn from(error: quinn::ConnectionError) -> Self {
match error {
Expand Down
22 changes: 16 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,18 @@ use crate::{
},
transport::{
manager::{SupportedTransport, TransportManager},
quic::QuicTransport,
tcp::TcpTransport,
webrtc::WebRtcTransport,
websocket::WebSocketTransport,
TransportBuilder, TransportEvent,
},
};

#[cfg(feature = "quic")]
use crate::transport::quic::QuicTransport;
#[cfg(feature = "webrtc")]
use crate::transport::webrtc::WebRtcTransport;
#[cfg(feature = "websocket")]
use crate::transport::websocket::WebSocketTransport;

use multiaddr::{Multiaddr, Protocol};
use multihash::Multihash;
use transport::Endpoint;
Expand All @@ -72,9 +76,11 @@ pub mod types;
pub mod yamux;

mod bandwidth;
mod mock;
mod multistream_select;

#[cfg(test)]
mod mock;

/// Public result type used by the crate.
pub type Result<T> = std::result::Result<T, error::Error>;

Expand Down Expand Up @@ -297,6 +303,7 @@ impl Litep2p {
}

// enable quic transport if the config exists
#[cfg(feature = "quic")]
if let Some(config) = litep2p_config.quic.take() {
let handle = transport_manager.transport_handle(Arc::clone(&litep2p_config.executor));
let (transport, transport_listen_addresses) =
Expand All @@ -313,6 +320,7 @@ impl Litep2p {
}

// enable webrtc transport if the config exists
#[cfg(feature = "webrtc")]
if let Some(config) = litep2p_config.webrtc.take() {
let handle = transport_manager.transport_handle(Arc::clone(&litep2p_config.executor));
let (transport, transport_listen_addresses) =
Expand All @@ -329,6 +337,7 @@ impl Litep2p {
}

// enable websocket transport if the config exists
#[cfg(feature = "websocket")]
if let Some(config) = litep2p_config.websocket.take() {
let handle = transport_manager.transport_handle(Arc::clone(&litep2p_config.executor));
let (transport, transport_listen_addresses) =
Expand Down Expand Up @@ -396,14 +405,17 @@ impl Litep2p {
.tcp
.is_some()
.then(|| supported_transports.insert(SupportedTransport::Tcp));
#[cfg(feature = "quic")]
config
.quic
.is_some()
.then(|| supported_transports.insert(SupportedTransport::Quic));
#[cfg(feature = "websocket")]
config
.websocket
.is_some()
.then(|| supported_transports.insert(SupportedTransport::WebSocket));
#[cfg(feature = "webrtc")]
config
.webrtc
.is_some()
Expand Down Expand Up @@ -515,7 +527,6 @@ mod tests {

let config = ConfigBuilder::new()
.with_tcp(Default::default())
.with_quic(Default::default())
.with_notification_protocol(config1)
.with_notification_protocol(config2)
.with_libp2p_ping(ping_config)
Expand Down Expand Up @@ -591,7 +602,6 @@ mod tests {

let config = ConfigBuilder::new()
.with_tcp(Default::default())
.with_quic(Default::default())
.with_notification_protocol(config1)
.with_notification_protocol(config2)
.with_libp2p_ping(ping_config)
Expand Down
1 change: 0 additions & 1 deletion src/multistream_select/length_delimited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use std::{
io,
pin::Pin,
task::{Context, Poll},
u16,
};

const MAX_LEN_BYTES: u16 = 2;
Expand Down
4 changes: 2 additions & 2 deletions src/protocol/notification/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ impl NotificationProtocol {
let Some(context) = self.peers.get_mut(&peer) else {
tracing::error!(target: LOG_TARGET, ?peer, "peer doesn't exist for outbound substream");
debug_assert!(false);
return Err(Error::PeerDoesntExist(peer.clone()));
return Err(Error::PeerDoesntExist(peer));
};

let pending_peer = self.pending_outbound.remove(&substream_id);
Expand Down Expand Up @@ -661,7 +661,7 @@ impl NotificationProtocol {
let Some(context) = self.peers.get_mut(&peer) else {
tracing::error!(target: LOG_TARGET, ?peer, "peer doesn't exist for inbound substream");
debug_assert!(false);
return Err(Error::PeerDoesntExist(peer.clone()));
return Err(Error::PeerDoesntExist(peer));
};

tracing::debug!(
Expand Down
Loading

0 comments on commit 3b664f7

Please sign in to comment.