diff --git a/Cargo.lock b/Cargo.lock index cf6dbf34..eac5f31f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,28 +166,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -[[package]] -name = "async-socks5" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575663f6d00adcfc4289d3f0825f49856380e062c030e799a2f9f4a275d842d6" -dependencies = [ - "async-trait", - "thiserror", - "tokio", -] - -[[package]] -name = "async-trait" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a265e3abeffdce30b2e26b7a11b222fe37c6067404001b434101457d0385eb92" -dependencies = [ - "proc-macro2 1.0.19", - "quote 1.0.7", - "syn 1.0.38", -] - [[package]] name = "atty" version = "0.2.14" @@ -442,6 +420,16 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +dependencies = [ + "byteorder", + "iovec", +] + [[package]] name = "bytes" version = "0.5.6" @@ -915,6 +903,15 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "encoding_rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "enum_primitive" version = "0.1.1" @@ -1186,7 +1183,7 @@ name = "grin_api" version = "5.1.0-alpha.1" source = "git+https://github.com/mimblewimble/grin?branch=master#f6ec77a592de04fcc4a78127822932ec7e18525c" dependencies = [ - "bytes", + "bytes 0.5.6", "easy-jsonrpc-mw", "failure", "failure_derive", @@ -1199,18 +1196,18 @@ dependencies = [ "grin_util", "http", "hyper", - "hyper-rustls", + "hyper-rustls 0.20.0", "hyper-timeout", "lazy_static", "log", "regex", "ring", - "rustls", + "rustls 0.17.0", "serde", "serde_derive", "serde_json", "tokio", - "tokio-rustls", + "tokio-rustls 0.13.1", "url", ] @@ -1245,7 +1242,7 @@ source = "git+https://github.com/mimblewimble/grin?branch=master#f6ec77a592de04f dependencies = [ "blake2-rfc", "byteorder", - "bytes", + "bytes 0.5.6", "chrono", "croaring", "enum_primitive", @@ -1293,7 +1290,7 @@ version = "5.1.0-alpha.1" source = "git+https://github.com/mimblewimble/grin?branch=master#f6ec77a592de04fcc4a78127822932ec7e18525c" dependencies = [ "bitflags 1.2.1", - "bytes", + "bytes 0.5.6", "chrono", "enum_primitive", "grin_chain", @@ -1496,16 +1493,12 @@ dependencies = [ "grin_wallet_config", "grin_wallet_libwallet", "grin_wallet_util", - "http", - "hyper", - "hyper-rustls", - "hyper-socks2-mw", - "hyper-timeout", "lazy_static", "log", "rand 0.6.5", "regex", "remove_dir_all 0.7.0", + "reqwest", "ring", "serde", "serde_derive", @@ -1574,7 +1567,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "futures-sink", @@ -1650,7 +1643,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "itoa", ] @@ -1661,7 +1654,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ - "bytes", + "bytes 0.5.6", "http", ] @@ -1692,7 +1685,7 @@ version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-channel", "futures-core", "futures-util", @@ -1716,31 +1709,32 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac965ea399ec3a25ac7d13b8affd4b8f39325cca00858ddf5eb29b79e6b14b08" dependencies = [ - "bytes", + "bytes 0.5.6", "ct-logs", "futures-util", "hyper", "log", - "rustls", + "rustls 0.17.0", "rustls-native-certs", "tokio", - "tokio-rustls", + "tokio-rustls 0.13.1", "webpki", ] [[package]] -name = "hyper-socks2-mw" -version = "0.4.4" +name = "hyper-rustls" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7267805b50714db2ebe2904b1e70158ba6ba8eafdaf7c9d7735aca3273c4f8" +checksum = "37743cc83e8ee85eacfce90f2f4102030d9ff0a95244098d781e9bee4a90abb6" dependencies = [ - "async-socks5", - "futures 0.3.5", - "http", + "bytes 0.5.6", + "futures-util", "hyper", - "hyper-tls", - "thiserror", + "log", + "rustls 0.18.1", "tokio", + "tokio-rustls 0.14.1", + "webpki", ] [[package]] @@ -1749,7 +1743,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d1f9b0b8258e3ef8f45928021d3ef14096c2b93b99e4b8cfcabf1f58ec84b0a" dependencies = [ - "bytes", + "bytes 0.5.6", "hyper", "tokio", "tokio-io-timeout", @@ -1761,7 +1755,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" dependencies = [ - "bytes", + "bytes 0.5.6", "hyper", "native-tls", "tokio", @@ -1798,6 +1792,12 @@ dependencies = [ "libc", ] +[[package]] +name = "ipnet" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" + [[package]] name = "itoa" version = "0.4.6" @@ -2045,6 +2045,22 @@ dependencies = [ "autocfg 1.0.0", ] +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.4.0" @@ -2886,6 +2902,46 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "reqwest" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9eaa17ac5d7b838b7503d118fa16ad88f440498bf9ffe5424e621f93190d61e" +dependencies = [ + "base64 0.12.3", + "bytes 0.5.6", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-rustls 0.21.0", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "mime_guess", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls 0.18.1", + "serde", + "serde_urlencoded", + "tokio", + "tokio-rustls 0.14.1", + "tokio-socks", + "tokio-tls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + [[package]] name = "ring" version = "0.16.15" @@ -2965,6 +3021,19 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" +dependencies = [ + "base64 0.12.3", + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "rustls-native-certs" version = "0.3.0" @@ -2972,7 +3041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75ffeb84a6bd9d014713119542ce415db3a3e4748f0bfce1e1416cd224a23a5" dependencies = [ "openssl-probe", - "rustls", + "rustls 0.17.0", "schannel", "security-framework", ] @@ -3154,6 +3223,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" +dependencies = [ + "dtoa", + "itoa", + "serde", + "url", +] + [[package]] name = "serde_yaml" version = "0.8.14" @@ -3525,7 +3606,7 @@ version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "iovec", @@ -3549,7 +3630,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9390a43272c8a6ac912ed1d1e2b6abeafd5047e05530a2fa304deee041a06215" dependencies = [ - "bytes", + "bytes 0.5.6", "tokio", ] @@ -3571,11 +3652,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15cb62a0d2770787abc96e99c1cd98fcf17f94959f3af63ca85bdfb203f051b4" dependencies = [ "futures-core", - "rustls", + "rustls 0.17.0", "tokio", "webpki", ] +[[package]] +name = "tokio-rustls" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" +dependencies = [ + "futures-core", + "rustls 0.18.1", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-socks" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1997788a0e25e09300e44680ba1ef9d44d6f634a883641f80109e8b59c928daf" +dependencies = [ + "bytes 0.4.12", + "either", + "futures 0.3.5", + "thiserror", + "tokio", +] + [[package]] name = "tokio-tls" version = "0.3.1" @@ -3592,7 +3698,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-core", "futures-sink", "log", @@ -3662,6 +3768,15 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -3814,6 +3929,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" dependencies = [ "cfg-if 0.1.10", + "serde", + "serde_json", "wasm-bindgen-macro", ] @@ -3832,6 +3949,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" +dependencies = [ + "cfg-if 0.1.10", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.67" @@ -3881,6 +4010,15 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki-roots" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eff4b7516a57307f9349c64bf34caa34b940b66fed4b2fb3136cb7386e5739" +dependencies = [ + "webpki", +] + [[package]] name = "which" version = "3.1.1" @@ -3933,6 +4071,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" diff --git a/api/src/foreign.rs b/api/src/foreign.rs index af81ae53..813f35dc 100644 --- a/api/src/foreign.rs +++ b/api/src/foreign.rs @@ -139,7 +139,7 @@ where /// /// // A NodeClient must first be created to handle communication between /// // the wallet and the node. - /// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); + /// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap(); /// /// // impls::DefaultWalletImpl is provided for convenience in instantiating the wallet /// // It contains the LMDBBackend, DefaultLCProvider (lifecycle) and ExtKeychain used @@ -494,7 +494,8 @@ macro_rules! doctest_helper_setup_doc_env_foreign { wallet_config.data_file_dir = dir.to_owned(); let pw = ZeroingString::from(""); - let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); + let node_client = + HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap(); let mut wallet = Box::new( DefaultWalletImpl::<'static, HTTPNodeClient>::new(node_client.clone()).unwrap(), ) diff --git a/api/src/owner.rs b/api/src/owner.rs index 92b6680d..bf1710dd 100644 --- a/api/src/owner.rs +++ b/api/src/owner.rs @@ -141,7 +141,7 @@ where /// /// // A NodeClient must first be created to handle communication between /// // the wallet and the node. - /// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); + /// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap(); /// /// // impls::DefaultWalletImpl is provided for convenience in instantiating the wallet /// // It contains the LMDBBackend, DefaultLCProvider (lifecycle) and ExtKeychain used @@ -2451,7 +2451,8 @@ macro_rules! doctest_helper_setup_doc_env { wallet_config.data_file_dir = dir.to_owned(); let pw = ZeroingString::from(""); - let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); + let node_client = + HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap(); let mut wallet = Box::new( DefaultWalletImpl::<'static, HTTPNodeClient>::new(node_client.clone()).unwrap(), ) diff --git a/impls/Cargo.toml b/impls/Cargo.toml index 28a940cd..62d650b7 100644 --- a/impls/Cargo.toml +++ b/impls/Cargo.toml @@ -20,20 +20,14 @@ serde_derive = "1" serde_json = "1" log = "0.4" ring = "0.16" -tokio = { version = "0.2", features = ["full"] } uuid = { version = "0.8", features = ["serde", "v4"] } chrono = { version = "0.4.11", features = ["serde"] } -lazy_static = "1.4" - -#http client (copied from grin) -http = "0.2" -hyper-rustls = "0.20" -hyper-timeout = "0.3" +lazy_static = "1" +tokio = { version = "0.2", features = ["full"] } +reqwest = { version = "0.10", features = ["rustls-tls", "socks"] } #Socks/Tor byteorder = "1" -hyper = "0.13" -hyper-socks2-mw = "0.4" ed25519-dalek = "1.0.0-pre.4" x25519-dalek = "0.6" data-encoding = "2" diff --git a/impls/src/adapters/http.rs b/impls/src/adapters/http.rs index 29ca3477..7d9f360d 100644 --- a/impls/src/adapters/http.rs +++ b/impls/src/adapters/http.rs @@ -13,7 +13,7 @@ // limitations under the License. /// HTTP Wallet 'plugin' implementation -use crate::client_utils::{Client, ClientError}; +use crate::client_utils::{Client, ClientError, ClientErrorKind}; use crate::libwallet::slate_versions::{SlateVersion, VersionedSlate}; use crate::libwallet::{Error, ErrorKind, Slate}; use crate::SlateSender; @@ -163,11 +163,15 @@ impl HttpSlateSender { where IN: Serialize, { - let mut client = Client::new(); - if self.use_socks { - client.use_socks = true; - client.socks_proxy_addr = self.socks_proxy_addr; - } + let client = + if self.use_socks { + Client::new() + } else { + Client::with_socks_proxy(self.socks_proxy_addr.ok_or_else(|| { + ClientErrorKind::Internal("No socks proxy address set".into()) + })?) + } + .map_err(|_| ClientErrorKind::Internal("Unable to create http client".into()))?; let req = client.create_post_request(url, api_secret, &input)?; let res = client.send_request(req)?; Ok(res) diff --git a/impls/src/adapters/keybase.rs b/impls/src/adapters/keybase.rs index 5003d236..ba5084e8 100644 --- a/impls/src/adapters/keybase.rs +++ b/impls/src/adapters/keybase.rs @@ -345,7 +345,7 @@ impl SlateReceiver for KeybaseAllChannels { account: &str, node_api_secret: Option, ) -> Result<(), Error> { - let node_client = HTTPNodeClient::new(&config.check_node_api_http_addr, node_api_secret); + let node_client = HTTPNodeClient::new(&config.check_node_api_http_addr, node_api_secret)?; let mut wallet = Box::new(DefaultWalletImpl::<'static, HTTPNodeClient>::new(node_client).unwrap()) as Box< diff --git a/impls/src/client_utils/client.rs b/impls/src/client_utils/client.rs index bf41758a..bc4cb124 100644 --- a/impls/src/client_utils/client.rs +++ b/impls/src/client_utils/client.rs @@ -16,12 +16,9 @@ use crate::util::to_base64; use failure::{Backtrace, Context, Fail, ResultExt}; -use hyper::body; -use hyper::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE, USER_AGENT}; -use hyper::{self, Body, Client as HyperClient, Request, Uri}; -use hyper_rustls; -use hyper_timeout::TimeoutConnector; use lazy_static::lazy_static; +use reqwest::header::{HeaderMap, HeaderValue, ACCEPT, AUTHORIZATION, CONTENT_TYPE, USER_AGENT}; +use reqwest::{ClientBuilder, Method, Proxy, RequestBuilder}; use serde::{Deserialize, Serialize}; use serde_json; use std::fmt::{self, Display}; @@ -103,19 +100,41 @@ impl From> for Error { #[derive(Clone)] pub struct Client { - /// Whether to use socks proxy - pub use_socks: bool, - /// Proxy url/port - pub socks_proxy_addr: Option, + client: reqwest::Client, } impl Client { /// New client - pub fn new() -> Self { - Client { - use_socks: false, - socks_proxy_addr: None, + pub fn new() -> Result { + Self::build(None) + } + + pub fn with_socks_proxy(socks_proxy_addr: SocketAddr) -> Result { + Self::build(Some(socks_proxy_addr)) + } + + fn build(socks_proxy_addr: Option) -> Result { + let mut headers = HeaderMap::new(); + headers.insert(USER_AGENT, HeaderValue::from_static("grin-client")); + headers.insert(ACCEPT, HeaderValue::from_static("application/json")); + headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); + + let mut builder = ClientBuilder::new() + .timeout(Duration::from_secs(20)) + .use_rustls_tls() + .default_headers(headers); + + if let Some(s) = socks_proxy_addr { + let proxy = Proxy::all(&format!("socks5://{}:{}", s.ip(), s.port())) + .map_err(|e| ErrorKind::Internal(format!("Unable to create proxy: {}", e)))?; + builder = builder.proxy(proxy); } + + let client = builder + .build() + .map_err(|e| ErrorKind::Internal(format!("Unable to build client: {}", e)))?; + + Ok(Client { client }) } /// Helper function to easily issue a HTTP GET request against a given URL that @@ -125,7 +144,7 @@ impl Client { where for<'de> T: Deserialize<'de>, { - self.handle_request(self.build_request(url, "GET", api_secret, None)?) + self.handle_request(self.build_request(url, Method::GET, api_secret, None)?) } /// Helper function to easily issue an async HTTP GET request against a given @@ -139,7 +158,7 @@ impl Client { where for<'de> T: Deserialize<'de> + Send + 'static, { - self.handle_request_async(self.build_request(url, "GET", api_secret, None)?) + self.handle_request_async(self.build_request(url, Method::GET, api_secret, None)?) .await } @@ -147,7 +166,7 @@ impl Client { /// on a given URL that returns nothing. Handles request /// building and response code checking. pub fn _get_no_ret(&self, url: &str, api_secret: Option) -> Result<(), Error> { - let req = self.build_request(url, "GET", api_secret, None)?; + let req = self.build_request(url, Method::GET, api_secret, None)?; self.send_request(req)?; Ok(()) } @@ -228,32 +247,21 @@ impl Client { fn build_request( &self, url: &str, - method: &str, + method: Method, api_secret: Option, body: Option, - ) -> Result, Error> { - let uri: Uri = url - .parse() - .map_err(|_| ErrorKind::RequestError(format!("Invalid url {}", url)))?; - let mut builder = Request::builder(); + ) -> Result { + let mut builder = self.client.request(method, url); if let Some(api_secret) = api_secret { let basic_auth = format!("Basic {}", to_base64(&format!("grin:{}", api_secret))); builder = builder.header(AUTHORIZATION, basic_auth); } - builder - .method(method) - .uri(uri) - .header(USER_AGENT, "grin-client") - .header(ACCEPT, "application/json") - .header(CONTENT_TYPE, "application/json") - .body(match body { - None => Body::empty(), - Some(json) => json.into(), - }) - .map_err(|e| { - ErrorKind::RequestError(format!("Bad request {} {}: {}", method, url, e)).into() - }) + if let Some(body) = body { + builder = builder.body(body); + } + + Ok(builder) } pub fn create_post_request( @@ -261,17 +269,17 @@ impl Client { url: &str, api_secret: Option, input: &IN, - ) -> Result, Error> + ) -> Result where IN: Serialize, { let json = serde_json::to_string(input).context(ErrorKind::Internal( "Could not serialize data to JSON".to_owned(), ))?; - self.build_request(url, "POST", api_secret, Some(json)) + self.build_request(url, Method::POST, api_secret, Some(json)) } - fn handle_request(&self, req: Request) -> Result + fn handle_request(&self, req: RequestBuilder) -> Result where for<'de> T: Deserialize<'de>, { @@ -282,7 +290,7 @@ impl Client { }) } - async fn handle_request_async(&self, req: Request) -> Result + async fn handle_request_async(&self, req: RequestBuilder) -> Result where for<'de> T: Deserialize<'de> + Send + 'static, { @@ -292,54 +300,19 @@ impl Client { Ok(ser) } - async fn send_request_async(&self, req: Request) -> Result { - let resp = if !self.use_socks { - let https = hyper_rustls::HttpsConnector::new(); - let mut connector = TimeoutConnector::new(https); - connector.set_connect_timeout(Some(Duration::from_secs(20))); - connector.set_read_timeout(Some(Duration::from_secs(20))); - connector.set_write_timeout(Some(Duration::from_secs(20))); - let client = HyperClient::builder().build::<_, Body>(connector); - - client.request(req).await - } else { - let addr = self.socks_proxy_addr.ok_or_else(|| { - ErrorKind::RequestError("Missing Socks proxy address".to_string()) - })?; - let auth = format!("{}:{}", addr.ip(), addr.port()); - - let https = hyper_rustls::HttpsConnector::new(); - let socks = hyper_socks2_mw::SocksConnector { - proxy_addr: hyper::Uri::builder() - .scheme("socks5") - .authority(auth.as_str()) - .path_and_query("/") - .build() - .map_err(|_| { - ErrorKind::RequestError("Can't parse Socks proxy address".to_string()) - })?, - auth: None, - connector: https, - }; - let mut connector = TimeoutConnector::new(socks); - connector.set_connect_timeout(Some(Duration::from_secs(20))); - connector.set_read_timeout(Some(Duration::from_secs(20))); - connector.set_write_timeout(Some(Duration::from_secs(20))); - let client = HyperClient::builder().build::<_, Body>(connector); - - client.request(req).await - }; - let resp = - resp.map_err(|e| ErrorKind::RequestError(format!("Cannot make request: {}", e)))?; - - let raw = body::to_bytes(resp) + async fn send_request_async(&self, req: RequestBuilder) -> Result { + let resp = req + .send() .await - .map_err(|e| ErrorKind::RequestError(format!("Cannot read response body: {}", e)))?; - - Ok(String::from_utf8_lossy(&raw).to_string()) + .map_err(|e| ErrorKind::RequestError(format!("Cannot make request: {}", e)))?; + let text = resp + .text() + .await + .map_err(|e| ErrorKind::ResponseError(format!("Cannot parse response: {}", e)))?; + Ok(text) } - pub fn send_request(&self, req: Request) -> Result { + pub fn send_request(&self, req: RequestBuilder) -> Result { // This client is currently used both outside and inside of a tokio runtime // context. In the latter case we are not allowed to do a blocking call to // our global runtime, which unfortunately means we have to spawn a new thread diff --git a/impls/src/client_utils/json_rpc.rs b/impls/src/client_utils/json_rpc.rs index 98896997..06e4465d 100644 --- a/impls/src/client_utils/json_rpc.rs +++ b/impls/src/client_utils/json_rpc.rs @@ -16,7 +16,6 @@ //! JSON RPC Client functionality use std::{error, fmt}; -use hyper; use serde_json; /// Builds a request @@ -97,8 +96,6 @@ impl Response { pub enum Error { /// Json error Json(serde_json::Error), - /// Client error - Hyper(hyper::error::Error), /// Error response Rpc(RpcError), /// Response to a request did not have the expected nonce @@ -121,12 +118,6 @@ impl From for Error { } } -impl From for Error { - fn from(e: hyper::error::Error) -> Error { - Error::Hyper(e) - } -} - impl From for Error { fn from(e: RpcError) -> Error { Error::Rpc(e) @@ -137,7 +128,6 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Json(ref e) => write!(f, "JSON decode error: {}", e), - Error::Hyper(ref e) => write!(f, "Hyper error: {}", e), Error::Rpc(ref r) => write!(f, "RPC error response: {:?}", r), Error::_BatchDuplicateResponseId(ref v) => { write!(f, "duplicate RPC batch response ID: {}", v) @@ -152,7 +142,6 @@ impl std::error::Error for Error { fn description(&self) -> &str { match *self { Error::Json(_) => "JSON decode error", - Error::Hyper(_) => "Hyper error", Error::Rpc(_) => "RPC error response", Error::_NonceMismatch => "Nonce of response did not match nonce of request", Error::_VersionMismatch => "`jsonrpc` field set to non-\"2.0\"", @@ -168,7 +157,6 @@ impl std::error::Error for Error { fn cause(&self) -> Option<&dyn error::Error> { match *self { Error::Json(ref e) => Some(e), - Error::Hyper(ref e) => Some(e), _ => None, } } diff --git a/impls/src/client_utils/mod.rs b/impls/src/client_utils/mod.rs index 1e6777d0..78ed753b 100644 --- a/impls/src/client_utils/mod.rs +++ b/impls/src/client_utils/mod.rs @@ -15,4 +15,4 @@ mod client; pub mod json_rpc; -pub use client::{Client, Error as ClientError, RUNTIME}; +pub use client::{Client, Error as ClientError, ErrorKind as ClientErrorKind, RUNTIME}; diff --git a/impls/src/node_clients/http.rs b/impls/src/node_clients/http.rs index f6988a6e..6e383e81 100644 --- a/impls/src/node_clients/http.rs +++ b/impls/src/node_clients/http.rs @@ -21,7 +21,6 @@ use futures::stream::FuturesUnordered; use futures::TryStreamExt; use std::collections::HashMap; use std::env; -use tokio::runtime::Handle; use crate::client_utils::{Client, RUNTIME}; use crate::libwallet; @@ -35,6 +34,7 @@ const ENDPOINT: &str = "/v2/foreign"; #[derive(Clone)] pub struct HTTPNodeClient { + client: Client, node_url: String, node_api_secret: Option, node_version_info: Option, @@ -42,12 +42,16 @@ pub struct HTTPNodeClient { impl HTTPNodeClient { /// Create a new client that will communicate with the given grin node - pub fn new(node_url: &str, node_api_secret: Option) -> HTTPNodeClient { - HTTPNodeClient { + pub fn new( + node_url: &str, + node_api_secret: Option, + ) -> Result { + Ok(HTTPNodeClient { + client: Client::new().map_err(|_| libwallet::ErrorKind::Node)?, node_url: node_url.to_owned(), node_api_secret: node_api_secret, node_version_info: None, - } + }) } /// Allow returning the chain height without needing a wallet instantiated @@ -61,9 +65,10 @@ impl HTTPNodeClient { params: &serde_json::Value, ) -> Result { let url = format!("{}{}", self.node_url(), ENDPOINT); - let client = Client::new(); let req = build_request(method, params); - let res = client.post::(url.as_str(), self.node_api_secret(), &req); + let res = self + .client + .post::(url.as_str(), self.node_api_secret(), &req); match res { Err(e) => { @@ -156,9 +161,10 @@ impl NodeClient for HTTPNodeClient { let params = json!([excess.0.as_ref().to_hex(), min_height, max_height]); // have to handle this manually since the error needs to be parsed let url = format!("{}{}", self.node_url(), ENDPOINT); - let client = Client::new(); let req = build_request(method, ¶ms); - let res = client.post::(url.as_str(), self.node_api_secret(), &req); + let res = self + .client + .post::(url.as_str(), self.node_api_secret(), &req); match res { Err(e) => { @@ -225,8 +231,6 @@ impl NodeClient for HTTPNodeClient { let url = format!("{}{}", self.node_url(), ENDPOINT); let api_secret = self.node_api_secret(); let task = async move { - let client = Client::new(); - let params: Vec<_> = query_params .chunks(chunk_size) .map(|c| json!([c, null, null, false, false])) @@ -239,7 +243,7 @@ impl NodeClient for HTTPNodeClient { let mut tasks = Vec::with_capacity(params.len()); for req in &reqs { - tasks.push(client.post_async::( + tasks.push(self.client.post_async::( url.as_str(), req, api_secret.clone(), @@ -250,14 +254,7 @@ impl NodeClient for HTTPNodeClient { task.try_collect().await }; - let res: Result, _> = if Handle::try_current().is_ok() { - let rt = RUNTIME.clone(); - std::thread::spawn(move || rt.lock().unwrap().block_on(task)) - .join() - .unwrap() - } else { - RUNTIME.lock().unwrap().block_on(task) - }; + let res: Result, _> = RUNTIME.lock().unwrap().block_on(task); let results: Vec = match res { Ok(resps) => { diff --git a/src/bin/grin-wallet.rs b/src/bin/grin-wallet.rs index 7f870d0f..712285b5 100644 --- a/src/bin/grin-wallet.rs +++ b/src/bin/grin-wallet.rs @@ -156,7 +156,7 @@ fn real_main() -> i32 { global::init_global_accept_fee_base(config.members.as_ref().unwrap().wallet.accept_fee_base()); let wallet_config = config.clone().members.unwrap().wallet; - let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None); + let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap(); cmd::wallet_command(&args, config, node_client) }