Skip to content
This repository was archived by the owner on Sep 4, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ pub trait Transport: Send + Sync + 'static {

/// A JSON-RPC client.
///
/// Create a new Client using one of the transport-specific constructors:
/// - [Client::simple_http] for the built-in bare-minimum HTTP transport
/// Create a new Client using one of the transport-specific constructors e.g.,
/// [`Client::simple_http`] for a bare-minimum HTTP transport.
pub struct Client {
pub(crate) transport: Box<dyn Transport>,
nonce: atomic::AtomicUsize,
Expand Down Expand Up @@ -74,16 +74,20 @@ impl Client {
}
}

/// Sends a request to a client
/// Sends a request to a client.
pub fn send_request(&self, request: Request) -> Result<Response, Error> {
self.transport.send_request(request)
}

/// Sends a batch of requests to the client. The return vector holds the response
/// for the request at the corresponding index. If no response was provided, it's [None].
/// Sends a batch of requests to the client.
///
/// Note that the requests need to have valid IDs, so it is advised to create the requests
/// with [`Client::build_request`].
///
/// # Returns
///
/// The return vector holds the response for the request at the corresponding index. If no
/// response was provided, it's [`None`].
pub fn send_batch(&self, requests: &[Request]) -> Result<Vec<Option<Response>>, Error> {
if requests.is_empty() {
return Err(Error::EmptyBatch);
Expand Down
35 changes: 18 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,16 @@ pub use crate::error::Error;

use serde_json::value::RawValue;

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
/// Since serializers rarely fail, it's probably easier to use [arg] instead.
/// Shorthand method to convert an argument into a boxed [`serde_json::value::RawValue`].
///
/// Since serializers rarely fail, it's probably easier to use [`arg`] instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just arg, no? It's not a identifier so it can't be a link.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is correct, arg is a function as well. This threw me too, perhaps we should change the paramater identifier to not be arg?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooooooooohhhh. :D

pub fn try_arg<T: serde::Serialize>(arg: T) -> Result<Box<RawValue>, serde_json::Error> {
RawValue::from_string(serde_json::to_string(&arg)?)
}

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
/// Shorthand method to convert an argument into a boxed [`serde_json::value::RawValue`].
///
/// This conversion should not fail, so to avoid returning a [Result],
/// This conversion should not fail, so to avoid returning a [`Result`],
/// in case of an error, the error is serialized as the return value.
pub fn arg<T: serde::Serialize>(arg: T) -> Box<RawValue> {
match try_arg(arg) {
Expand All @@ -72,33 +73,33 @@ pub fn arg<T: serde::Serialize>(arg: T) -> Box<RawValue> {
}

#[derive(Debug, Clone, Serialize)]
/// A JSONRPC request object
/// A JSONRPC request object.
pub struct Request<'a> {
/// The name of the RPC call
/// The name of the RPC call.
pub method: &'a str,
/// Parameters to the RPC call
/// Parameters to the RPC call.
pub params: &'a [Box<RawValue>],
/// Identifier for this Request, which should appear in the response
/// Identifier for this Request, which should appear in the response.
pub id: serde_json::Value,
/// jsonrpc field, MUST be "2.0"
/// jsonrpc field, MUST be "2.0".
pub jsonrpc: Option<&'a str>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
/// A JSONRPC response object
/// A JSONRPC response object.
pub struct Response {
/// A result if there is one, or null
/// A result if there is one, or [`None`].
pub result: Option<Box<RawValue>>,
/// An error if there is one, or null
/// An error if there is one, or [`None`].
pub error: Option<error::RpcError>,
/// Identifier for this Request, which should match that of the request
/// Identifier for this Request, which should match that of the request.
pub id: serde_json::Value,
/// jsonrpc field, MUST be "2.0"
/// jsonrpc field, MUST be "2.0".
pub jsonrpc: Option<String>,
}

impl Response {
/// Extract the result from a response
/// Extracts the result from a response.
pub fn result<T: for<'a> serde::de::Deserialize<'a>>(&self) -> Result<T, Error> {
if let Some(ref e) = self.error {
return Err(Error::Rpc(e.clone()));
Expand All @@ -111,7 +112,7 @@ impl Response {
}
}

/// Return the RPC error, if there was one, but do not check the result
/// Returns the RPC error, if there was one, but does not check the result.
pub fn check_error(self) -> Result<(), Error> {
if let Some(e) = self.error {
Err(Error::Rpc(e))
Expand All @@ -120,7 +121,7 @@ impl Response {
}
}

/// Returns whether or not the `result` field is empty
/// Returns whether or not the `result` field is empty.
pub fn is_none(&self) -> bool {
self.result.is_none()
}
Expand Down
45 changes: 23 additions & 22 deletions src/simple_http.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This module implements a minimal and non standard conforming HTTP 1.0
//! round-tripper that works with the bitcoind RPC server. This can be used
//! if minimal dependencies are a goal and synchronous communication is ok.
//!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this so every file has the same comment layout. This is copied from rust-bitcoin where I also did it to make everything uniform - pretty anal I know. I did these docs fixes in preparation for bring this repo into the rust-bitcoin org.


#[cfg(feature = "proxy")]
use socks::Socks5Stream;
Expand Down Expand Up @@ -64,12 +65,12 @@ impl Default for SimpleHttpTransport {
}

impl SimpleHttpTransport {
/// Construct a new `SimpleHttpTransport` with default parameters
/// Constructs a new [`SimpleHttpTransport`] with default parameters.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imperative mood is idiomatic, AFAIK.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I certainly hope not, I've been changing everything to third person for the last 10 months in rust-bitcoin :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my...

... I just checked stdlib ... and indeed ...

... I've been living a lie.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

pub fn new() -> Self {
SimpleHttpTransport::default()
}

/// Returns a builder for `SimpleHttpTransport`
/// Returns a builder for [`SimpleHttpTransport`].
pub fn builder() -> Builder {
Builder::new()
}
Expand Down Expand Up @@ -209,7 +210,7 @@ impl SimpleHttpTransport {
}
}

/// Error that can happen when sending requests
/// Error that can happen when sending requests.
#[derive(Debug)]
pub enum Error {
/// An invalid URL was passed.
Expand All @@ -219,20 +220,20 @@ pub enum Error {
/// The reason the URL is invalid.
reason: &'static str,
},
/// An error occurred on the socket layer
/// An error occurred on the socket layer.
SocketError(io::Error),
/// The HTTP header of the response couldn't be parsed
/// The HTTP header of the response couldn't be parsed.
HttpParseError,
/// Unexpected HTTP error code (non-200)
/// Unexpected HTTP error code (non-200).
HttpErrorCode(u16),
/// We didn't receive a complete response till the deadline ran out
/// We didn't receive a complete response till the deadline ran out.
Timeout,
/// JSON parsing error.
Json(serde_json::Error),
}

impl Error {
/// Utility method to create [Error::InvalidUrl] variants.
/// Utility method to create [`Error::InvalidUrl`] variants.
fn url<U: Into<String>>(url: U, reason: &'static str) -> Error {
Error::InvalidUrl {
url: url.into(),
Expand Down Expand Up @@ -295,8 +296,8 @@ impl From<Error> for crate::Error {
}
}

/// Try to read a line from a buffered reader. If no line can be read till the deadline is reached
/// return a timeout error.
/// Tries to read a line from a buffered reader. If no line can be read till the deadline is reached
/// returns a timeout error.
fn get_line<R: BufRead>(reader: &mut R, deadline: Instant) -> Result<String, Error> {
let mut line = String::new();
while deadline > Instant::now() {
Expand All @@ -312,7 +313,7 @@ fn get_line<R: BufRead>(reader: &mut R, deadline: Instant) -> Result<String, Err
Err(Error::Timeout)
}

/// Do some very basic manual URL parsing because the uri/url crates
/// Does some very basic manual URL parsing because the uri/url crates
/// all have unicode-normalization as a dependency and that's broken.
fn check_url(url: &str) -> Result<(SocketAddr, String), Error> {
// The fallback port in case no port was provided.
Expand Down Expand Up @@ -385,35 +386,35 @@ impl Transport for SimpleHttpTransport {
}
}

/// Builder for simple bitcoind `SimpleHttpTransport`s
/// Builder for simple bitcoind [`SimpleHttpTransport`].
#[derive(Clone, Debug)]
pub struct Builder {
tp: SimpleHttpTransport,
}

impl Builder {
/// Construct new `Builder` with default configuration
/// Constructs a new [`Builder`] with default configuration.
pub fn new() -> Builder {
Builder {
tp: SimpleHttpTransport::new(),
}
}

/// Sets the timeout after which requests will abort if they aren't finished
/// Sets the timeout after which requests will abort if they aren't finished.
pub fn timeout(mut self, timeout: Duration) -> Self {
self.tp.timeout = timeout;
self
}

/// Set the URL of the server to the transport.
/// Sets the URL of the server to the transport.
pub fn url(mut self, url: &str) -> Result<Self, Error> {
let url = check_url(url)?;
self.tp.addr = url.0;
self.tp.path = url.1;
Ok(self)
}

/// Add authentication information to the transport.
/// Adds authentication information to the transport.
pub fn auth<S: AsRef<str>>(mut self, user: S, pass: Option<S>) -> Self {
let mut auth = user.as_ref().to_owned();
auth.push(':');
Expand All @@ -424,29 +425,29 @@ impl Builder {
self
}

/// Add authentication information to the transport using a cookie string ('user:pass')
/// Adds authentication information to the transport using a cookie string ('user:pass').
pub fn cookie_auth<S: AsRef<str>>(mut self, cookie: S) -> Self {
self.tp.basic_auth = Some(format!("Basic {}", &base64::encode(cookie.as_ref().as_bytes())));
self
}

#[cfg(feature = "proxy")]
/// Add proxy address to the transport for SOCKS5 proxy
/// Adds proxy address to the transport for SOCKS5 proxy.
pub fn proxy_addr<S: AsRef<str>>(mut self, proxy_addr: S) -> Result<Self, Error> {
// We don't expect path in proxy address.
self.tp.proxy_addr = check_url(proxy_addr.as_ref())?.0;
Ok(self)
}

#[cfg(feature = "proxy")]
/// Add optional proxy authentication as ('username', 'password')
/// Adds optional proxy authentication as ('username', 'password').
pub fn proxy_auth<S: AsRef<str>>(mut self, user: S, pass: S) -> Self {
self.tp.proxy_auth =
Some((user, pass)).map(|(u, p)| (u.as_ref().to_string(), p.as_ref().to_string()));
self
}

/// Builds the final `SimpleHttpTransport`
/// Builds the final [`SimpleHttpTransport`].
pub fn build(self) -> SimpleHttpTransport {
self.tp
}
Expand All @@ -459,7 +460,7 @@ impl Default for Builder {
}

impl crate::Client {
/// Create a new JSON-RPC client using a bare-minimum HTTP transport.
/// Creates a new JSON-RPC client using a bare-minimum HTTP transport.
pub fn simple_http(
url: &str,
user: Option<String>,
Expand All @@ -473,7 +474,7 @@ impl crate::Client {
}

#[cfg(feature = "proxy")]
/// Create a new JSON_RPC client using a HTTP-Socks5 proxy transport.
/// Creates a new JSON_RPC client using a HTTP-Socks5 proxy transport.
pub fn http_proxy(
url: &str,
user: Option<String>,
Expand Down
11 changes: 6 additions & 5 deletions src/simple_tcp.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! This module implements a synchronous transport over a raw TcpListener. Note that
//! it does not handle TCP over Unix Domain Sockets, see `simple_uds` for this.
//!

use std::{error, fmt, io, net, time};

Expand All @@ -12,9 +13,9 @@ use crate::{Request, Response};
/// Error that can occur while using the TCP transport.
#[derive(Debug)]
pub enum Error {
/// An error occurred on the socket layer
/// An error occurred on the socket layer.
SocketError(io::Error),
/// We didn't receive a complete response till the deadline ran out
/// We didn't receive a complete response till the deadline ran out.
Timeout,
/// JSON parsing error.
Json(serde_json::Error),
Expand Down Expand Up @@ -66,14 +67,14 @@ impl From<Error> for crate::Error {
/// Simple synchronous TCP transport.
#[derive(Debug, Clone)]
pub struct TcpTransport {
/// The internet socket address to connect to
/// The internet socket address to connect to.
pub addr: net::SocketAddr,
/// The read and write timeout to use for this connection
/// The read and write timeout to use for this connection.
pub timeout: Option<time::Duration>,
}

impl TcpTransport {
/// Create a new TcpTransport without timeouts
/// Creates a new TcpTransport without timeouts.
pub fn new(addr: net::SocketAddr) -> TcpTransport {
TcpTransport {
addr,
Expand Down
11 changes: 6 additions & 5 deletions src/simple_uds.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! This module implements a synchronous transport over a raw TcpListener.
//!

use std::os::unix::net::UnixStream;
use std::{error, fmt, io, path, time};
Expand All @@ -12,9 +13,9 @@ use crate::{Request, Response};
/// Error that can occur while using the UDS transport.
#[derive(Debug)]
pub enum Error {
/// An error occurred on the socket layer
/// An error occurred on the socket layer.
SocketError(io::Error),
/// We didn't receive a complete response till the deadline ran out
/// We didn't receive a complete response till the deadline ran out.
Timeout,
/// JSON parsing error.
Json(serde_json::Error),
Expand Down Expand Up @@ -66,14 +67,14 @@ impl From<Error> for crate::error::Error {
/// Simple synchronous UDS transport.
#[derive(Debug, Clone)]
pub struct UdsTransport {
/// The path to the Unix Domain Socket
/// The path to the Unix Domain Socket.
pub sockpath: path::PathBuf,
/// The read and write timeout to use
/// The read and write timeout to use.
pub timeout: Option<time::Duration>,
}

impl UdsTransport {
/// Create a new UdsTransport without timeouts to use
/// Creates a new [`UdsTransport`] without timeouts to use.
pub fn new<P: AsRef<path::Path>>(sockpath: P) -> UdsTransport {
UdsTransport {
sockpath: sockpath.as_ref().to_path_buf(),
Expand Down
4 changes: 2 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use std::hash::{Hash, Hasher};

use serde_json::Value;

/// Newtype around `Value` which allows hashing for use as hashmap keys
/// This is needed for batch requests.
/// Newtype around `Value` which allows hashing for use as hashmap keys,
/// this is needed for batch requests.
///
/// The reason `Value` does not support `Hash` or `Eq` by itself
/// is that it supports `f64` values; but for batch requests we
Expand Down