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}