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}