litep2p/protocol/notification/
config.rs

1// Copyright 2023 litep2p developers
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
21use crate::{
22    codec::ProtocolCodec,
23    protocol::notification::{
24        handle::NotificationHandle,
25        types::{
26            InnerNotificationEvent, NotificationCommand, ASYNC_CHANNEL_SIZE, SYNC_CHANNEL_SIZE,
27        },
28    },
29    types::protocol::ProtocolName,
30    PeerId, DEFAULT_CHANNEL_SIZE,
31};
32
33use bytes::BytesMut;
34use parking_lot::RwLock;
35use tokio::sync::mpsc::{channel, Receiver, Sender};
36
37use std::sync::Arc;
38
39/// Notification configuration.
40#[derive(Debug)]
41pub struct Config {
42    /// Protocol name.
43    pub(crate) protocol_name: ProtocolName,
44
45    /// Protocol codec.
46    pub(crate) codec: ProtocolCodec,
47
48    /// Maximum notification size.
49    _max_notification_size: usize,
50
51    /// Handshake bytes.
52    pub(crate) handshake: Arc<RwLock<Vec<u8>>>,
53
54    /// Auto accept inbound substream.
55    pub(super) auto_accept: bool,
56
57    /// Protocol aliases.
58    pub(crate) fallback_names: Vec<ProtocolName>,
59
60    /// TX channel passed to the protocol used for sending events.
61    pub(crate) event_tx: Sender<InnerNotificationEvent>,
62
63    /// TX channel for sending notifications from the connection handlers.
64    pub(crate) notif_tx: Sender<(PeerId, BytesMut)>,
65
66    /// RX channel passed to the protocol used for receiving commands.
67    pub(crate) command_rx: Receiver<NotificationCommand>,
68
69    /// Synchronous channel size.
70    pub(crate) sync_channel_size: usize,
71
72    /// Asynchronous channel size.
73    pub(crate) async_channel_size: usize,
74
75    /// Should `NotificationProtocol` dial the peer if there is no connection to them
76    /// when an outbound substream is requested.
77    pub(crate) should_dial: bool,
78}
79
80impl Config {
81    /// Create new [`Config`].
82    pub fn new(
83        protocol_name: ProtocolName,
84        max_notification_size: usize,
85        handshake: Vec<u8>,
86        fallback_names: Vec<ProtocolName>,
87        auto_accept: bool,
88        sync_channel_size: usize,
89        async_channel_size: usize,
90        should_dial: bool,
91    ) -> (Self, NotificationHandle) {
92        let (event_tx, event_rx) = channel(DEFAULT_CHANNEL_SIZE);
93        let (notif_tx, notif_rx) = channel(DEFAULT_CHANNEL_SIZE);
94        let (command_tx, command_rx) = channel(DEFAULT_CHANNEL_SIZE);
95        let handshake = Arc::new(RwLock::new(handshake));
96        let handle = NotificationHandle::new(
97            event_rx,
98            notif_rx,
99            command_tx,
100            Arc::clone(&handshake),
101            protocol_name.clone(),
102        );
103
104        (
105            Self {
106                protocol_name,
107                codec: ProtocolCodec::UnsignedVarint(Some(max_notification_size)),
108                _max_notification_size: max_notification_size,
109                auto_accept,
110                handshake,
111                fallback_names,
112                event_tx,
113                notif_tx,
114                command_rx,
115                should_dial,
116                sync_channel_size,
117                async_channel_size,
118            },
119            handle,
120        )
121    }
122
123    /// Get protocol name.
124    pub(crate) fn protocol_name(&self) -> &ProtocolName {
125        &self.protocol_name
126    }
127
128    /// Set handshake for the protocol.
129    ///
130    /// This function is used to work around an issue in Polkadot SDK and users
131    /// should not depend on its continued existence.
132    pub fn set_handshake(&mut self, handshake: Vec<u8>) {
133        let mut inner = self.handshake.write();
134        *inner = handshake;
135    }
136}
137
138/// Notification configuration builder.
139pub struct ConfigBuilder {
140    /// Protocol name.
141    protocol_name: ProtocolName,
142
143    /// Maximum notification size.
144    max_notification_size: Option<usize>,
145
146    /// Handshake bytes.
147    handshake: Option<Vec<u8>>,
148
149    /// Should `NotificationProtocol` dial the peer if an outbound substream is requested but there
150    /// is no connection to the peer.
151    should_dial: bool,
152
153    /// Fallback names.
154    fallback_names: Vec<ProtocolName>,
155
156    /// Auto accept inbound substream.
157    auto_accept_inbound_for_initiated: bool,
158
159    /// Synchronous channel size.
160    sync_channel_size: usize,
161
162    /// Asynchronous channel size.
163    async_channel_size: usize,
164}
165
166impl ConfigBuilder {
167    /// Create new [`ConfigBuilder`].
168    pub fn new(protocol_name: ProtocolName) -> Self {
169        Self {
170            protocol_name,
171            max_notification_size: None,
172            handshake: None,
173            fallback_names: Vec::new(),
174            auto_accept_inbound_for_initiated: false,
175            sync_channel_size: SYNC_CHANNEL_SIZE,
176            async_channel_size: ASYNC_CHANNEL_SIZE,
177            should_dial: true,
178        }
179    }
180
181    /// Set maximum notification size.
182    pub fn with_max_size(mut self, max_notification_size: usize) -> Self {
183        self.max_notification_size = Some(max_notification_size);
184        self
185    }
186
187    /// Set handshake.
188    pub fn with_handshake(mut self, handshake: Vec<u8>) -> Self {
189        self.handshake = Some(handshake);
190        self
191    }
192
193    /// Set fallback names.
194    pub fn with_fallback_names(mut self, fallback_names: Vec<ProtocolName>) -> Self {
195        self.fallback_names = fallback_names;
196        self
197    }
198
199    /// Auto-accept inbound substreams for those connections which were initiated by the local
200    /// node.
201    ///
202    /// Connection in this context means a bidirectional substream pair between two peers over a
203    /// given protocol.
204    ///
205    /// By default, when a node starts a connection with a remote node and opens an outbound
206    /// substream to them, that substream is validated and if it's accepted, remote node sends
207    /// their handshake over that substream and opens another substream to local node. The
208    /// substream that was opened by the local node is used for sending data and the one opened
209    /// by the remote node is used for receiving data.
210    ///
211    /// By default, even if the local node was the one that opened the first substream, this inbound
212    /// substream coming from remote node must be validated as the handshake of the remote node
213    /// may reveal that it's not someone that the local node is willing to accept.
214    ///
215    /// To disable this behavior, auto accepting for the inbound substream can be enabled. If local
216    /// node is the one that opened the connection and it was accepted by the remote node, local
217    /// node is only notified via
218    /// [`NotificationStreamOpened`](super::types::NotificationEvent::NotificationStreamOpened).
219    pub fn with_auto_accept_inbound(mut self, auto_accept: bool) -> Self {
220        self.auto_accept_inbound_for_initiated = auto_accept;
221        self
222    }
223
224    /// Configure size of the channel for sending synchronous notifications.
225    ///
226    /// Default value is `16`.
227    pub fn with_sync_channel_size(mut self, size: usize) -> Self {
228        self.sync_channel_size = size;
229        self
230    }
231
232    /// Configure size of the channel for sending asynchronous notifications.
233    ///
234    /// Default value is `8`.
235    pub fn with_async_channel_size(mut self, size: usize) -> Self {
236        self.async_channel_size = size;
237        self
238    }
239
240    /// Should `NotificationProtocol` attempt to dial the peer if an outbound substream is opened
241    /// but no connection to the peer exist.
242    ///
243    /// Dialing is enabled by default.
244    pub fn with_dialing_enabled(mut self, should_dial: bool) -> Self {
245        self.should_dial = should_dial;
246        self
247    }
248
249    /// Build notification configuration.
250    pub fn build(mut self) -> (Config, NotificationHandle) {
251        Config::new(
252            self.protocol_name,
253            self.max_notification_size.take().expect("notification size to be specified"),
254            self.handshake.take().expect("handshake to be specified"),
255            self.fallback_names,
256            self.auto_accept_inbound_for_initiated,
257            self.sync_channel_size,
258            self.async_channel_size,
259            self.should_dial,
260        )
261    }
262}