Skip to main content

soil_rpc/system/
mod.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Substrate system API.
8
9#[cfg(test)]
10mod tests;
11
12use crate::check_if_safe;
13use futures::channel::oneshot;
14use jsonrpsee::{
15	core::{async_trait, JsonValue},
16	Extensions,
17};
18use soil_client::tracing::logging;
19use soil_client::utils::mpsc::TracingUnboundedSender;
20use subsoil::runtime::traits::{self, Header as HeaderT};
21
22pub use self::helpers::{Health, NodeRole, PeerInfo, SyncState, SystemInfo};
23pub use crate::api::system::*;
24
25/// System API implementation
26pub struct System<B: traits::Block> {
27	info: SystemInfo,
28	send_back: TracingUnboundedSender<Request<B>>,
29}
30
31/// Request to be processed.
32pub enum Request<B: traits::Block> {
33	/// Must return the health of the network.
34	Health(oneshot::Sender<Health>),
35	/// Must return the base58-encoded local `PeerId`.
36	LocalPeerId(oneshot::Sender<String>),
37	/// Must return the string representation of the addresses we listen on, including the
38	/// trailing `/p2p/`.
39	LocalListenAddresses(oneshot::Sender<Vec<String>>),
40	/// Must return information about the peers we are connected to.
41	Peers(oneshot::Sender<Vec<PeerInfo<B::Hash, <B::Header as HeaderT>::Number>>>),
42	/// Must return the state of the network.
43	NetworkState(oneshot::Sender<serde_json::Value>),
44	/// Must return any potential parse error.
45	NetworkAddReservedPeer(String, oneshot::Sender<error::Result<()>>),
46	/// Must return any potential parse error.
47	NetworkRemoveReservedPeer(String, oneshot::Sender<error::Result<()>>),
48	/// Must return the list of reserved peers
49	NetworkReservedPeers(oneshot::Sender<Vec<String>>),
50	/// Must return the node role.
51	NodeRoles(oneshot::Sender<Vec<NodeRole>>),
52	/// Must return the state of the node syncing.
53	SyncState(oneshot::Sender<SyncState<<B::Header as HeaderT>::Number>>),
54}
55
56impl<B: traits::Block> System<B> {
57	/// Creates new `System`.
58	///
59	/// The `send_back` will be used to transmit some of the requests. The user is responsible for
60	/// reading from that channel and answering the requests.
61	pub fn new(info: SystemInfo, send_back: TracingUnboundedSender<Request<B>>) -> Self {
62		System { info, send_back }
63	}
64}
65
66#[async_trait]
67impl<B: traits::Block> SystemApiServer<B::Hash, <B::Header as HeaderT>::Number> for System<B> {
68	fn system_name(&self) -> Result<String, Error> {
69		Ok(self.info.impl_name.clone())
70	}
71
72	fn system_version(&self) -> Result<String, Error> {
73		Ok(self.info.impl_version.clone())
74	}
75
76	fn system_chain(&self) -> Result<String, Error> {
77		Ok(self.info.chain_name.clone())
78	}
79
80	fn system_type(&self) -> Result<soil_chain_spec::ChainType, Error> {
81		Ok(self.info.chain_type.clone())
82	}
83
84	fn system_properties(&self) -> Result<soil_chain_spec::Properties, Error> {
85		Ok(self.info.properties.clone())
86	}
87
88	async fn system_health(&self) -> Result<Health, Error> {
89		let (tx, rx) = oneshot::channel();
90		let _ = self.send_back.unbounded_send(Request::Health(tx));
91		rx.await.map_err(|e| Error::Internal(e.to_string()))
92	}
93
94	async fn system_local_peer_id(&self) -> Result<String, Error> {
95		let (tx, rx) = oneshot::channel();
96		let _ = self.send_back.unbounded_send(Request::LocalPeerId(tx));
97		rx.await.map_err(|e| Error::Internal(e.to_string()))
98	}
99
100	async fn system_local_listen_addresses(&self) -> Result<Vec<String>, Error> {
101		let (tx, rx) = oneshot::channel();
102		let _ = self.send_back.unbounded_send(Request::LocalListenAddresses(tx));
103		rx.await.map_err(|e| Error::Internal(e.to_string()))
104	}
105
106	async fn system_peers(
107		&self,
108		ext: &Extensions,
109	) -> Result<Vec<PeerInfo<B::Hash, <B::Header as HeaderT>::Number>>, Error> {
110		check_if_safe(ext)?;
111		let (tx, rx) = oneshot::channel();
112		let _ = self.send_back.unbounded_send(Request::Peers(tx));
113		rx.await.map_err(|e| Error::Internal(e.to_string()))
114	}
115
116	async fn system_network_state(&self, ext: &Extensions) -> Result<JsonValue, Error> {
117		check_if_safe(ext)?;
118		let (tx, rx) = oneshot::channel();
119		let _ = self.send_back.unbounded_send(Request::NetworkState(tx));
120		rx.await.map_err(|e| Error::Internal(e.to_string()))
121	}
122
123	async fn system_add_reserved_peer(&self, ext: &Extensions, peer: String) -> Result<(), Error> {
124		check_if_safe(ext)?;
125		let (tx, rx) = oneshot::channel();
126		let _ = self.send_back.unbounded_send(Request::NetworkAddReservedPeer(peer, tx));
127		match rx.await {
128			Ok(Ok(())) => Ok(()),
129			Ok(Err(e)) => Err(e),
130			Err(e) => Err(Error::Internal(e.to_string())),
131		}
132	}
133
134	async fn system_remove_reserved_peer(
135		&self,
136		ext: &Extensions,
137		peer: String,
138	) -> Result<(), Error> {
139		check_if_safe(ext)?;
140		let (tx, rx) = oneshot::channel();
141		let _ = self.send_back.unbounded_send(Request::NetworkRemoveReservedPeer(peer, tx));
142		match rx.await {
143			Ok(Ok(())) => Ok(()),
144			Ok(Err(e)) => Err(e),
145			Err(e) => Err(Error::Internal(e.to_string())),
146		}
147	}
148
149	async fn system_reserved_peers(&self) -> Result<Vec<String>, Error> {
150		let (tx, rx) = oneshot::channel();
151		let _ = self.send_back.unbounded_send(Request::NetworkReservedPeers(tx));
152		rx.await.map_err(|e| Error::Internal(e.to_string()))
153	}
154
155	async fn system_node_roles(&self) -> Result<Vec<NodeRole>, Error> {
156		let (tx, rx) = oneshot::channel();
157		let _ = self.send_back.unbounded_send(Request::NodeRoles(tx));
158		rx.await.map_err(|e| Error::Internal(e.to_string()))
159	}
160
161	async fn system_sync_state(&self) -> Result<SyncState<<B::Header as HeaderT>::Number>, Error> {
162		let (tx, rx) = oneshot::channel();
163		let _ = self.send_back.unbounded_send(Request::SyncState(tx));
164		rx.await.map_err(|e| Error::Internal(e.to_string()))
165	}
166
167	fn system_add_log_filter(&self, ext: &Extensions, directives: String) -> Result<(), Error> {
168		check_if_safe(ext)?;
169
170		logging::add_directives(&directives);
171		logging::reload_filter().map_err(|e| Error::Internal(e))
172	}
173
174	fn system_reset_log_filter(&self, ext: &Extensions) -> Result<(), Error> {
175		check_if_safe(ext)?;
176		logging::reset_log_filter().map_err(|e| Error::Internal(e))
177	}
178}