cuprated/rpc/request/
address_book.rs

1//! Functions for TODO: doc enum message.
2
3use std::convert::Infallible;
4
5use anyhow::{anyhow, Error};
6use tower::ServiceExt;
7
8use cuprate_helper::cast::usize_to_u64;
9use cuprate_p2p_core::{
10    services::{AddressBookRequest, AddressBookResponse},
11    types::{BanState, ConnectionId},
12    AddressBook, NetworkZone,
13};
14use cuprate_pruning::PruningSeed;
15use cuprate_rpc_types::misc::{ConnectionInfo, Span};
16
17use crate::rpc::constants::FIELD_NOT_SUPPORTED;
18
19// FIXME: use `anyhow::Error` over `tower::BoxError` in address book.
20
21/// [`AddressBookRequest::PeerlistSize`]
22pub(crate) async fn peerlist_size<Z: NetworkZone>(
23    address_book: &mut impl AddressBook<Z>,
24) -> Result<(u64, u64), Error> {
25    let AddressBookResponse::PeerlistSize { white, grey } = address_book
26        .ready()
27        .await
28        .map_err(|e| anyhow!(e))?
29        .call(AddressBookRequest::PeerlistSize)
30        .await
31        .map_err(|e| anyhow!(e))?
32    else {
33        unreachable!();
34    };
35
36    Ok((usize_to_u64(white), usize_to_u64(grey)))
37}
38
39/// [`AddressBookRequest::ConnectionInfo`]
40pub(crate) async fn connection_info<Z: NetworkZone>(
41    address_book: &mut impl AddressBook<Z>,
42) -> Result<Vec<ConnectionInfo>, Error> {
43    let AddressBookResponse::ConnectionInfo(vec) = address_book
44        .ready()
45        .await
46        .map_err(|e| anyhow!(e))?
47        .call(AddressBookRequest::ConnectionInfo)
48        .await
49        .map_err(|e| anyhow!(e))?
50    else {
51        unreachable!();
52    };
53
54    // FIXME: impl this map somewhere instead of inline.
55    let vec = vec
56        .into_iter()
57        .map(|info| {
58            let (ip, port) = match info.socket_addr {
59                Some(socket) => (socket.ip().to_string(), socket.port().to_string()),
60                None => (String::new(), String::new()),
61            };
62
63            ConnectionInfo {
64                address: info.address.to_string(),
65                address_type: info.address_type,
66                avg_download: info.avg_download,
67                avg_upload: info.avg_upload,
68                connection_id: String::from(ConnectionId::DEFAULT_STR),
69                current_download: info.current_download,
70                current_upload: info.current_upload,
71                height: info.height,
72                host: info.host,
73                incoming: info.incoming,
74                ip,
75                live_time: info.live_time,
76                localhost: info.localhost,
77                local_ip: info.local_ip,
78                peer_id: hex::encode(info.peer_id.to_ne_bytes()),
79                port,
80                pruning_seed: info.pruning_seed.compress(),
81                recv_count: info.recv_count,
82                recv_idle_time: info.recv_idle_time,
83                rpc_credits_per_hash: info.rpc_credits_per_hash,
84                rpc_port: info.rpc_port,
85                send_count: info.send_count,
86                send_idle_time: info.send_idle_time,
87                state: info.state,
88                support_flags: info.support_flags,
89            }
90        })
91        .collect();
92
93    Ok(vec)
94}
95
96/// [`AddressBookRequest::ConnectionCount`]
97pub(crate) async fn connection_count<Z: NetworkZone>(
98    address_book: &mut impl AddressBook<Z>,
99) -> Result<(u64, u64), Error> {
100    let AddressBookResponse::ConnectionCount { incoming, outgoing } = address_book
101        .ready()
102        .await
103        .map_err(|e| anyhow!(e))?
104        .call(AddressBookRequest::ConnectionCount)
105        .await
106        .map_err(|e| anyhow!(e))?
107    else {
108        unreachable!();
109    };
110
111    Ok((usize_to_u64(incoming), usize_to_u64(outgoing)))
112}
113
114/// [`AddressBookRequest::SetBan`]
115pub(crate) async fn set_ban<Z: NetworkZone>(
116    address_book: &mut impl AddressBook<Z>,
117    set_ban: cuprate_p2p_core::types::SetBan<Z::Addr>,
118) -> Result<(), Error> {
119    let AddressBookResponse::Ok = address_book
120        .ready()
121        .await
122        .map_err(|e| anyhow!(e))?
123        .call(AddressBookRequest::SetBan(set_ban))
124        .await
125        .map_err(|e| anyhow!(e))?
126    else {
127        unreachable!();
128    };
129
130    Ok(())
131}
132
133/// [`AddressBookRequest::GetBan`]
134pub(crate) async fn get_ban<Z: NetworkZone>(
135    address_book: &mut impl AddressBook<Z>,
136    peer: Z::Addr,
137) -> Result<Option<std::time::Instant>, Error> {
138    let AddressBookResponse::GetBan { unban_instant } = address_book
139        .ready()
140        .await
141        .map_err(|e| anyhow!(e))?
142        .call(AddressBookRequest::GetBan(peer))
143        .await
144        .map_err(|e| anyhow!(e))?
145    else {
146        unreachable!();
147    };
148
149    Ok(unban_instant)
150}
151
152/// [`AddressBookRequest::GetBans`]
153pub(crate) async fn get_bans<Z: NetworkZone>(
154    address_book: &mut impl AddressBook<Z>,
155) -> Result<Vec<BanState<Z::Addr>>, Error> {
156    let AddressBookResponse::GetBans(bans) = address_book
157        .ready()
158        .await
159        .map_err(|e| anyhow!(e))?
160        .call(AddressBookRequest::GetBans)
161        .await
162        .map_err(|e| anyhow!(e))?
163    else {
164        unreachable!();
165    };
166
167    Ok(bans)
168}