corepc_client/client_sync/
mod.rs1mod error;
6pub mod v17;
7pub mod v18;
8pub mod v19;
9pub mod v20;
10pub mod v21;
11pub mod v22;
12pub mod v23;
13pub mod v24;
14pub mod v25;
15pub mod v26;
16pub mod v27;
17pub mod v28;
18pub mod v29;
19pub mod v30;
20
21use std::fs::File;
22use std::io::{BufRead, BufReader};
23use std::path::PathBuf;
24
25pub use crate::client_sync::error::Error;
26
27pub type Result<T> = std::result::Result<T, Error>;
31
32#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
34pub enum Auth {
35 None,
36 UserPass(String, String),
37 CookieFile(PathBuf),
38}
39
40impl Auth {
41 pub fn get_user_pass(self) -> Result<(Option<String>, Option<String>)> {
43 match self {
44 Auth::None => Ok((None, None)),
45 Auth::UserPass(u, p) => Ok((Some(u), Some(p))),
46 Auth::CookieFile(path) => {
47 let line = BufReader::new(File::open(path)?)
48 .lines()
49 .next()
50 .ok_or(Error::InvalidCookieFile)??;
51 let colon = line.find(':').ok_or(Error::InvalidCookieFile)?;
52 Ok((Some(line[..colon].into()), Some(line[colon + 1..].into())))
53 }
54 }
55 }
56}
57
58#[macro_export]
60macro_rules! define_jsonrpc_bitreq_client {
61 ($version:literal) => {
62 use std::fmt;
63
64 use $crate::client_sync::{log_response, Auth, Result};
65 use $crate::client_sync::error::Error;
66
67 pub struct Client {
69 inner: jsonrpc::client::Client,
70 }
71
72 impl fmt::Debug for Client {
73 fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
74 write!(
75 f,
76 "corepc_client::client_sync::{}::Client({:?})", $version, self.inner
77 )
78 }
79 }
80
81 impl Client {
82 pub fn new(url: &str) -> Self {
84 let transport = jsonrpc::http::bitreq_http::Builder::new()
85 .url(url)
86 .expect("jsonrpc v0.19, this function does not error")
87 .timeout(std::time::Duration::from_secs(60))
88 .build();
89 let inner = jsonrpc::client::Client::with_transport(transport);
90
91 Self { inner }
92 }
93
94 pub fn new_with_auth(url: &str, auth: Auth) -> Result<Self> {
96 if matches!(auth, Auth::None) {
97 return Err(Error::MissingUserPassword);
98 }
99 let (user, pass) = auth.get_user_pass()?;
100
101 let transport = jsonrpc::http::bitreq_http::Builder::new()
102 .url(url)
103 .expect("jsonrpc v0.19, this function does not error")
104 .timeout(std::time::Duration::from_secs(60))
105 .basic_auth(user.unwrap(), pass)
106 .build();
107 let inner = jsonrpc::client::Client::with_transport(transport);
108
109 Ok(Self { inner })
110 }
111
112 pub fn call<T: for<'a> serde::de::Deserialize<'a>>(
114 &self,
115 method: &str,
116 args: &[serde_json::Value],
117 ) -> Result<T> {
118 let raw = serde_json::value::to_raw_value(args)?;
119 let req = self.inner.build_request(&method, Some(&*raw));
120 if log::log_enabled!(log::Level::Debug) {
121 log::debug!(target: "corepc", "request: {} {}", method, serde_json::Value::from(args));
122 }
123
124 let resp = self.inner.send_request(req).map_err(Error::from);
125 log_response(method, &resp);
126 Ok(resp?.result()?)
127 }
128 }
129 }
130}
131
132#[macro_export]
141macro_rules! impl_client_check_expected_server_version {
142 ($expected_versions:expr) => {
143 impl Client {
144 pub fn check_expected_server_version(&self) -> Result<()> {
146 let server_version = self.server_version()?;
147 if !$expected_versions.contains(&server_version) {
148 return Err($crate::client_sync::error::UnexpectedServerVersionError {
149 got: server_version,
150 expected: $expected_versions.to_vec(),
151 })?;
152 }
153 Ok(())
154 }
155 }
156 };
157}
158
159fn into_json<T>(val: T) -> Result<serde_json::Value>
161where
162 T: serde::ser::Serialize,
163{
164 Ok(serde_json::to_value(val)?)
165}
166
167fn log_response(method: &str, resp: &Result<jsonrpc::Response>) {
169 use log::Level::{Debug, Trace, Warn};
170
171 if log::log_enabled!(Warn) || log::log_enabled!(Debug) || log::log_enabled!(Trace) {
172 match resp {
173 Err(ref e) =>
174 if log::log_enabled!(Debug) {
175 log::debug!(target: "corepc", "error: {}: {:?}", method, e);
176 },
177 Ok(ref resp) =>
178 if let Some(ref e) = resp.error {
179 if log::log_enabled!(Debug) {
180 log::debug!(target: "corepc", "response error for {}: {:?}", method, e);
181 }
182 } else if log::log_enabled!(Trace) {
183 let def =
184 serde_json::value::to_raw_value(&serde_json::value::Value::Null).unwrap();
185 let result = resp.result.as_ref().unwrap_or(&def);
186 log::trace!(target: "corepc", "response for {}: {}", method, result);
187 },
188 }
189 }
190}