tycho_network/util/
traits.rs1use std::future::Future;
2
3use anyhow::Result;
4
5use crate::network::{Network, Peer};
6use crate::types::{PeerId, Request, Response};
7
8pub trait NetworkExt {
9 fn query(
10 &self,
11 peer_id: &PeerId,
12 request: Request,
13 ) -> impl Future<Output = Result<Response>> + Send;
14
15 fn send(&self, peer_id: &PeerId, request: Request) -> impl Future<Output = Result<()>> + Send;
16}
17
18impl NetworkExt for Network {
19 async fn query(&self, peer_id: &PeerId, request: Request) -> Result<Response> {
20 on_connected_peer(self, Peer::rpc, peer_id, request).await
21 }
22
23 async fn send(&self, peer_id: &PeerId, request: Request) -> Result<()> {
24 on_connected_peer(self, Peer::send_message, peer_id, request).await
25 }
26}
27
28async fn on_connected_peer<T, F>(
29 network: &Network,
30 f: F,
31 peer_id: &PeerId,
32 request: Request,
33) -> Result<T>
34where
35 for<'a> F: PeerTask<'a, T>,
36{
37 let peer = 'peer: {
38 if let Some(peer) = network.peer(peer_id) {
40 break 'peer peer;
41 }
42
43 match network.known_peers().get(peer_id) {
45 Some(peer_info) => {
47 let address = peer_info
49 .iter_addresses()
50 .next()
51 .cloned()
52 .expect("address list must have at least one item");
53
54 network.connect(address, peer_id).await?
55 }
56 None => anyhow::bail!(UnknownPeerError { peer_id: *peer_id }),
58 }
59 };
60
61 f.call(&peer, request).await
62}
63
64trait PeerTask<'a, T> {
65 type Output: Future<Output = Result<T>> + 'a;
66
67 fn call(self, peer: &'a Peer, request: Request) -> Self::Output;
68}
69
70impl<'a, T, F, Fut> PeerTask<'a, T> for F
71where
72 F: FnOnce(&'a Peer, Request) -> Fut,
73 Fut: Future<Output = Result<T>> + 'a,
74{
75 type Output = Fut;
76
77 #[inline]
78 fn call(self, peer: &'a Peer, request: Request) -> Fut {
79 self(peer, request)
80 }
81}
82
83#[derive(Debug, PartialEq, Eq, thiserror::Error)]
84#[error("trying to interact with an unknown peer: {peer_id}")]
85pub struct UnknownPeerError {
86 pub peer_id: PeerId,
87}