beetswap/builder.rs
1use std::sync::Arc;
2
3use blockstore::Blockstore;
4
5use crate::client::{ClientBehaviour, ClientConfig};
6use crate::multihasher::{Multihasher, MultihasherTable};
7use crate::server::ServerBehaviour;
8use crate::utils::stream_protocol;
9use crate::{Behaviour, Error, Result};
10
11/// Builder for [`Behaviour`].
12///
13/// # Example
14///
15/// ```rust,no_run
16/// # use std::sync::Arc;
17/// # use blockstore::InMemoryBlockstore;
18/// # fn new() -> beetswap::Behaviour<64, InMemoryBlockstore<64>> {
19/// beetswap::Behaviour::builder(Arc::new(InMemoryBlockstore::new()))
20/// .build()
21/// # }
22pub struct BehaviourBuilder<const S: usize, B>
23where
24 B: Blockstore + 'static,
25{
26 protocol_prefix: Option<String>,
27 blockstore: Arc<B>,
28 client: ClientConfig,
29 multihasher: MultihasherTable<S>,
30}
31
32impl<const S: usize, B> BehaviourBuilder<S, B>
33where
34 B: Blockstore + 'static,
35{
36 /// Creates a new builder for [`Behaviour`].
37 pub(crate) fn new(blockstore: Arc<B>) -> Self {
38 BehaviourBuilder {
39 protocol_prefix: None,
40 blockstore,
41 client: ClientConfig {
42 set_send_dont_have: true,
43 },
44 multihasher: MultihasherTable::<S>::new(),
45 }
46 }
47
48 /// Set a prefix on the protocol name.
49 ///
50 /// The prefix will be added on `/ipfs/bitswap/1.2.0`.
51 ///
52 /// # Errors
53 ///
54 /// This function will return an error if `prefix` does not start with a forward slash (`/`).
55 ///
56 /// # Example
57 ///
58 /// ```rust
59 /// # use std::sync::Arc;
60 /// # use blockstore::InMemoryBlockstore;
61 /// # fn new() -> beetswap::Result<beetswap::Behaviour<64, InMemoryBlockstore<64>>> {
62 /// # Ok(
63 /// beetswap::Behaviour::builder(Arc::new(InMemoryBlockstore::new()))
64 /// .protocol_prefix("/celestia/celestia")?
65 /// .build()
66 /// # )
67 /// # }
68 /// ```
69 pub fn protocol_prefix(mut self, prefix: &str) -> Result<Self> {
70 if !prefix.starts_with('/') {
71 return Err(Error::InvalidProtocolPrefix(prefix.to_owned()));
72 }
73
74 self.protocol_prefix = Some(prefix.to_owned());
75 Ok(self)
76 }
77
78 /// Client will set `send_dont_have` flag on each query (enabled by default).
79 ///
80 /// # Example
81 ///
82 /// ```rust
83 /// # use std::sync::Arc;
84 /// # use blockstore::InMemoryBlockstore;
85 /// # fn new() -> beetswap::Behaviour<64, InMemoryBlockstore<64>> {
86 /// beetswap::Behaviour::builder(Arc::new(InMemoryBlockstore::new()))
87 /// .client_set_send_dont_have(false)
88 /// .build()
89 /// # }
90 pub fn client_set_send_dont_have(mut self, enable: bool) -> Self {
91 self.client.set_send_dont_have = enable;
92 self
93 }
94
95 /// Register an extra [`Multihasher`].
96 ///
97 /// Every registration adds new hasher to [`Behaviour`]. Hashers are used to
98 /// reconstruct the [`Cid`] from the received data. `Behaviour` will try them
99 /// in the reverse order they were registered until one successfully constructs
100 /// [`Multihash`].
101 ///
102 /// By default `BehaviourBuilder` is pre-loaded with [`StandardMultihasher`].
103 ///
104 /// [`StandardMultihasher`]: crate::multihasher::StandardMultihasher
105 /// [`Cid`]: cid::CidGeneric
106 /// [`Multihash`]: libp2p_core::multihash::Multihash
107 pub fn register_multihasher<M>(mut self, multihasher: M) -> Self
108 where
109 M: Multihasher<S> + Send + Sync + 'static,
110 {
111 self.multihasher.register(multihasher);
112 self
113 }
114
115 /// Build a [`Behaviour`].
116 pub fn build(self) -> Behaviour<S, B> {
117 let blockstore = self.blockstore;
118 let multihasher = Arc::new(self.multihasher);
119 let protocol_prefix = self.protocol_prefix.as_deref();
120
121 Behaviour {
122 protocol: stream_protocol(protocol_prefix, "/ipfs/bitswap/1.2.0")
123 .expect("prefix checked by beetswap::BehaviourBuilder::protocol_prefix"),
124 client: ClientBehaviour::new(self.client, blockstore.clone(), protocol_prefix),
125 server: ServerBehaviour::new(blockstore, protocol_prefix),
126 multihasher,
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use blockstore::InMemoryBlockstore;
135
136 #[test]
137 fn invalid_protocol_prefix() {
138 assert!(matches!(
139 BehaviourBuilder::<64, _>::new(Arc::new(InMemoryBlockstore::<64>::new()))
140 .protocol_prefix("foo"),
141 Err(Error::InvalidProtocolPrefix(_))
142 ));
143 }
144}