1use crate::error::{ConnexaResult, Error};
2use crate::handle::Connexa;
3use crate::types::{DHTCommand, DHTEvent};
4use bytes::Bytes;
5use futures::StreamExt;
6use futures::channel::oneshot;
7use futures::stream::BoxStream;
8use libp2p::kad::{Mode, PeerInfo, PeerRecord, Quorum, RecordKey};
9use libp2p::{Multiaddr, PeerId};
10use std::collections::HashSet;
11
12pub struct ConnexaDht<'a, T, K> {
13 connexa: &'a Connexa<T, K>,
14}
15
16impl<'a, T, K> Copy for ConnexaDht<'a, T, K> {}
17
18impl<'a, T, K> Clone for ConnexaDht<'a, T, K> {
19 fn clone(&self) -> Self {
20 *self
21 }
22}
23
24impl<'a, T, K> ConnexaDht<'a, T, K>
25where
26 T: Send + Sync + 'static,
27{
28 pub(crate) fn new(connexa: &'a Connexa<T, K>) -> Self {
29 Self { connexa }
30 }
31
32 pub async fn find_peer(&self, peer_id: PeerId) -> ConnexaResult<Vec<PeerInfo>> {
34 let (tx, rx) = oneshot::channel();
35 self.connexa
36 .to_task
37 .clone()
38 .send(DHTCommand::FindPeer { peer_id, resp: tx }.into())
39 .await
40 .map_err(|_| Error::ChannelClosed)?;
41 rx.await.map_err(|_| Error::ChannelClosed)?
42 }
43
44 pub async fn provide(&self, key: impl ToRecordKey) -> ConnexaResult<()> {
46 let key = key.to_record_key();
47 let (tx, rx) = oneshot::channel();
48 self.connexa
49 .to_task
50 .clone()
51 .send(DHTCommand::Provide { key, resp: tx }.into())
52 .await
53 .map_err(|_| Error::ChannelClosed)?;
54 rx.await.map_err(|_| Error::ChannelClosed)?
55 }
56
57 pub async fn stop_provide(&self, key: impl ToRecordKey) -> ConnexaResult<()> {
59 let key = key.to_record_key();
60 let (tx, rx) = oneshot::channel();
61 self.connexa
62 .to_task
63 .clone()
64 .send(DHTCommand::StopProviding { key, resp: tx }.into())
65 .await
66 .map_err(|_| Error::ChannelClosed)?;
67 rx.await.map_err(|_| Error::ChannelClosed)?
68 }
69
70 pub async fn get_providers(
72 &self,
73 key: impl ToRecordKey,
74 ) -> ConnexaResult<BoxStream<'static, ConnexaResult<HashSet<PeerId>>>> {
75 let key = key.to_record_key();
76 let (tx, rx) = oneshot::channel();
77 self.connexa
78 .to_task
79 .clone()
80 .send(DHTCommand::GetProviders { key, resp: tx }.into())
81 .await
82 .map_err(|_| Error::ChannelClosed)?;
83 rx.await
84 .map_err(|_| Error::ChannelClosed)?
85 .map(|s| s.boxed())
86 }
87
88 pub async fn bootstrap(&self) -> ConnexaResult<()> {
91 let (tx, rx) = oneshot::channel();
92 self.connexa
93 .to_task
94 .clone()
95 .send(
96 DHTCommand::Bootstrap {
97 lazy: false,
98 resp: tx,
99 }
100 .into(),
101 )
102 .await
103 .map_err(|_| Error::ChannelClosed)?;
104 rx.await.map_err(|_| Error::ChannelClosed)?
105 }
106
107 pub async fn bootstrap_lazy(&self) -> ConnexaResult<()> {
110 let (tx, rx) = oneshot::channel();
111 self.connexa
112 .to_task
113 .clone()
114 .send(
115 DHTCommand::Bootstrap {
116 lazy: true,
117 resp: tx,
118 }
119 .into(),
120 )
121 .await
122 .map_err(|_| Error::ChannelClosed)?;
123 rx.await.map_err(|_| Error::ChannelClosed)?
124 }
125
126 pub async fn listener(
128 &self,
129 key: impl ToOptionalRecordKey,
130 ) -> ConnexaResult<BoxStream<'static, DHTEvent>> {
131 let key = key.to_record_key();
132 let (tx, rx) = oneshot::channel();
133 self.connexa
134 .to_task
135 .clone()
136 .send(DHTCommand::Listener { key, resp: tx }.into())
137 .await
138 .map_err(|_| Error::ChannelClosed)?;
139 rx.await
140 .map_err(|_| Error::ChannelClosed)?
141 .map(|s| s.boxed())
142 }
143
144 pub async fn get(
146 &self,
147 key: impl ToRecordKey,
148 ) -> ConnexaResult<BoxStream<'static, ConnexaResult<PeerRecord>>> {
149 let key = key.to_record_key();
150 let (tx, rx) = oneshot::channel();
151 self.connexa
152 .to_task
153 .clone()
154 .send(DHTCommand::Get { key, resp: tx }.into())
155 .await
156 .map_err(|_| Error::ChannelClosed)?;
157 rx.await
158 .map_err(|_| Error::ChannelClosed)?
159 .map(|s| s.boxed())
160 }
161
162 pub async fn put(
164 &self,
165 key: impl ToRecordKey,
166 data: impl Into<Bytes>,
167 quorum: Quorum,
168 ) -> ConnexaResult<()> {
169 let key = key.to_record_key();
170 let data = data.into();
171 let (tx, rx) = oneshot::channel();
172 self.connexa
173 .to_task
174 .clone()
175 .send(
176 DHTCommand::Put {
177 key,
178 data,
179 quorum,
180 resp: tx,
181 }
182 .into(),
183 )
184 .await
185 .map_err(|_| Error::ChannelClosed)?;
186 rx.await.map_err(|_| Error::ChannelClosed)?
187 }
188
189 pub async fn put_to(
195 &self,
196 target: impl ExactSizeIterator<Item = PeerId>,
197 key: impl ToRecordKey,
198 data: impl Into<Bytes>,
199 quorum: Quorum,
200 ) -> ConnexaResult<()> {
201 let key = key.to_record_key();
202 let data = data.into();
203 let target = target.collect::<Vec<_>>();
204
205 let (tx, rx) = oneshot::channel();
206
207 self.connexa
208 .to_task
209 .clone()
210 .send(
211 DHTCommand::PutTo {
212 target,
213 key,
214 data,
215 quorum,
216 resp: tx,
217 }
218 .into(),
219 )
220 .await
221 .map_err(|_| Error::ChannelClosed)?;
222 rx.await.map_err(|_| Error::ChannelClosed)?
223 }
224
225 pub async fn remove_record(&self, key: impl ToRecordKey) -> ConnexaResult<()> {
227 let key = key.to_record_key();
228 let (tx, rx) = oneshot::channel();
229
230 self.connexa
231 .to_task
232 .clone()
233 .send(DHTCommand::Remove { key, resp: tx }.into())
234 .await
235 .map_err(|_| Error::ChannelClosed)?;
236 rx.await.map_err(|_| Error::ChannelClosed)?
237 }
238
239 pub async fn set_mode(&self, mode: impl Into<Option<Mode>>) -> ConnexaResult<()> {
242 let mode = mode.into();
243 let (tx, rx) = oneshot::channel();
244 self.connexa
245 .to_task
246 .clone()
247 .send(DHTCommand::SetDHTMode { mode, resp: tx }.into())
248 .await
249 .map_err(|_| Error::ChannelClosed)?;
250 rx.await.map_err(|_| Error::ChannelClosed)?
251 }
252
253 pub async fn mode(&self) -> ConnexaResult<Mode> {
255 let (tx, rx) = oneshot::channel();
256 self.connexa
257 .to_task
258 .clone()
259 .send(DHTCommand::DHTMode { resp: tx }.into())
260 .await
261 .map_err(|_| Error::ChannelClosed)?;
262 rx.await.map_err(|_| Error::ChannelClosed)?
263 }
264
265 pub async fn add_address(&self, peer_id: PeerId, addr: Multiaddr) -> ConnexaResult<()> {
267 let (tx, rx) = oneshot::channel();
268 self.connexa
269 .to_task
270 .clone()
271 .send(
272 DHTCommand::AddAddress {
273 peer_id,
274 addr,
275 resp: tx,
276 }
277 .into(),
278 )
279 .await
280 .map_err(|_| Error::ChannelClosed)?;
281 rx.await.map_err(|_| Error::ChannelClosed)?
282 }
283
284 pub async fn remove_address(&self, peer_id: PeerId, addr: Multiaddr) -> ConnexaResult<()> {
286 let (tx, rx) = oneshot::channel();
287 self.connexa
288 .to_task
289 .clone()
290 .send(
291 DHTCommand::RemoveAddress {
292 peer_id,
293 addr,
294 resp: tx,
295 }
296 .into(),
297 )
298 .await
299 .map_err(|_| Error::ChannelClosed)?;
300 rx.await.map_err(|_| Error::ChannelClosed)?
301 }
302
303 pub async fn remove_peer(&self, peer_id: PeerId) -> ConnexaResult<()> {
305 let (tx, rx) = oneshot::channel();
306 self.connexa
307 .to_task
308 .clone()
309 .send(DHTCommand::RemovePeer { peer_id, resp: tx }.into())
310 .await
311 .map_err(|_| Error::ChannelClosed)?;
312 rx.await.map_err(|_| Error::ChannelClosed)?
313 }
314}
315
316pub trait ToRecordKey {
317 fn to_record_key(self) -> RecordKey;
318}
319
320pub trait ToOptionalRecordKey {
321 fn to_record_key(self) -> Option<RecordKey>;
322}
323
324#[cfg(feature = "cid")]
325impl ToRecordKey for cid::Cid {
326 fn to_record_key(self) -> RecordKey {
327 self.hash().to_bytes().into()
328 }
329}
330
331impl ToRecordKey for RecordKey {
332 fn to_record_key(self) -> RecordKey {
333 self
334 }
335}
336
337impl ToRecordKey for &RecordKey {
338 fn to_record_key(self) -> RecordKey {
339 self.clone()
340 }
341}
342
343impl ToRecordKey for String {
344 fn to_record_key(self) -> RecordKey {
345 self.into_bytes().into()
346 }
347}
348
349impl ToRecordKey for &String {
350 fn to_record_key(self) -> RecordKey {
351 self.as_bytes().to_vec().into()
352 }
353}
354
355impl ToRecordKey for &str {
356 fn to_record_key(self) -> RecordKey {
357 self.as_bytes().to_vec().into()
358 }
359}
360
361impl ToRecordKey for Vec<u8> {
362 fn to_record_key(self) -> RecordKey {
363 self.into()
364 }
365}
366
367impl ToRecordKey for &[u8] {
368 fn to_record_key(self) -> RecordKey {
369 self.to_vec().into()
370 }
371}
372
373impl<const N: usize> ToRecordKey for [u8; N] {
374 fn to_record_key(self) -> RecordKey {
375 self.to_vec().into()
376 }
377}
378
379impl ToRecordKey for Bytes {
380 fn to_record_key(self) -> RecordKey {
381 self.to_vec().into()
382 }
383}
384
385impl<R: ToRecordKey> ToOptionalRecordKey for R {
386 fn to_record_key(self) -> Option<RecordKey> {
387 Some(self.to_record_key())
388 }
389}
390
391impl<R: ToRecordKey> ToOptionalRecordKey for Option<R> {
392 fn to_record_key(self) -> Option<RecordKey> {
393 self.map(|r| r.to_record_key())
394 }
395}
396
397impl ToOptionalRecordKey for () {
398 fn to_record_key(self) -> Option<RecordKey> {
399 None
400 }
401}