cuprated/rpc/service/
address_book.rs
1use std::net::SocketAddrV4;
4
5use anyhow::{anyhow, Error};
6use tower::ServiceExt;
7
8use cuprate_helper::{cast::usize_to_u64, map::u32_from_ipv4};
9use cuprate_p2p_core::{
10 services::{AddressBookRequest, AddressBookResponse, ZoneSpecificPeerListEntryBase},
11 types::{BanState, ConnectionId},
12 AddressBook, NetworkZone,
13};
14use cuprate_rpc_types::misc::ConnectionInfo;
15use cuprate_types::rpc::Peer;
16
17pub async fn peerlist_size<Z: NetworkZone>(
21 address_book: &mut impl AddressBook<Z>,
22) -> Result<(u64, u64), Error> {
23 let AddressBookResponse::PeerlistSize { white, grey } = address_book
24 .ready()
25 .await
26 .map_err(|e| anyhow!(e))?
27 .call(AddressBookRequest::PeerlistSize)
28 .await
29 .map_err(|e| anyhow!(e))?
30 else {
31 unreachable!();
32 };
33
34 Ok((usize_to_u64(white), usize_to_u64(grey)))
35}
36
37pub async fn connection_info<Z: NetworkZone>(
39 address_book: &mut impl AddressBook<Z>,
40) -> Result<Vec<ConnectionInfo>, Error> {
41 let AddressBookResponse::ConnectionInfo(vec) = address_book
42 .ready()
43 .await
44 .map_err(|e| anyhow!(e))?
45 .call(AddressBookRequest::ConnectionInfo)
46 .await
47 .map_err(|e| anyhow!(e))?
48 else {
49 unreachable!();
50 };
51
52 let vec = vec
54 .into_iter()
55 .map(|info| {
56 let (ip, port) = match info.socket_addr {
57 Some(socket) => (socket.ip().to_string(), socket.port().to_string()),
58 None => (String::new(), String::new()),
59 };
60
61 ConnectionInfo {
62 address: info.address.to_string(),
63 address_type: info.address_type,
64 avg_download: info.avg_download,
65 avg_upload: info.avg_upload,
66 connection_id: String::from(ConnectionId::DEFAULT_STR),
67 current_download: info.current_download,
68 current_upload: info.current_upload,
69 height: info.height,
70 host: info.host,
71 incoming: info.incoming,
72 ip,
73 live_time: info.live_time,
74 localhost: info.localhost,
75 local_ip: info.local_ip,
76 peer_id: hex::encode(info.peer_id.to_ne_bytes()),
77 port,
78 pruning_seed: info.pruning_seed.compress(),
79 recv_count: info.recv_count,
80 recv_idle_time: info.recv_idle_time,
81 rpc_credits_per_hash: info.rpc_credits_per_hash,
82 rpc_port: info.rpc_port,
83 send_count: info.send_count,
84 send_idle_time: info.send_idle_time,
85 state: info.state,
86 support_flags: info.support_flags,
87 }
88 })
89 .collect();
90
91 Ok(vec)
92}
93
94pub async fn connection_count<Z: NetworkZone>(
96 address_book: &mut impl AddressBook<Z>,
97) -> Result<(u64, u64), Error> {
98 let AddressBookResponse::ConnectionCount { incoming, outgoing } = address_book
99 .ready()
100 .await
101 .map_err(|e| anyhow!(e))?
102 .call(AddressBookRequest::ConnectionCount)
103 .await
104 .map_err(|e| anyhow!(e))?
105 else {
106 unreachable!();
107 };
108
109 Ok((usize_to_u64(incoming), usize_to_u64(outgoing)))
110}
111
112pub async fn set_ban<Z: NetworkZone>(
114 address_book: &mut impl AddressBook<Z>,
115 set_ban: cuprate_p2p_core::types::SetBan<Z::Addr>,
116) -> Result<(), Error> {
117 let AddressBookResponse::Ok = address_book
118 .ready()
119 .await
120 .map_err(|e| anyhow!(e))?
121 .call(AddressBookRequest::SetBan(set_ban))
122 .await
123 .map_err(|e| anyhow!(e))?
124 else {
125 unreachable!();
126 };
127
128 Ok(())
129}
130
131pub async fn get_ban<Z: NetworkZone>(
133 address_book: &mut impl AddressBook<Z>,
134 peer: Z::Addr,
135) -> Result<Option<std::time::Instant>, Error> {
136 let AddressBookResponse::GetBan { unban_instant } = address_book
137 .ready()
138 .await
139 .map_err(|e| anyhow!(e))?
140 .call(AddressBookRequest::GetBan(peer))
141 .await
142 .map_err(|e| anyhow!(e))?
143 else {
144 unreachable!();
145 };
146
147 Ok(unban_instant)
148}
149
150pub async fn get_bans<Z: NetworkZone>(
152 address_book: &mut impl AddressBook<Z>,
153) -> Result<Vec<BanState<Z::Addr>>, Error> {
154 let AddressBookResponse::GetBans(bans) = address_book
155 .ready()
156 .await
157 .map_err(|e| anyhow!(e))?
158 .call(AddressBookRequest::GetBans)
159 .await
160 .map_err(|e| anyhow!(e))?
161 else {
162 unreachable!();
163 };
164
165 Ok(bans)
166}
167
168pub async fn peerlist<Z: NetworkZone>(
170 address_book: &mut impl AddressBook<Z>,
171) -> Result<(Vec<Peer>, Vec<Peer>), Error> {
172 let AddressBookResponse::Peerlist(peerlist) = address_book
173 .ready()
174 .await
175 .map_err(|e| anyhow!(e))?
176 .call(AddressBookRequest::Peerlist)
177 .await
178 .map_err(|e| anyhow!(e))?
179 else {
180 unreachable!();
181 };
182
183 fn map<Z: NetworkZone>(peers: Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>) -> Vec<Peer> {
184 peers
185 .into_iter()
186 .map(|peer| {
187 let ZoneSpecificPeerListEntryBase {
188 adr,
189 id,
190 last_seen,
191 pruning_seed,
192 rpc_port,
193 rpc_credits_per_hash,
194 } = peer;
195
196 let host = adr.to_string();
197
198 let (ip, port) = if let Ok(socket_addr) = host.parse::<SocketAddrV4>() {
199 (u32_from_ipv4(*socket_addr.ip()), socket_addr.port())
200 } else {
201 (0, 0)
202 };
203
204 let last_seen = last_seen.try_into().unwrap_or(0);
205 let pruning_seed = pruning_seed.compress();
206
207 Peer {
208 id,
209 host,
210 ip,
211 port,
212 rpc_port,
213 rpc_credits_per_hash,
214 last_seen,
215 pruning_seed,
216 }
217 })
218 .collect()
219 }
220
221 let white = map::<Z>(peerlist.white);
222 let grey = map::<Z>(peerlist.grey);
223
224 Ok((white, grey))
225}