Skip to main content

clightningrpc_common/
client.rs

1// Rust JSON-RPC Library
2// Written by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//     Wladimir J. van der Laan <laanwj@gmail.com>
5//
6// To the extent possible under law, the author(s) have dedicated all
7// copyright and related and neighboring rights to this software to
8// the public domain worldwide. This software is distributed without
9// any warranty.
10//
11// You should have received a copy of the CC0 Public Domain Dedication
12// along with this software.
13// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
14//
15
16//! Client support
17//!
18//! Support for connecting to JSONRPC servers over UNIX socets, sending requests,
19//! and parsing responses
20//!
21
22use std::os::unix::net::UnixStream;
23use std::path::{Path, PathBuf};
24use std::time::Duration;
25
26use serde::de::DeserializeOwned;
27use serde::Serialize;
28use serde_json::{to_writer, Deserializer};
29
30use crate::errors::Error;
31use crate::types::{Request, Response};
32
33/// A handle to a remote JSONRPC server
34#[derive(Debug)]
35pub struct Client {
36    /// field that defines path to the lightning-rpc socket file
37    sockpath: PathBuf,
38    /// timeout for RPC request
39    timeout: Option<Duration>,
40}
41
42impl Client {
43    /// Creates a new client using the path to the socket file and initializing the timeout field to None
44    pub fn new<P: AsRef<Path>>(sockpath: P) -> Client {
45        Client {
46            sockpath: sockpath.as_ref().to_path_buf(),
47            timeout: None,
48        }
49    }
50
51    /// Set an optional timeout for requests
52    pub fn set_timeout(&mut self, timeout: Option<Duration>) {
53        self.timeout = timeout;
54    }
55
56    /// Sends a request to a client
57    pub fn send_request<S: Serialize, D: DeserializeOwned>(
58        &self,
59        method: &str,
60        params: S,
61    ) -> Result<Response<D>, Error> {
62        // Setup connection
63        let mut stream = UnixStream::connect(&self.sockpath)?;
64        stream.set_read_timeout(self.timeout)?;
65        stream.set_write_timeout(self.timeout)?;
66
67        to_writer(
68            &mut stream,
69            &Request {
70                method: method.to_owned(),
71                params,
72                // FIXME: use a custom json to identify the json request!
73                id: Some("0".into()), // we always open a new connection, so we don't have to care about the nonce
74                jsonrpc: "2.0".to_owned(),
75            },
76        )?;
77
78        let response: Response<D> = Deserializer::from_reader(&mut stream)
79            .into_iter()
80            .next()
81            .map_or(Err(Error::NoErrorOrResult), |res| Ok(res?))?;
82        if response
83            .jsonrpc
84            .as_ref()
85            .map_or(false, |version| version != "2.0")
86        {
87            return Err(Error::VersionMismatch);
88        }
89
90        Ok(response)
91    }
92}