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}