client.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! JSON-RPC client-side implementation.
  19. use std::time::Duration;
  20. use async_std::io::timeout;
  21. use futures::{select, AsyncReadExt, AsyncWriteExt, FutureExt};
  22. use log::{debug, error};
  23. use serde_json::{json, Value};
  24. use url::Url;
  25. use super::jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResult};
  26. use crate::{
  27. net::transport::{
  28. TcpTransport, TorTransport, Transport, TransportName, TransportStream, UnixTransport,
  29. },
  30. system::SubscriberPtr,
  31. Error, Result,
  32. };
  33. /// JSON-RPC client implementation using asynchronous channels.
  34. pub struct RpcClient {
  35. send: smol::channel::Sender<Value>,
  36. recv: smol::channel::Receiver<JsonResult>,
  37. stop_signal: smol::channel::Sender<()>,
  38. url: Url,
  39. }
  40. impl RpcClient {
  41. /// Instantiate a new JSON-RPC client that will connect to the given URL.
  42. pub async fn new(url: Url) -> Result<Self> {
  43. let (send, recv, stop_signal) = Self::open_channels(&url).await?;
  44. Ok(Self { send, recv, stop_signal, url })
  45. }
  46. /// Close the channels of an instantiated [`RpcClient`].
  47. pub async fn close(&self) -> Result<()> {
  48. self.stop_signal.send(()).await?;
  49. Ok(())
  50. }
  51. /// Listen instantiated client for notifications.
  52. /// NOTE: Subscriber listeners must perform response handling.
  53. pub async fn subscribe(
  54. &self,
  55. req: JsonRequest,
  56. subscriber: SubscriberPtr<JsonResult>,
  57. ) -> Result<()> {
  58. // Perform initial request.
  59. debug!(target: "jsonrpc-client", "--> {}", serde_json::to_string(&req)?);
  60. // If the connection is closed, the sender will get an error for sending to a closed channel.
  61. if let Err(e) = self.send.send(json!(req)).await {
  62. error!(target: "jsonrpc-client", "JSON-RPC client unable to send to {} (channels closed): {}", self.url, e);
  63. return Err(Error::NetworkOperationFailed)
  64. }
  65. loop {
  66. // If the connection is closed, the receiver will get an error for waiting on a closed channel.
  67. let notification = self.recv.recv().await;
  68. if notification.is_err() {
  69. error!(target: "jsonrpc-client", "JSON-RPC client unable to recv from {} (channels closed)", self.url);
  70. break
  71. }
  72. // Notify subscribed channels
  73. let notification = notification?;
  74. debug!(target: "jsonrpc-client", "<-- {}", serde_json::to_string(&notification)?);
  75. subscriber.notify(notification.clone()).await;
  76. // Stop listenning on error
  77. match notification {
  78. JsonResult::Notification(_) => {}
  79. _ => break,
  80. }
  81. // Triggering next consume
  82. if let Err(e) = self.send.send(json!(req)).await {
  83. error!(target: "jsonrpc-client", "JSON-RPC client unable to send to {} (channels closed): {}", self.url, e);
  84. break
  85. }
  86. }
  87. subscriber.notify(JsonError::new(ErrorCode::InternalError, None, req.id).into()).await;
  88. Err(Error::NetworkOperationFailed)
  89. }
  90. /// Send a given JSON-RPC request over the instantiated client.
  91. pub async fn request(&self, value: JsonRequest) -> Result<Value> {
  92. let req_id = value.id.clone().as_u64().unwrap();
  93. debug!(target: "jsonrpc-client", "--> {}", serde_json::to_string(&value)?);
  94. // If the connection is closed, the sender will get an error for
  95. // sending to a closed channel.
  96. if let Err(e) = self.send.send(json!(value)).await {
  97. error!("JSON-RPC client unable to send to {} (channels closed): {}", self.url, e);
  98. return Err(Error::NetworkOperationFailed)
  99. }
  100. // If the connection is closed, the receiver will get an error for
  101. // waiting on a closed channel.
  102. let reply = self.recv.recv().await;
  103. if reply.is_err() {
  104. error!("JSON-RPC client unable to recv from {} (channels closed)", self.url);
  105. return Err(Error::NetworkOperationFailed)
  106. }
  107. match reply? {
  108. JsonResult::Response(r) => {
  109. // Check if the IDs match
  110. let resp_id = r.id.as_u64();
  111. if resp_id.is_none() {
  112. let e = JsonError::new(ErrorCode::InvalidId, None, r.id);
  113. //self.stop_signal.send(()).await?;
  114. return Err(Error::JsonRpcError(e.error.message.to_string()))
  115. }
  116. if resp_id.unwrap() != req_id {
  117. let e = JsonError::new(ErrorCode::InvalidId, None, r.id);
  118. //self.stop_signal.send(()).await?;
  119. return Err(Error::JsonRpcError(e.error.message.to_string()))
  120. }
  121. debug!(target: "jsonrpc-client", "<-- {}", serde_json::to_string(&r)?);
  122. Ok(r.result)
  123. }
  124. JsonResult::Error(e) => {
  125. debug!(target: "jsonrpc-client", "<-- {}", serde_json::to_string(&e)?);
  126. // Close the server connection
  127. //self.stop_signal.send(()).await?;
  128. Err(Error::JsonRpcError(e.error.message.to_string()))
  129. }
  130. JsonResult::Notification(n) => {
  131. debug!(target: "jsonrpc-client", "<-- {}", serde_json::to_string(&n)?);
  132. // Close the server connection
  133. //self.stop_signal.send(()).await?;
  134. Err(Error::JsonRpcError("Unexpected reply".to_string()))
  135. }
  136. JsonResult::Subscriber(_) => Err(Error::JsonRpcError("Unexpected reply".to_string())),
  137. }
  138. }
  139. /// Oneshot send a given JSON-RPC request over the instantiated client
  140. /// and close the channels on reply.
  141. pub async fn oneshot_request(&self, value: JsonRequest) -> Result<Value> {
  142. let rep = self.request(value).await?;
  143. self.stop_signal.send(()).await?;
  144. Ok(rep)
  145. }
  146. /// Instantiate channels for a new [`RpcClient`].
  147. async fn open_channels(
  148. uri: &Url,
  149. ) -> Result<(
  150. smol::channel::Sender<Value>,
  151. smol::channel::Receiver<JsonResult>,
  152. smol::channel::Sender<()>,
  153. )> {
  154. let (data_send, data_recv) = smol::channel::unbounded();
  155. let (result_send, result_recv) = smol::channel::unbounded();
  156. let (stop_send, stop_recv) = smol::channel::unbounded();
  157. let transport_name = TransportName::try_from(uri.clone())?;
  158. macro_rules! reqrep {
  159. ($stream:expr, $transport:expr, $upgrade:expr) => {{
  160. if let Err(err) = $stream {
  161. error!("JSON-RPC client setup for {} failed: {}", uri, err);
  162. return Err(Error::ConnectFailed)
  163. }
  164. let stream = $stream?.await;
  165. if let Err(err) = stream {
  166. error!("JSON-RPC client connection to {} failed: {}", uri, err);
  167. return Err(Error::ConnectFailed)
  168. }
  169. let stream = stream?;
  170. match $upgrade {
  171. None => {
  172. smol::spawn(Self::reqrep_loop(stream, result_send, data_recv, stop_recv))
  173. .detach();
  174. }
  175. Some(u) if u == "tls" => {
  176. let stream = $transport.upgrade_dialer(stream)?.await?;
  177. smol::spawn(Self::reqrep_loop(stream, result_send, data_recv, stop_recv))
  178. .detach();
  179. }
  180. Some(u) => return Err(Error::UnsupportedTransportUpgrade(u)),
  181. }
  182. }};
  183. }
  184. match transport_name {
  185. TransportName::Tcp(upgrade) => {
  186. let transport = TcpTransport::new(None, 1024);
  187. let stream = transport.dial(uri.clone(), None);
  188. reqrep!(stream, transport, upgrade);
  189. }
  190. TransportName::Tor(upgrade) => {
  191. let socks5_url = TorTransport::get_dialer_env()?;
  192. let transport = TorTransport::new(socks5_url, None)?;
  193. let stream = transport.clone().dial(uri.clone(), None);
  194. reqrep!(stream, transport, upgrade);
  195. }
  196. TransportName::Unix => {
  197. let transport = UnixTransport::new();
  198. let stream = transport.dial(uri.clone()).await;
  199. if let Err(err) = stream {
  200. error!("JSON-RPC client connection to {} failed: {}", uri, err);
  201. return Err(Error::ConnectFailed)
  202. }
  203. smol::spawn(Self::reqrep_loop(stream?, result_send, data_recv, stop_recv)).detach();
  204. }
  205. _ => unimplemented!(),
  206. }
  207. Ok((data_send, result_recv, stop_send))
  208. }
  209. /// Internal function that loops on a given stream and multiplexes the data.
  210. async fn reqrep_loop<T: TransportStream>(
  211. mut stream: T,
  212. result_send: smol::channel::Sender<JsonResult>,
  213. data_recv: smol::channel::Receiver<Value>,
  214. stop_recv: smol::channel::Receiver<()>,
  215. ) -> Result<()> {
  216. // If we don't get a reply within 30 seconds, we'll fail.
  217. let read_timeout = Duration::from_secs(30);
  218. loop {
  219. // FIXME: Nasty size. 8M
  220. let mut buf = vec![0; 1024 * 8192];
  221. select! {
  222. data = data_recv.recv().fuse() => {
  223. let data_bytes = serde_json::to_vec(&data?)?;
  224. stream.write_all(&data_bytes).await?;
  225. let n = timeout(read_timeout, async { stream.read(&mut buf[..]).await }).await?;
  226. let reply: JsonResult = serde_json::from_slice(&buf[0..n])?;
  227. result_send.send(reply).await?;
  228. }
  229. _ = stop_recv.recv().fuse() => break
  230. }
  231. }
  232. Ok(())
  233. }
  234. }