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;
19
20use std::fs::File;
21use std::io::{BufRead, BufReader};
22use std::path::PathBuf;
23
24pub use crate::client_sync::error::Error;
25
26pub type Result<T> = std::result::Result<T, Error>;
30
31#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
33pub enum Auth {
34 None,
35 UserPass(String, String),
36 CookieFile(PathBuf),
37}
38
39impl Auth {
40 pub fn get_user_pass(self) -> Result<(Option<String>, Option<String>)> {
42 match self {
43 Auth::None => Ok((None, None)),
44 Auth::UserPass(u, p) => Ok((Some(u), Some(p))),
45 Auth::CookieFile(path) => {
46 let line = BufReader::new(File::open(path)?)
47 .lines()
48 .next()
49 .ok_or(Error::InvalidCookieFile)??;
50 let colon = line.find(':').ok_or(Error::InvalidCookieFile)?;
51 Ok((Some(line[..colon].into()), Some(line[colon + 1..].into())))
52 }
53 }
54 }
55}
56
57#[macro_export]
59macro_rules! define_jsonrpc_minreq_client {
60 ($version:literal) => {
61 use std::fmt;
62
63 use $crate::client_sync::{log_response, Auth, Result};
64 use $crate::client_sync::error::Error;
65
66 pub struct Client {
68 inner: jsonrpc::client::Client,
69 }
70
71 impl fmt::Debug for Client {
72 fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
73 write!(
74 f,
75 "corepc_client::client_sync::{}::Client({:?})", $version, self.inner
76 )
77 }
78 }
79
80 impl Client {
81 pub fn new(url: &str) -> Self {
83 let transport = jsonrpc::http::minreq_http::Builder::new()
84 .url(url)
85 .expect("jsonrpc v0.18, this function does not error")
86 .build();
87 let inner = jsonrpc::client::Client::with_transport(transport);
88
89 Self { inner }
90 }
91
92 pub fn new_with_auth(url: &str, auth: Auth) -> Result<Self> {
94 if matches!(auth, Auth::None) {
95 return Err(Error::MissingUserPassword);
96 }
97 let (user, pass) = auth.get_user_pass()?;
98
99 let transport = jsonrpc::http::minreq_http::Builder::new()
100 .url(url)
101 .expect("jsonrpc v0.18, this function does not error")
102 .basic_auth(user.unwrap(), pass)
103 .build();
104 let inner = jsonrpc::client::Client::with_transport(transport);
105
106 Ok(Self { inner })
107 }
108
109 pub fn call<T: for<'a> serde::de::Deserialize<'a>>(
111 &self,
112 method: &str,
113 args: &[serde_json::Value],
114 ) -> Result<T> {
115 let raw = serde_json::value::to_raw_value(args)?;
116 let req = self.inner.build_request(&method, Some(&*raw));
117 if log::log_enabled!(log::Level::Debug) {
118 log::debug!(target: "corepc", "request: {} {}", method, serde_json::Value::from(args));
119 }
120
121 let resp = self.inner.send_request(req).map_err(Error::from);
122 log_response(method, &resp);
123 Ok(resp?.result()?)
124 }
125 }
126 }
127}
128
129#[macro_export]
138macro_rules! impl_client_check_expected_server_version {
139 ($expected_versions:expr) => {
140 impl Client {
141 pub fn check_expected_server_version(&self) -> Result<()> {
143 let server_version = self.server_version()?;
144 if !$expected_versions.contains(&server_version) {
145 return Err($crate::client_sync::error::UnexpectedServerVersionError {
146 got: server_version,
147 expected: $expected_versions.to_vec(),
148 })?;
149 }
150 Ok(())
151 }
152 }
153 };
154}
155
156fn into_json<T>(val: T) -> Result<serde_json::Value>
158where
159 T: serde::ser::Serialize,
160{
161 Ok(serde_json::to_value(val)?)
162}
163
164#[allow(dead_code)] fn opt_into_json<T>(opt: Option<T>) -> Result<serde_json::Value>
167where
168 T: serde::ser::Serialize,
169{
170 match opt {
171 Some(val) => Ok(into_json(val)?),
172 None => Ok(serde_json::Value::Null),
173 }
174}
175
176#[allow(dead_code)] fn null() -> serde_json::Value { serde_json::Value::Null }
179
180#[allow(dead_code)] fn empty_arr() -> serde_json::Value { serde_json::Value::Array(vec![]) }
183
184#[allow(dead_code)] fn empty_obj() -> serde_json::Value { serde_json::Value::Object(Default::default()) }
187
188#[allow(dead_code)] fn opt_result<T: for<'a> serde::de::Deserialize<'a>>(
191 result: serde_json::Value,
192) -> Result<Option<T>> {
193 if result == serde_json::Value::Null {
194 Ok(None)
195 } else {
196 Ok(serde_json::from_value(result)?)
197 }
198}
199
200fn log_response(method: &str, resp: &Result<jsonrpc::Response>) {
202 use log::Level::{Debug, Trace, Warn};
203
204 if log::log_enabled!(Warn) || log::log_enabled!(Debug) || log::log_enabled!(Trace) {
205 match resp {
206 Err(ref e) =>
207 if log::log_enabled!(Debug) {
208 log::debug!(target: "corepc", "error: {}: {:?}", method, e);
209 },
210 Ok(ref resp) =>
211 if let Some(ref e) = resp.error {
212 if log::log_enabled!(Debug) {
213 log::debug!(target: "corepc", "response error for {}: {:?}", method, e);
214 }
215 } else if log::log_enabled!(Trace) {
216 let def =
217 serde_json::value::to_raw_value(&serde_json::value::Value::Null).unwrap();
218 let result = resp.result.as_ref().unwrap_or(&def);
219 log::trace!(target: "corepc", "response for {}: {}", method, result);
220 },
221 }
222 }
223}