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 =
97            NotificationHandle::new(event_rx, notif_rx, command_tx, Arc::clone(&handshake));
98
99        (
100            Self {
101                protocol_name,
102                codec: ProtocolCodec::UnsignedVarint(Some(max_notification_size)),
103                _max_notification_size: max_notification_size,
104                auto_accept,
105                handshake,
106                fallback_names,
107                event_tx,
108                notif_tx,
109                command_rx,
110                should_dial,
111                sync_channel_size,
112                async_channel_size,
113            },
114            handle,
115        )
116    }
117
118    /// Get protocol name.
119    pub(crate) fn protocol_name(&self) -> &ProtocolName {
120        &self.protocol_name
121    }
122
123    /// Set handshake for the protocol.
124    ///
125    /// This function is used to work around an issue in Polkadot SDK and users
126    /// should not depend on its continued existence.
127    pub fn set_handshake(&mut self, handshake: Vec<u8>) {
128        let mut inner = self.handshake.write();
129        *inner = handshake;
130    }
131}
132
133/// Notification configuration builder.
134pub struct ConfigBuilder {
135    /// Protocol name.
136    protocol_name: ProtocolName,
137
138    /// Maximum notification size.
139    max_notification_size: Option<usize>,
140
141    /// Handshake bytes.
142    handshake: Option<Vec<u8>>,
143
144    /// Should `NotificationProtocol` dial the peer if an outbound substream is requested but there
145    /// is no connection to the peer.
146    should_dial: bool,
147
148    /// Fallback names.
149    fallback_names: Vec<ProtocolName>,
150
151    /// Auto accept inbound substream.
152    auto_accept_inbound_for_initiated: bool,
153
154    /// Synchronous channel size.
155    sync_channel_size: usize,
156
157    /// Asynchronous channel size.
158    async_channel_size: usize,
159}
160
161impl ConfigBuilder {
162    /// Create new [`ConfigBuilder`].
163    pub fn new(protocol_name: ProtocolName) -> Self {
164        Self {
165            protocol_name,
166            max_notification_size: None,
167            handshake: None,
168            fallback_names: Vec::new(),
169            auto_accept_inbound_for_initiated: false,
170            sync_channel_size: SYNC_CHANNEL_SIZE,
171            async_channel_size: ASYNC_CHANNEL_SIZE,
172            should_dial: true,
173        }
174    }
175
176    /// Set maximum notification size.
177    pub fn with_max_size(mut self, max_notification_size: usize) -> Self {
178        self.max_notification_size = Some(max_notification_size);
179        self
180    }
181
182    /// Set handshake.
183    pub fn with_handshake(mut self, handshake: Vec<u8>) -> Self {
184        self.handshake = Some(handshake);
185        self
186    }
187
188    /// Set fallback names.
189    pub fn with_fallback_names(mut self, fallback_names: Vec<ProtocolName>) -> Self {
190        self.fallback_names = fallback_names;
191        self
192    }
193
194    /// Auto-accept inbound substreams for those connections which were initiated by the local
195    /// node.
196    ///
197    /// Connection in this context means a bidirectional substream pair between two peers over a
198    /// given protocol.
199    ///
200    /// By default, when a node starts a connection with a remote node and opens an outbound
201    /// substream to them, that substream is validated and if it's accepted, remote node sends
202    /// their handshake over that substream and opens another substream to local node. The
203    /// substream that was opened by the local node is used for sending data and the one opened
204    /// by the remote node is used for receiving data.
205    ///
206    /// By default, even if the local node was the one that opened the first substream, this inbound
207    /// substream coming from remote node must be validated as the handshake of the remote node
208    /// may reveal that it's not someone that the local node is willing to accept.
209    ///
210    /// To disable this behavior, auto accepting for the inbound substream can be enabled. If local
211    /// node is the one that opened the connection and it was accepted by the remote node, local
212    /// node is only notified via
213    /// [`NotificationStreamOpened`](super::types::NotificationEvent::NotificationStreamOpened).
214    pub fn with_auto_accept_inbound(mut self, auto_accept: bool) -> Self {
215        self.auto_accept_inbound_for_initiated = auto_accept;
216        self
217    }
218
219    /// Configure size of the channel for sending synchronous notifications.
220    ///
221    /// Default value is `16`.
222    pub fn with_sync_channel_size(mut self, size: usize) -> Self {
223        self.sync_channel_size = size;
224        self
225    }
226
227    /// Configure size of the channel for sending asynchronous notifications.
228    ///
229    /// Default value is `8`.
230    pub fn with_async_channel_size(mut self, size: usize) -> Self {
231        self.async_channel_size = size;
232        self
233    }
234
235    /// Should `NotificationProtocol` attempt to dial the peer if an outbound substream is opened
236    /// but no connection to the peer exist.
237    ///
238    /// Dialing is enabled by default.
239    pub fn with_dialing_enabled(mut self, should_dial: bool) -> Self {
240        self.should_dial = should_dial;
241        self
242    }
243
244    /// Build notification configuration.
245    pub fn build(mut self) -> (Config, NotificationHandle) {
246        Config::new(
247            self.protocol_name,
248            self.max_notification_size.take().expect("notification size to be specified"),
249            self.handshake.take().expect("handshake to be specified"),
250            self.fallback_names,
251            self.auto_accept_inbound_for_initiated,
252            self.sync_channel_size,
253            self.async_channel_size,
254            self.should_dial,
255        )
256    }
257}