hopr_transport_p2p/
lib.rs

1//! # P2P
2//!
3//! The underlying technology for managing the peer-to-peer networking used by this package is the [`rust-libp2p`](https://github.com/libp2p/rust-libp2p) library ([documentation](https://docs.libp2p.io/)).
4//!
5//! ## Modularity
6//!
7//! `rust-libp2p` is highly modular allowing for reimplmenting expected behavior using custom implementations for API
8//! traits.
9//!
10//! This way it is possible to experiment with and combine different components of the library in order to construct a
11//! specific targeted use case.
12//!
13//! ## `rust-libp2p` connectivity
14//!
15//! As per the [official documentation](https://connectivity.libp2p.io/), the connectivity types in the library are divided into the `standalone` (implementation of network over host) and `browser` (implementation of network over browser).
16//!
17//! Nodes that are not located behind a blocking firewall or NAT are designated as **public nodes** and can utilize the
18//! `TCP` or `QUIC` connectivity, with the recommendation to use QUIC if possible.
19//!
20//! Browser based solutions are almost always located behind a private network or a blocking firewall and to open a
21//! connection towards the standalone nodes these utilize either the `WebSocket` approach (by hijacking the `TCP`
22//! connection) or the (not yet fully speced up) `WebTransport` (by hijacking the `QUIC` connection).
23
24/// Constants exported by the crate.
25pub mod constants;
26
27/// Errors generated by the crate.
28pub mod errors;
29
30/// Raw swarm definition for the HOPR network.
31pub mod swarm;
32
33/// P2P behavior definitions for the transport level interactions not related to the HOPR protocol
34mod behavior;
35
36use std::collections::HashSet;
37
38use futures::{AsyncRead, AsyncWrite};
39pub use hopr_api::network::{Health, Observable};
40use hopr_api::network::{NetworkObservations, NetworkView};
41use hopr_transport_network::observation::Observations;
42use libp2p::{Multiaddr, PeerId};
43
44pub use crate::{
45    behavior::{HoprNetworkBehavior, HoprNetworkBehaviorEvent},
46    swarm::HoprLibp2pNetworkBuilder,
47};
48
49#[derive(Clone)]
50pub struct HoprNetwork {
51    tracker: hopr_transport_network::track::NetworkPeerTracker,
52    store: hopr_transport_network::store::NetworkPeerStore,
53    control: libp2p_stream::Control,
54    protocol: libp2p::StreamProtocol,
55}
56
57impl std::fmt::Debug for HoprNetwork {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        f.debug_struct("HoprNetwork")
60            .field("tracker", &self.tracker)
61            .field("store", &self.store)
62            .field("protocol", &self.protocol)
63            .finish()
64    }
65}
66
67impl NetworkView for HoprNetwork {
68    fn listening_as(&self) -> HashSet<Multiaddr> {
69        self.store.get(self.store.me()).unwrap_or_else(|| {
70            tracing::error!("failed to get own peer info from the peer store");
71            std::collections::HashSet::new()
72        })
73    }
74
75    #[inline]
76    fn discovered_peers(&self) -> HashSet<PeerId> {
77        self.store.iter_keys().collect()
78    }
79
80    #[inline]
81    fn connected_peers(&self) -> HashSet<PeerId> {
82        self.tracker.iter_keys().collect()
83    }
84
85    #[inline]
86    fn multiaddress_of(&self, peer: &PeerId) -> Option<HashSet<Multiaddr>> {
87        self.store.get(peer)
88    }
89
90    #[allow(refining_impl_trait_reachable)]
91    #[inline]
92    fn observations_for(&self, peer: &PeerId) -> Option<Observations> {
93        self.tracker.get(peer)
94    }
95
96    fn health(&self) -> Health {
97        match self.tracker.len() {
98            0 => Health::Red,
99            1 => Health::Orange,
100            2..4 => Health::Yellow,
101            _ => Health::Green,
102        }
103    }
104}
105
106#[async_trait::async_trait]
107impl hopr_transport_protocol::stream::BidirectionalStreamControl for HoprNetwork {
108    fn accept(
109        mut self,
110    ) -> Result<impl futures::Stream<Item = (PeerId, impl AsyncRead + AsyncWrite + Send)> + Send, impl std::error::Error>
111    {
112        self.control.accept(self.protocol)
113    }
114
115    async fn open(mut self, peer: PeerId) -> Result<impl AsyncRead + AsyncWrite + Send, impl std::error::Error> {
116        self.control.open_stream(peer, self.protocol).await
117    }
118}
119
120impl NetworkObservations for HoprNetwork {
121    fn update(&self, peer: &PeerId, result: std::result::Result<std::time::Duration, ()>) {
122        self.tracker.alter(peer, |_, mut o| {
123            o.record_probe(result.map_err(|_| ()));
124            o
125        });
126    }
127}