1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// This is free and unencumbered software released into the public domain.
use crate::PeerId;
use alloc::boxed::Box;
use asimov_id::{Handle, Id};
use core::pin::Pin;
use futures_lite::{Stream, StreamExt, stream};
/// A resolver for ASIMOV handles (e.g., "â’¶jhacker").
pub trait ResolveHandle {
type Error: core::fmt::Debug + Send;
/// Resolves an ASIMOV ID and yields a random known peer ID.
/// Ignores any erroneous results, sampling from only successful results.
///
/// The default implementation requires the `random` feature.
fn resolve_random(
&mut self,
id: impl Into<Id>,
) -> impl Future<Output = Result<Option<PeerId>, Self::Error>> {
#[cfg(not(feature = "random"))]
{
unimplemented!("resolve_random requires the `random` feature");
return async { Ok(None) };
}
#[cfg(feature = "random")]
async move {
let mut stream = Box::pin(self.resolve_all(id));
let mut results = alloc::vec::Vec::new();
while let Some(result) = stream.next().await {
let Ok(result) = result else {
continue; // ignore errors silently
};
results.push(result);
}
let index = fastrand::usize(..results.len());
Ok(results.get(index).copied())
}
}
/// Resolves an ASIMOV ID and yields only the first known peer ID.
/// Ignores any initial erroneous results, returning the first successful result.
fn resolve_first(
&mut self,
id: impl Into<Id>,
) -> impl Future<Output = Result<Option<PeerId>, Self::Error>> {
async move {
let mut stream = Box::pin(self.resolve_all(id));
while let Some(result) = stream.next().await {
let Ok(result) = result else {
continue; // ignore errors silently
};
return Ok(Some(result));
}
Ok(None)
}
}
/// Resolves an ASIMOV ID into a stream of all known peer IDs.
fn resolve_all(
&mut self,
id: impl Into<Id>,
) -> impl Stream<Item = Result<PeerId, Self::Error>> + Send {
let output: Pin<Box<dyn Stream<Item = Result<PeerId, Self::Error>> + Send>> =
match id.into() {
Id::Handle(handle) => Box::pin(self.resolve_handle(handle)),
Id::PublicKey(key) => Box::pin(stream::once(Ok(key))),
};
output
}
/// Resolves an ASIMOV handle into a stream of all known peer IDs.
///
/// This is the only method that trait implementors must provide.
fn resolve_handle(
&mut self,
_handle: impl Into<Handle>,
) -> impl Stream<Item = Result<PeerId, Self::Error>> + Send {
Box::pin(stream::empty())
}
}