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