diff --git a/Cargo.lock b/Cargo.lock index 4de1a43..f355490 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,14 +137,14 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arangors" -version = "0.5.4" +version = "0.5.5" dependencies = [ "anyhow", "async-std", "async-trait", "base64 0.22.1", "env_logger", - "http", + "http 1.1.0", "http-types", "log", "maybe-async", @@ -159,7 +159,6 @@ dependencies = [ "thiserror", "tokio", "typed-builder", - "uclient", "url", ] @@ -379,12 +378,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -767,6 +760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -841,6 +835,7 @@ dependencies = [ "futures-core", "futures-io", "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -910,16 +905,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes 1.6.0", "fnv", "futures-core", "futures-sink", - "futures-util", - "http", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -970,14 +965,37 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes 1.6.0", + "fnv", + "itoa", +] + [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes 1.6.0", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ "bytes 1.6.0", - "http", + "futures-core", + "http 1.1.0", + "http-body", "pin-project-lite", ] @@ -1023,12 +1041,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "humantime" version = "2.1.0" @@ -1037,53 +1049,58 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.29" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes 1.6.0", "futures-channel", - "futures-core", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.7", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] -name = "hyper-rustls" -version = "0.24.2" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "futures-util", - "http", + "bytes 1.6.0", + "http-body-util", "hyper", - "rustls", + "hyper-util", + "native-tls", "tokio", - "tokio-rustls", + "tokio-native-tls", + "tower-service", ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-util" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes 1.6.0", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body", "hyper", - "native-tls", + "pin-project-lite", + "socket2 0.5.7", "tokio", - "tokio-native-tls", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1156,7 +1173,7 @@ dependencies = [ "curl-sys", "flume", "futures-lite 1.13.0", - "http", + "http 0.2.12", "log", "once_cell", "slab", @@ -1640,22 +1657,24 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" dependencies = [ "async-compression", - "base64 0.21.7", + "base64 0.22.1", "bytes 1.6.0", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", + "http-body-util", "hyper", - "hyper-rustls", "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", @@ -1664,7 +1683,6 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", "rustls-pemfile", "serde", "serde_json", @@ -1673,32 +1691,15 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls", "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", "winreg", ] -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.15", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1741,36 +1742,21 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - [[package]] name = "rustls-pemfile" -version = "1.0.4" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", + "rustls-pki-types", ] [[package]] -name = "rustls-webpki" -version = "0.101.7" +name = "rustls-pki-types" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "ryu" @@ -1793,16 +1779,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "security-framework" version = "2.11.0" @@ -1965,6 +1941,12 @@ dependencies = [ "futures-io", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "socket2" version = "0.4.10" @@ -1985,12 +1967,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "spinning_top" version = "0.2.5" @@ -2260,28 +2236,39 @@ dependencies = [ ] [[package]] -name = "tokio-rustls" -version = "0.24.1" +name = "tokio-util" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ - "rustls", + "bytes 1.6.0", + "futures-core", + "futures-sink", + "pin-project-lite", "tokio", ] [[package]] -name = "tokio-util" -version = "0.7.11" +name = "tower" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ - "bytes 1.6.0", "futures-core", - "futures-sink", + "futures-util", + "pin-project", "pin-project-lite", "tokio", + "tower-layer", + "tower-service", ] +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -2362,21 +2349,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "uclient" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d45925a61653ac70f0588562067041ea522938898c912b0887c6dba8072ea7" -dependencies = [ - "async-trait", - "http", - "maybe-async", - "reqwest", - "surf", - "thiserror", - "url", -] - [[package]] name = "unicase" version = "2.7.0" @@ -2417,12 +2389,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "url" version = "2.5.0" @@ -2562,12 +2528,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "winapi" version = "0.3.9" @@ -2731,9 +2691,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winreg" -version = "0.50.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" dependencies = [ "cfg-if", "windows-sys 0.48.0", diff --git a/Cargo.toml b/Cargo.toml index fdf689b..075ba83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,12 +20,12 @@ status = "actively-developed" [features] default = [ "rocksdb", "reqwest_async" ] -blocking = [ "maybe-async/is_sync", "uclient/blocking" ] -reqwest_async = [ "uclient/async_reqwest" ] -reqwest_async_rustls = [ "uclient/async_reqwest_rustls" ] -reqwest_blocking = [ "uclient/blocking_reqwest", "blocking" ] -reqwest_blocking_rustls = [ "uclient/blocking_reqwest_rustls", "blocking" ] -surf_async = [ "uclient/async_surf", "http-types" ] + +blocking = [ "maybe-async/is_sync" ] +reqwest_async = [ "reqwest" ] +reqwest_blocking = [ "reqwest/blocking", "blocking" ] +surf_async = [ "http-types", "surf" ] + cluster = [ ] enterprise = [ ] mmfiles = [ ] @@ -35,7 +35,7 @@ arango3_7 = [ ] [dependencies] async-trait = "0.1" base64 = "0.22" -http = "0.2" +http = "1" log = "0.4" maybe-async = "0.2" serde_json = "1" @@ -43,7 +43,6 @@ serde_qs = "0.13" thiserror = "1" typed-builder = "0.18" url = "2" -uclient = "0.1" serde_repr = "0.1" [dependencies.serde] @@ -51,7 +50,7 @@ serde_repr = "0.1" features = [ "derive" ] [dependencies.reqwest] - version = "0.11" + version = "0.12" features = [ "gzip", "json" ] optional = true @@ -78,4 +77,4 @@ anyhow = "1" features = [ "attributes" ] [dev-dependencies.reqwest] - version = "0.11" + version = "0.12" diff --git a/examples/blocking/Cargo.toml b/examples/blocking/Cargo.toml index 82e1cff..30840ba 100644 --- a/examples/blocking/Cargo.toml +++ b/examples/blocking/Cargo.toml @@ -2,11 +2,11 @@ name = "blocking" version = "0.1.0" authors = [ "Guoli Lyu " ] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -arangors = { version = "0.4", features = [ +arangors = { version = "0.5", features = [ "blocking", ], default-features = false } diff --git a/examples/custom_client.rs b/examples/custom_client.rs index 8899437..2bae6cb 100644 --- a/examples/custom_client.rs +++ b/examples/custom_client.rs @@ -12,10 +12,10 @@ //! Several implementations are provided: async `reqwest`, blocking `reqwest`, //! `surf`(async-std) and later `awc`. use anyhow::Error; +use arangors::{client::ClientExt, ClientError}; use http::{HeaderMap, HeaderValue, Method}; #[cfg(feature = "reqwest_async")] use reqwest::Client; -use uclient::{ClientError, ClientExt}; use url::Url; use arangors::GenericConnection; @@ -32,7 +32,7 @@ pub struct ReqwestClient(pub Client, HeaderMap); /// Also, the API of reqwest is almost the same for async and sync. You can also /// use maybe_async::maybe_async to remove async/await keyword in need, and just /// import reqwesat::Client and rewest::blocking::Client respectively in async -/// and sync implementation. See `uclient::reqwest` source code. +/// and sync implementation. See `arangors::client::reqwest` source code. // This cfg is only to make rust compiler happy in Github Action, you can just ignore it #[cfg(feature = "reqwest_async")] #[async_trait::async_trait] diff --git a/examples/reqwest_rustls/Cargo.toml b/examples/reqwest_rustls/Cargo.toml index 9c32e68..e9d198e 100644 --- a/examples/reqwest_rustls/Cargo.toml +++ b/examples/reqwest_rustls/Cargo.toml @@ -2,22 +2,22 @@ name = "reqwest_rustls" version = "0.1.0" authors = [ "Guoli Lyu " ] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] # you can add features like rocksdb or blocking if you want # but DO NOT add `reqwest_async`, `reqwest_blocking` or `surf_async`. -arangors = { path = "../../", default-features = false } +arangors = { path = "../..", default-features = false } anyhow = "1" tokio = { version = "1", features = [ "macros", "rt-multi-thread" ] } # required dependencies for ReqwestClient -reqwest = { version = "0.11", features = [ +reqwest = { version = "0.12", features = [ "gzip", "json", "rustls-tls", ], default-features = false } async-trait = "0.1" -http = "0.2" +http = "1" diff --git a/examples/reqwest_rustls/src/client.rs b/examples/reqwest_rustls/src/client.rs index 500dd06..83759ce 100644 --- a/examples/reqwest_rustls/src/client.rs +++ b/examples/reqwest_rustls/src/client.rs @@ -3,10 +3,10 @@ use std::convert::TryInto; use ::reqwest::Client; use http::header::HeaderMap; -use uclient::ClientExt; -use arangors::ClientError; +use arangors::client::ClientExt; use arangors::transaction::TRANSACTION_HEADER; +use arangors::ClientError; #[derive(Debug, Clone)] pub struct ReqwestClient { @@ -16,7 +16,6 @@ pub struct ReqwestClient { #[async_trait::async_trait] impl ClientExt for ReqwestClient { - fn headers(&mut self) -> &mut HeaderMap { &mut self.headers } diff --git a/src/client/mod.rs b/src/client/mod.rs new file mode 100644 index 0000000..7d4a19f --- /dev/null +++ b/src/client/mod.rs @@ -0,0 +1,98 @@ +use http::{HeaderMap, Request, Response}; +use url::Url; + +use crate::ClientError; + +#[cfg(any(all(feature = "reqwest_async", feature = "reqwest_blocking"),))] +compile_error!(r#"Enabling both async and blocking version of reqwest client is not allowed."#); + +#[cfg(any(feature = "reqwest_async", feature = "reqwest_blocking",))] +pub mod reqwest; +#[cfg(any(feature = "surf_async"))] +pub mod surf; + +#[maybe_async::maybe_async] +pub trait ClientExt: Sync + Clone { + fn new>>(headers: U) -> Result; + + fn headers(&mut self) -> &mut HeaderMap; + + #[inline] + async fn get(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::get(url.to_string()).body(text.into()).unwrap()) + .await + } + #[inline] + async fn post(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::post(url.to_string()).body(text.into()).unwrap()) + .await + } + #[inline] + async fn put(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::put(url.to_string()).body(text.into()).unwrap()) + .await + } + #[inline] + async fn delete(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::delete(url.to_string()).body(text.into()).unwrap()) + .await + } + #[inline] + async fn patch(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::patch(url.to_string()).body(text.into()).unwrap()) + .await + } + + #[inline] + async fn connect(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::connect(url.to_string()).body(text.into()).unwrap()) + .await + } + + #[inline] + async fn head(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::head(url.to_string()).body(text.into()).unwrap()) + .await + } + + #[inline] + async fn options(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::options(url.to_string()).body(text.into()).unwrap()) + .await + } + + #[inline] + async fn trace(&self, url: Url, text: T) -> Result, ClientError> + where + T: Into + Send, + { + self.request(Request::trace(url.to_string()).body(text.into()).unwrap()) + .await + } + + async fn request(&self, request: Request) -> Result, ClientError>; +} diff --git a/src/client/reqwest.rs b/src/client/reqwest.rs new file mode 100644 index 0000000..787b050 --- /dev/null +++ b/src/client/reqwest.rs @@ -0,0 +1,78 @@ +//! Reqwest HTTP client +use std::convert::TryInto; + +#[cfg(any(feature = "reqwest_blocking"))] +use ::reqwest::blocking::Client; + +#[cfg(any(feature = "reqwest_async"))] +use ::reqwest::Client; + +use http::header::HeaderMap; + +use super::ClientExt; +use crate::ClientError; +use http::HeaderValue; + +#[derive(Debug, Clone)] +pub struct ReqwestClient { + pub client: Client, + headers: HeaderMap, +} + +#[maybe_async::maybe_async] +impl ClientExt for ReqwestClient { + fn new>>(headers: U) -> Result { + let client = Client::builder().gzip(true); + let headers = match headers.into() { + Some(h) => h, + None => HeaderMap::new(), + }; + + client + .build() + .map(|c| ReqwestClient { client: c, headers }) + .map_err(|e| ClientError::HttpClient(format!("{:?}", e))) + } + + fn headers(&mut self) -> &mut HeaderMap { + &mut self.headers + } + + async fn request( + &self, + mut request: http::Request, + ) -> Result, ClientError> { + let headers = request.headers_mut(); + for (header, value) in self.headers.iter() { + if !headers.contains_key(header) { + headers.insert(header, value.clone()); + } + } + let req = request.try_into().unwrap(); + + let resp = self + .client + .execute(req) + .await + .map_err(|e| ClientError::HttpClient(format!("{:?}", e)))?; + + let status_code = resp.status(); + let headers = resp.headers().clone(); + let version = resp.version(); + let content = resp + .text() + .await + .map_err(|e| ClientError::HttpClient(format!("{:?}", e)))?; + let mut build = http::Response::builder(); + + for header in headers.iter() { + build = build.header(header.0, header.1); + } + + build + .status(status_code) + .version(version) + .body(content) + .map_err(|e| ClientError::HttpClient(format!("{:?}", e))) + } +} diff --git a/src/client/surf.rs b/src/client/surf.rs new file mode 100644 index 0000000..5bee4a2 --- /dev/null +++ b/src/client/surf.rs @@ -0,0 +1,107 @@ +//! Surf HTTP client +use std::str::FromStr; + +use http::{ + header::{HeaderMap, HeaderValue}, + Method, StatusCode, Version, +}; + +use super::ClientExt; +use crate::ClientError; + +#[derive(Debug, Clone)] +pub struct SurfClient { + headers: HeaderMap, +} + +#[async_trait::async_trait] +impl ClientExt for SurfClient { + fn new>>(headers: U) -> Result { + let headers = match headers.into() { + Some(h) => h, + None => HeaderMap::new(), + }; + + Ok(SurfClient { headers }) + } + + fn headers(&mut self) -> &mut HeaderMap { + &mut self.headers + } + + async fn request( + &self, + request: http::Request, + ) -> Result, ClientError> { + use ::surf::http::headers::HeaderName as SurfHeaderName; + + let method = request.method().clone(); + let url = request.uri().to_owned().to_string(); + let text = request.body(); + + let req = match method { + Method::GET => ::surf::get(url), + Method::POST => ::surf::post(url), + Method::PUT => ::surf::put(url), + Method::DELETE => ::surf::delete(url), + Method::PATCH => ::surf::patch(url), + Method::CONNECT => ::surf::connect(url), + Method::HEAD => ::surf::head(url), + Method::OPTIONS => ::surf::options(url), + Method::TRACE => ::surf::trace(url), + m @ _ => return Err(ClientError::HttpClient(format!("invalid method {}", m))), + }; + + let req = self.headers.iter().fold(req, |req, (k, v)| { + req.header( + SurfHeaderName::from_str(k.as_str()).unwrap(), + v.to_str().unwrap(), + ) + }); + let req = request.headers().iter().fold(req, |req, (k, v)| { + req.header( + SurfHeaderName::from_str(k.as_str()).unwrap(), + v.to_str().unwrap(), + ) + }); + + let mut resp = req + .body(text.to_owned()) + .await + .map_err(|e| ClientError::HttpClient(format!("{:?}", e)))?; + + let status_code = resp.status(); + let status = u16::from(status_code); + + let version = resp.version(); + let content = resp + .body_string() + .await + .map_err(|e| ClientError::HttpClient(format!("{:?}", e)))?; + + let mut build = http::Response::builder(); + for (name, value) in resp.iter() { + let mut iter = value.iter(); + let acc = iter.next().map(|v| v.as_str()).unwrap_or("").to_owned(); + let s = iter.fold(acc, |acc, x| format!("{};{}", acc, x.as_str())); + build = build.header(name.as_str(), s); + } + + let http_version = version.map(|v| match v { + ::surf::http::Version::Http0_9 => Version::HTTP_09, + ::surf::http::Version::Http1_0 => Version::HTTP_10, + ::surf::http::Version::Http1_1 => Version::HTTP_11, + ::surf::http::Version::Http2_0 => Version::HTTP_2, + ::surf::http::Version::Http3_0 => Version::HTTP_3, + _ => unreachable!(), + }); + + let mut resp = + http::response::Builder::from(build).status(StatusCode::from_u16(status).unwrap()); + if version.is_some() { + resp = resp.version(http_version.unwrap()); + } + resp.body(content) + .map_err(|e| ClientError::HttpClient(format!("{:?}", e))) + } +} diff --git a/src/collection/mod.rs b/src/collection/mod.rs index 61da575..6b1b95c 100644 --- a/src/collection/mod.rs +++ b/src/collection/mod.rs @@ -8,13 +8,13 @@ use http::Request; use maybe_async::maybe_async; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::json; -use uclient::ClientExt; use url::Url; use options::*; use response::*; use crate::{ + client::ClientExt, document::{ options::{InsertOptions, ReadOptions, RemoveOptions, ReplaceOptions, UpdateOptions}, response::DocumentResponse, diff --git a/src/connection/mod.rs b/src/connection/mod.rs index 2759c62..55d2f68 100644 --- a/src/connection/mod.rs +++ b/src/connection/mod.rs @@ -42,10 +42,9 @@ use log::{debug, trace}; use maybe_async::maybe_async; use serde::{Deserialize, Serialize}; use serde_json::Value; -use uclient::ClientExt; use url::Url; -use crate::{response::ArangoResult, ClientError}; +use crate::{client::ClientExt, response::ArangoResult, ClientError}; use super::{database::Database, response::deserialize_response}; @@ -86,10 +85,10 @@ pub struct Version { } #[cfg(any(feature = "reqwest_async", feature = "reqwest_blocking"))] -pub type Connection = GenericConnection; +pub type Connection = GenericConnection; #[cfg(feature = "surf_async")] -pub type Connection = GenericConnection; +pub type Connection = GenericConnection; /// Connection is the top level API for this crate. /// It contains a http client, information about authentication, arangodb url. diff --git a/src/database.rs b/src/database.rs index 2b3b07e..1e6b380 100644 --- a/src/database.rs +++ b/src/database.rs @@ -2,7 +2,6 @@ //! //! AQL query are all executed in database level, so Database offers AQL query. use std::{collections::HashMap, fmt::Debug, sync::Arc}; -use uclient::ClientExt; use log::trace; use maybe_async::maybe_async; @@ -13,6 +12,7 @@ use url::Url; use crate::{ analyzer::{AnalyzerDescription, AnalyzerInfo}, aql::{AqlQuery, Cursor}, + client::ClientExt, collection::{ options::{CreateOptions, CreateParameters}, response::{Info, Properties}, diff --git a/src/error.rs b/src/error.rs index 8bbc777..6e1b253 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,7 +19,7 @@ pub enum ClientError { #[error("Error from serde: {0}")] Serde(#[from] serde_json::error::Error), #[error("HTTP client error: {0}")] - HttpClient(#[from] uclient::ClientError), + HttpClient(String), } #[derive(Deserialize, Debug, Error)] diff --git a/src/lib.rs b/src/lib.rs index 7d36310..da8a2d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -415,10 +415,10 @@ pub use crate::{ document::Document, error::{ArangoError, ClientError}, }; -pub use uclient; pub mod analyzer; pub mod aql; +pub mod client; pub mod collection; pub mod connection; pub mod database; diff --git a/src/transaction.rs b/src/transaction.rs index 144e313..6bcebfb 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -3,11 +3,11 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::Value; use std::{collections::HashMap, sync::Arc}; use typed_builder::TypedBuilder; -use uclient::ClientExt; use url::Url; use crate::{ aql::Cursor, + client::ClientExt, collection::response::Info, response::{deserialize_response, ArangoResult}, AqlQuery, ClientError, Collection, diff --git a/tests/analyzer.rs b/tests/analyzer.rs index 98bf17f..5baedcf 100644 --- a/tests/analyzer.rs +++ b/tests/analyzer.rs @@ -6,7 +6,6 @@ use log::{info, trace}; use maybe_async::maybe_async; use pretty_assertions::assert_eq; use std::collections::HashMap; -use uclient::ClientExt; use arangors::{ analyzer::{ @@ -14,6 +13,7 @@ use arangors::{ NgramAnalyzerProperties, NgramStreamType, NormAnalyzerProperties, PipelineAnalyzerProperties, PipelineAnalyzers, }, + client::ClientExt, collection::{ options::{ChecksumOptions, PropertiesOptions}, response::Status, diff --git a/tests/common.rs b/tests/common.rs index 6ab3366..9ac9ec4 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -70,7 +70,7 @@ pub async fn root_connection() -> arangors::Connection { pub async fn collection<'a>( conn: &'a arangors::Connection, name: &str, -) -> Collection { +) -> Collection { let database = conn.db("test_db").await.unwrap(); match database.drop_collection(name).await { @@ -88,7 +88,7 @@ pub async fn collection<'a>( pub async fn collection<'a>( conn: &'a arangors::Connection, name: &str, -) -> Collection { +) -> Collection { let database = conn.db("test_db").await.unwrap(); match database.drop_collection(name).await { diff --git a/tests/connection.rs b/tests/connection.rs index 57b82a2..4dc4828 100644 --- a/tests/connection.rs +++ b/tests/connection.rs @@ -1,7 +1,7 @@ #![allow(unused_imports)] #![allow(unused_parens)] +use arangors::client::ClientExt; use pretty_assertions::assert_eq; -use uclient::ClientExt; use arangors::{connection::Permission, Connection}; use common::{ diff --git a/tests/graph.rs b/tests/graph.rs index ca9f1f5..3aaf752 100644 --- a/tests/graph.rs +++ b/tests/graph.rs @@ -4,9 +4,9 @@ use log::trace; use pretty_assertions::assert_eq; use serde_json::{json, Value}; -use uclient::ClientExt; use arangors::{ + client::ClientExt, collection::{ options::{ChecksumOptions, PropertiesOptions}, response::Status, diff --git a/tests/transaction.rs b/tests/transaction.rs index d77d16f..75bd9e0 100644 --- a/tests/transaction.rs +++ b/tests/transaction.rs @@ -4,10 +4,10 @@ use log::trace; use maybe_async::maybe_async; use pretty_assertions::assert_eq; use serde_json::{json, Value}; -use uclient::ClientExt; use crate::common::{collection, connection}; use arangors::{ + client::ClientExt, collection::{ options::{ChecksumOptions, PropertiesOptions}, response::Status, diff --git a/tests/user.rs b/tests/user.rs index 85d601c..6d0d327 100644 --- a/tests/user.rs +++ b/tests/user.rs @@ -1,11 +1,11 @@ #![allow(unused_imports)] #![allow(unused_parens)] +use arangors::client::ClientExt; use log::{info, trace, warn}; use pretty_assertions::assert_eq; use serde_json::Value; use std::collections::HashMap; -use uclient::ClientExt; use crate::common::{get_root_user, root_connection}; use arangors::{ diff --git a/tests/view.rs b/tests/view.rs index 47d9a92..92f12ae 100644 --- a/tests/view.rs +++ b/tests/view.rs @@ -6,9 +6,9 @@ use crate::common::{collection, connection}; use log::{info, trace}; use maybe_async::maybe_async; use pretty_assertions::assert_eq; -use uclient::ClientExt; use arangors::{ + client::ClientExt, collection::{ options::{ChecksumOptions, PropertiesOptions}, response::Status,