1mod types;
5use itertools::Itertools;
6pub use types::*;
7
8use std::any::Any;
9use std::str::FromStr;
10
11use crate::libp2p::{NetRPCMethods, NetworkMessage, PeerId};
12use crate::rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError};
13use anyhow::{Context as _, Result};
14use cid::multibase;
15use enumflags2::BitFlags;
16use fvm_ipld_blockstore::Blockstore;
17
18pub enum NetAddrsListen {}
19impl RpcMethod<0> for NetAddrsListen {
20 const NAME: &'static str = "Filecoin.NetAddrsListen";
21 const PARAM_NAMES: [&'static str; 0] = [];
22 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
23 const PERMISSION: Permission = Permission::Read;
24 const DESCRIPTION: Option<&'static str> =
25 Some("Returns a list of listening addresses and the peer ID.");
26
27 type Params = ();
28 type Ok = AddrInfo;
29
30 async fn handle(
31 ctx: Ctx<impl Blockstore>,
32 (): Self::Params,
33 _: &http::Extensions,
34 ) -> Result<Self::Ok, ServerError> {
35 let (tx, rx) = flume::bounded(1);
36 let req = NetworkMessage::JSONRPCRequest {
37 method: NetRPCMethods::AddrsListen(tx),
38 };
39
40 ctx.network_send().send_async(req).await?;
41 let (id, addrs) = rx.recv_async().await?;
42
43 Ok(AddrInfo::new(id, addrs))
44 }
45}
46
47pub enum NetPeers {}
48impl RpcMethod<0> for NetPeers {
49 const NAME: &'static str = "Filecoin.NetPeers";
50 const PARAM_NAMES: [&'static str; 0] = [];
51 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
52 const PERMISSION: Permission = Permission::Read;
53 const DESCRIPTION: Option<&'static str> = Some("Returns a list of currently connected peers.");
54
55 type Params = ();
56 type Ok = Vec<AddrInfo>;
57
58 async fn handle(
59 ctx: Ctx<impl Blockstore>,
60 (): Self::Params,
61 _: &http::Extensions,
62 ) -> Result<Self::Ok, ServerError> {
63 let (tx, rx) = flume::bounded(1);
64 let req = NetworkMessage::JSONRPCRequest {
65 method: NetRPCMethods::Peers(tx),
66 };
67
68 ctx.network_send().send_async(req).await?;
69 let peer_addresses = rx.recv_async().await?;
70
71 let connections = peer_addresses
72 .into_iter()
73 .map(|(id, addrs)| AddrInfo::new(id, addrs))
74 .collect();
75
76 Ok(connections)
77 }
78}
79
80pub enum NetFindPeer {}
81impl RpcMethod<1> for NetFindPeer {
82 const NAME: &'static str = "Filecoin.NetFindPeer";
83 const PARAM_NAMES: [&'static str; 1] = ["peer_id"];
84 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
85 const PERMISSION: Permission = Permission::Read;
86
87 type Params = (String,);
88 type Ok = AddrInfo;
89
90 async fn handle(
91 ctx: Ctx<impl Blockstore>,
92 (peer_id,): Self::Params,
93 _: &http::Extensions,
94 ) -> Result<Self::Ok, ServerError> {
95 let peer_id = PeerId::from_str(&peer_id)?;
96 let (tx, rx) = flume::bounded(1);
97 ctx.network_send()
98 .send_async(NetworkMessage::JSONRPCRequest {
99 method: NetRPCMethods::Peer(tx, peer_id),
100 })
101 .await?;
102 let addrs = rx
103 .recv_async()
104 .await?
105 .with_context(|| format!("peer {peer_id} not found"))?;
106 Ok(AddrInfo::new(peer_id, addrs))
107 }
108}
109
110pub enum NetListening {}
111impl RpcMethod<0> for NetListening {
112 const NAME: &'static str = "Filecoin.NetListening";
113 const PARAM_NAMES: [&'static str; 0] = [];
114 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all_with_v2();
115 const PERMISSION: Permission = Permission::Read;
116 const NAME_ALIAS: Option<&'static str> = Some("net_listening");
117
118 type Params = ();
119 type Ok = bool;
120
121 async fn handle(
122 _: Ctx<impl Any>,
123 (): Self::Params,
124 _: &http::Extensions,
125 ) -> Result<Self::Ok, ServerError> {
126 Ok(true)
127 }
128}
129
130pub enum NetInfo {}
131impl RpcMethod<0> for NetInfo {
132 const NAME: &'static str = "Forest.NetInfo";
133 const PARAM_NAMES: [&'static str; 0] = [];
134 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
135 const PERMISSION: Permission = Permission::Read;
136
137 type Params = ();
138 type Ok = NetInfoResult;
139
140 async fn handle(
141 ctx: Ctx<impl Blockstore>,
142 (): Self::Params,
143 _: &http::Extensions,
144 ) -> Result<Self::Ok, ServerError> {
145 let (tx, rx) = flume::bounded(1);
146 let req = NetworkMessage::JSONRPCRequest {
147 method: NetRPCMethods::Info(tx),
148 };
149
150 ctx.network_send().send_async(req).await?;
151 Ok(rx.recv_async().await?)
152 }
153}
154
155pub enum NetConnect {}
156impl RpcMethod<1> for NetConnect {
157 const NAME: &'static str = "Filecoin.NetConnect";
158 const PARAM_NAMES: [&'static str; 1] = ["peerAddressInfo"];
159 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
160 const PERMISSION: Permission = Permission::Write;
161 const DESCRIPTION: Option<&'static str> = Some("Connects to a specified peer.");
162
163 type Params = (AddrInfo,);
164 type Ok = ();
165
166 async fn handle(
167 ctx: Ctx<impl Blockstore>,
168 (AddrInfo { id, addrs },): Self::Params,
169 _: &http::Extensions,
170 ) -> Result<Self::Ok, ServerError> {
171 let (_, id) = multibase::decode(format!("{}{}", "z", id))?;
172 let peer_id = PeerId::from_bytes(&id)?;
173
174 let (tx, rx) = flume::bounded(1);
175 let req = NetworkMessage::JSONRPCRequest {
176 method: NetRPCMethods::Connect(tx, peer_id, addrs),
177 };
178
179 ctx.network_send().send_async(req).await?;
180 let success = rx.recv_async().await?;
181
182 if success {
183 Ok(())
184 } else {
185 Err(anyhow::anyhow!("Peer could not be dialed from any address provided").into())
186 }
187 }
188}
189
190pub enum NetDisconnect {}
191impl RpcMethod<1> for NetDisconnect {
192 const NAME: &'static str = "Filecoin.NetDisconnect";
193 const PARAM_NAMES: [&'static str; 1] = ["peerId"];
194 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
195 const PERMISSION: Permission = Permission::Write;
196 const DESCRIPTION: Option<&'static str> = Some("Disconnects from the specified peer.");
197
198 type Params = (String,);
199 type Ok = ();
200
201 async fn handle(
202 ctx: Ctx<impl Blockstore>,
203 (peer_id,): Self::Params,
204 _: &http::Extensions,
205 ) -> Result<Self::Ok, ServerError> {
206 let peer_id = PeerId::from_str(&peer_id)?;
207
208 let (tx, rx) = flume::bounded(1);
209 let req = NetworkMessage::JSONRPCRequest {
210 method: NetRPCMethods::Disconnect(tx, peer_id),
211 };
212
213 ctx.network_send().send_async(req).await?;
214 rx.recv_async().await?;
215
216 Ok(())
217 }
218}
219
220pub enum NetAgentVersion {}
221impl RpcMethod<1> for NetAgentVersion {
222 const NAME: &'static str = "Filecoin.NetAgentVersion";
223 const PARAM_NAMES: [&'static str; 1] = ["peerId"];
224 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
225 const PERMISSION: Permission = Permission::Read;
226 const DESCRIPTION: Option<&'static str> = Some("Returns the agent version string.");
227
228 type Params = (String,);
229 type Ok = String;
230
231 async fn handle(
232 ctx: Ctx<impl Blockstore>,
233 (peer_id,): Self::Params,
234 _: &http::Extensions,
235 ) -> Result<Self::Ok, ServerError> {
236 let peer_id = PeerId::from_str(&peer_id)?;
237 let (tx, rx) = flume::bounded(1);
238 ctx.network_send()
239 .send_async(NetworkMessage::JSONRPCRequest {
240 method: NetRPCMethods::AgentVersion(tx, peer_id),
241 })
242 .await?;
243 Ok(rx.recv_async().await?.context("item not found")?)
244 }
245}
246
247pub enum NetAutoNatStatus {}
248impl RpcMethod<0> for NetAutoNatStatus {
249 const NAME: &'static str = "Filecoin.NetAutoNatStatus";
250 const PARAM_NAMES: [&'static str; 0] = [];
251 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
252 const PERMISSION: Permission = Permission::Read;
253
254 type Params = ();
255 type Ok = NatStatusResult;
256
257 async fn handle(
258 ctx: Ctx<impl Blockstore>,
259 (): Self::Params,
260 _: &http::Extensions,
261 ) -> Result<Self::Ok, ServerError> {
262 let (tx, rx) = flume::bounded(1);
263 let req = NetworkMessage::JSONRPCRequest {
264 method: NetRPCMethods::AutoNATStatus(tx),
265 };
266 ctx.network_send().send_async(req).await?;
267 let nat_status = rx.recv_async().await?;
268 Ok(nat_status.into())
269 }
270}
271
272pub enum NetVersion {}
273impl RpcMethod<0> for NetVersion {
274 const NAME: &'static str = "Filecoin.NetVersion";
275 const PARAM_NAMES: [&'static str; 0] = [];
276 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all_with_v2();
277 const PERMISSION: Permission = Permission::Read;
278 const NAME_ALIAS: Option<&'static str> = Some("net_version");
279
280 type Params = ();
281 type Ok = String;
282
283 async fn handle(
284 ctx: Ctx<impl Blockstore>,
285 (): Self::Params,
286 _: &http::Extensions,
287 ) -> Result<Self::Ok, ServerError> {
288 Ok(ctx.chain_config().eth_chain_id.to_string())
289 }
290}
291
292pub enum NetProtectAdd {}
293impl RpcMethod<1> for NetProtectAdd {
294 const NAME: &'static str = "Filecoin.NetProtectAdd";
295 const PARAM_NAMES: [&'static str; 1] = ["peerIdList"];
296 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
297 const PERMISSION: Permission = Permission::Admin;
298 const DESCRIPTION: Option<&'static str> = Some(
299 "Protects a peer from having its connection(s) pruned in the event the libp2p host reaches its maximum number of peers.",
300 );
301
302 type Params = (Vec<String>,);
303 type Ok = ();
304
305 async fn handle(
310 ctx: Ctx<impl Blockstore>,
311 (peer_ids,): Self::Params,
312 _: &http::Extensions,
313 ) -> Result<Self::Ok, ServerError> {
314 let peer_ids = peer_ids
315 .iter()
316 .map(String::as_str)
317 .map(PeerId::from_str)
318 .try_collect()?;
319 let (tx, rx) = flume::bounded(1);
320 ctx.network_send()
321 .send_async(NetworkMessage::JSONRPCRequest {
322 method: NetRPCMethods::ProtectPeer(tx, peer_ids),
323 })
324 .await?;
325 rx.recv_async().await?;
326 Ok(())
327 }
328}
329
330pub enum NetProtectList {}
331impl RpcMethod<0> for NetProtectList {
332 const NAME: &'static str = "Filecoin.NetProtectList";
333 const PARAM_NAMES: [&'static str; 0] = [];
334 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
335 const PERMISSION: Permission = Permission::Read;
336 const DESCRIPTION: Option<&'static str> = Some("Returns the current list of protected peers.");
337
338 type Params = ();
339 type Ok = Vec<String>;
340 async fn handle(
341 ctx: Ctx<impl Blockstore>,
342 (): Self::Params,
343 _: &http::Extensions,
344 ) -> Result<Self::Ok, ServerError> {
345 let (tx, rx) = flume::bounded(1);
346 ctx.network_send()
347 .send_async(NetworkMessage::JSONRPCRequest {
348 method: NetRPCMethods::ListProtectedPeers(tx),
349 })
350 .await?;
351 let peers = rx.recv_async().await?;
352 Ok(peers.into_iter().map(|p| p.to_string()).collect())
353 }
354}
355
356pub enum NetProtectRemove {}
357impl RpcMethod<1> for NetProtectRemove {
358 const NAME: &'static str = "Filecoin.NetProtectRemove";
359 const PARAM_NAMES: [&'static str; 1] = ["peerIdList"];
360 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
361 const PERMISSION: Permission = Permission::Admin;
362 const DESCRIPTION: Option<&'static str> = Some("Remove a peer from the protected list.");
363
364 type Params = (Vec<String>,);
365 type Ok = ();
366
367 async fn handle(
369 ctx: Ctx<impl Blockstore>,
370 (peer_ids,): Self::Params,
371 _: &http::Extensions,
372 ) -> Result<Self::Ok, ServerError> {
373 let peer_ids = peer_ids
374 .iter()
375 .map(String::as_str)
376 .map(PeerId::from_str)
377 .try_collect()?;
378 let (tx, rx) = flume::bounded(1);
379 ctx.network_send()
380 .send_async(NetworkMessage::JSONRPCRequest {
381 method: NetRPCMethods::UnprotectPeer(tx, peer_ids),
382 })
383 .await?;
384 rx.recv_async().await?;
385 Ok(())
386 }
387}