libp2prs_core/muxing.rs
1// Copyright 2020 Netwarps Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21//! Muxing is the process of splitting a connection into multiple substreams.
22//!
23//! The main item of this module is the `StreamMuxer` trait. An implementation of `StreamMuxer`
24//! has ownership of a connection, lets you open and close substreams, and read/write data
25//! on open substreams.
26//!
27//! > **Note**: You normally don't need to use the methods of the `StreamMuxer` directly, as this
28//! > is managed by the library's internals.
29//!
30//! Each substream of a connection is an isolated stream of data. All the substreams are muxed
31//! together so that the data read from or written to each substream doesn't influence the other
32//! substreams.
33//!
34//! In the context of libp2p, each substream can use a different protocol. Contrary to opening a
35//! connection, opening a substream is almost free in terms of resources. This means that you
36//! shouldn't hesitate to rapidly open and close substreams, and to design protocols that don't
37//! require maintaining long-lived channels of communication.
38//!
39//! > **Example**: The Kademlia protocol opens a new substream for each request it wants to
40//! > perform. Multiple requests can be performed simultaneously by opening multiple
41//! > substreams, without having to worry about associating responses with the
42//! > right request.
43//!
44//! # Implementing a muxing protocol
45//!
46//! In order to implement a muxing protocol, create an object that implements the `UpgradeInfo`
47//! and `Upgrader` traits. See the `upgrade` module for more information.
48//! The `Output` associated type of the `Upgrader` traits should be an object that implements
49//! the `StreamMuxer` trait.
50//!
51//! The upgrade process will take ownership of the connection, which makes it possible for the
52//! implementation of `StreamMuxer` to control everything that happens on the wire.
53//!
54//! The `Output` associated type of the `StreamMuxer` is a trait object `IReadWrite`, which is
55//! in fact AsyncRead + AsyncWrite + StreamInfo + Unpin.
56//!
57//! IStreamMuxer is the trait object of StreamMuxer.
58
59use async_trait::async_trait;
60use futures::future::BoxFuture;
61
62use crate::secure_io::SecureInfo;
63use crate::transport::{ConnectionInfo, TransportError};
64use futures::{AsyncRead, AsyncWrite};
65
66/// StreamInfo returns the information of a substream opened by stream muxer.
67///
68/// The output of StreamMuxer must implements this trait.
69pub trait StreamInfo: Send {
70 /// Returns the identity of the stream.
71 fn id(&self) -> usize;
72}
73
74/// The trait for IReadWrite. It can be made into a trait object `IReadWrite` used
75/// by Swarm Substream.
76/// `StreamInfo` must be supported.
77#[async_trait]
78pub trait ReadWriteEx: AsyncRead + AsyncWrite + StreamInfo + Unpin + std::fmt::Debug {
79 fn box_clone(&self) -> IReadWrite;
80}
81
82pub type IReadWrite = Box<dyn ReadWriteEx>;
83
84/*
85impl Clone for IReadWrite {
86 fn clone(&self) -> Self {
87 self.box_clone()
88 }
89}
90 */
91
92/*
93impl AsyncRead for IReadWrite {
94 fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
95 AsyncRead::poll_read(Pin::new(&mut **self), cx, buf)
96 }
97}
98
99impl AsyncWrite for IReadWrite {
100 fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
101 AsyncWrite::poll_write(Pin::new(&mut **self), cx, buf)
102 }
103
104 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
105 AsyncWrite::poll_flush(Pin::new(&mut **self), cx)
106 }
107
108 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
109 AsyncWrite::poll_close(Pin::new(&mut **self), cx)
110 }
111}
112 */
113
114#[async_trait]
115pub trait StreamMuxer {
116 /// Opens a new outgoing substream.
117 async fn open_stream(&mut self) -> Result<IReadWrite, TransportError>;
118 /// Accepts a new incoming substream.
119 async fn accept_stream(&mut self) -> Result<IReadWrite, TransportError>;
120 /// Closes the stream muxer, the runtime of stream muxer will then exit.
121 async fn close(&mut self) -> Result<(), TransportError>;
122 /// Returns a Future which represents the main loop of the stream muxer.
123 fn task(&mut self) -> Option<BoxFuture<'static, ()>>;
124 /// Returns the cloned Trait object.
125 fn box_clone(&self) -> IStreamMuxer;
126}
127
128/// The trait for IStreamMuxer. It can be made into a trait object `IStreamMuxer`.
129/// Stream muxer in Swarm must support ConnectionInfo + SecureInfo.
130pub trait StreamMuxerEx: StreamMuxer + ConnectionInfo + SecureInfo + std::fmt::Debug {}
131
132pub type IStreamMuxer = Box<dyn StreamMuxerEx>;
133
134impl Clone for IStreamMuxer {
135 fn clone(&self) -> Self {
136 self.box_clone()
137 }
138}