Skip to content

Commit 4cff6d5

Browse files
authored
Reqwest Client (Tokio 1.0 support) (#92)
1 parent 7cad292 commit 4cff6d5

File tree

9 files changed

+145
-79
lines changed

9 files changed

+145
-79
lines changed

.github/workflows/rust.yml

+7-5
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,17 @@ jobs:
2626
components: "rustfmt,clippy"
2727
- name: Check code formatting
2828
run: cargo fmt --all -- --check
29-
- name: Check Clippy lints
30-
run: cargo clippy --all-targets --all-features -- -D warnings
29+
- name: Check Clippy lints (reqwest)
30+
run: cargo clippy --all-targets --no-default-features --features use-serde,derive,reqwest-client -- -D warnings
31+
- name: Check Clippy lints (surf)
32+
run: cargo clippy --all-targets --no-default-features --features use-serde,derive,hyper-client -- -D warnings
3133

3234
compile:
3335
name: Compile (${{ matrix.rust_release }}/${{ matrix.os }})
3436
runs-on: ${{ matrix.os }}
3537
strategy:
3638
matrix:
37-
rust_release: [1.45, stable, nightly]
39+
rust_release: [1.46, stable, nightly]
3840
os: [ubuntu-latest, windows-latest, macOS-latest]
3941

4042
steps:
@@ -50,7 +52,7 @@ jobs:
5052
runs-on: ubuntu-latest
5153
strategy:
5254
matrix:
53-
http-backend: [curl-client, h1-client, h1-client-rustls, hyper-client]
55+
http-backend: [curl-client, h1-client, h1-client-rustls, hyper-client, reqwest-client, reqwest-client-rustls]
5456
services:
5557
influxdb:
5658
image: influxdb:1.8
@@ -122,7 +124,7 @@ jobs:
122124
cargo tarpaulin -v \
123125
--target-dir target/tarpaulin \
124126
--workspace \
125-
--all-features \
127+
--features use-serde,derive \
126128
--exclude-files 'derive/*' \
127129
--exclude-files 'target/*' \
128130
--ignore-panics --ignore-tests \

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- reqwest-based http client (enabled by default)
13+
1014
## [0.4.0] - 2021-03-08
1115

1216
### Fixed

README.md

+17-7
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
<a href="https://www.rust-lang.org/en-US/">
2626
<img src="https://img.shields.io/badge/Made%20with-Rust-orange.svg" alt='Build with Rust' />
2727
</a>
28-
<a href="https://blog.rust-lang.org/2020/03/12/Rust-1.45.html">
29-
<img src="https://img.shields.io/badge/rustc-1.45+-yellow.svg" alt='Minimum Rust Version' />
28+
<a href="https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html">
29+
<img src="https://img.shields.io/badge/rustc-1.46+-yellow.svg" alt='Minimum Rust Version' />
3030
</a>
3131
</p>
3232

@@ -62,8 +62,8 @@ use influxdb::{Client, Query, Timestamp};
6262
use influxdb::InfluxDbWriteable;
6363
use chrono::{DateTime, Utc};
6464

65-
#[async_std::main]
66-
// or #[tokio::main] if you prefer
65+
#[tokio::main]
66+
// or #[async_std::main] if you prefer
6767
async fn main() {
6868
// Connect to db `test` on `http://localhost:8086`
6969
let client = Client::new("http://localhost:8086", "test");
@@ -101,11 +101,21 @@ in the repository.
101101

102102
## Choice of HTTP backend
103103

104-
To communicate with InfluxDB, you can choose the HTTP backend to be used configuring the appropriate feature:
104+
To communicate with InfluxDB, you can choose the HTTP backend to be used configuring the appropriate feature. We recommend sticking with the default reqwest-based client, unless you really need async-std compatibility.
105105

106-
- **[hyper](https://github.com/hyperium/hyper)** (used by default)
106+
- **[hyper](https://github.com/hyperium/hyper)** (through reqwest, used by default), with [rustls](https://github.com/ctz/rustls)
107+
```toml
108+
influxdb = { version = "0.4.0", features = ["derive"] }
109+
```
110+
111+
- **[hyper](https://github.com/hyperium/hyper)** (through reqwest), with native TLS (OpenSSL)
112+
```toml
113+
influxdb = { version = "0.4.0", default-features = false, features = ["derive", "use-serde", "reqwest-client"] }
114+
```
115+
116+
- **[hyper](https://github.com/hyperium/hyper)** (through surf), use this if you need tokio 0.2 compatibility
107117
```toml
108-
influxdb = { version = "0.4.0", features = ["derive"] }
118+
influxdb = { version = "0.4.0", default-features = false, features = ["derive", "use-serde", "curl-client"] }
109119
```
110120
- **[curl](https://github.com/alexcrichton/curl-rust)**, using [libcurl](https://curl.se/libcurl/)
111121
```toml

README.tpl

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
<a href="https://www.rust-lang.org/en-US/">
2626
<img src="https://img.shields.io/badge/Made%20with-Rust-orange.svg" alt='Build with Rust' />
2727
</a>
28-
<a href="https://blog.rust-lang.org/2020/03/12/Rust-1.45.html">
29-
<img src="https://img.shields.io/badge/rustc-1.45+-yellow.svg" alt='Minimum Rust Version' />
28+
<a href="https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html">
29+
<img src="https://img.shields.io/badge/rustc-1.46+-yellow.svg" alt='Minimum Rust Version' />
3030
</a>
3131
</p>
3232

3333
{{readme}}
3434

35-
@ 2020 Gero Gerke and [contributors](https://github.com/Empty2k12/influxdb-rust/graphs/contributors).
35+
@ 2020 Gero Gerke and [contributors](https://github.com/Empty2k12/influxdb-rust/graphs/contributors).

influxdb/Cargo.toml

+17-11
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,30 @@ travis-ci = { repository = "Empty2k12/influxdb-rust", branch = "master" }
1818
[dependencies]
1919
chrono = { version = "0.4.11", features = ["serde"] }
2020
futures = "0.3.4"
21-
lazy_static = "1.4.0"
21+
http = "0.2.4"
2222
influxdb_derive = { version = "0.4.0", optional = true }
23+
lazy_static = "1.4.0"
2324
regex = "1.3.5"
24-
surf = { version = "2.2.0", default-features = false }
25+
reqwest = { version = "0.11.4", default-features = false, optional = true }
26+
surf = { version = "2.2.0", default-features = false, optional = true }
2527
serde = { version = "1.0.104", features = ["derive"], optional = true }
2628
serde_json = { version = "1.0.48", optional = true }
2729
thiserror = "1.0"
2830

2931
[features]
30-
use-serde = ["serde", "serde_json"]
31-
curl-client = ["surf/curl-client"]
32-
h1-client = ["surf/h1-client"]
33-
h1-client-rustls = ["surf/h1-client-rustls"]
34-
hyper-client = ["surf/hyper-client"]
35-
wasm-client = ["surf/wasm-client"]
36-
default = ["use-serde", "hyper-client"]
32+
default = ["use-serde", "reqwest-client-rustls"]
3733
derive = ["influxdb_derive"]
34+
use-serde = ["serde", "serde_json"]
35+
36+
# http clients
37+
curl-client = ["surf", "surf/curl-client"]
38+
h1-client = ["surf", "surf/h1-client"]
39+
h1-client-rustls = ["surf", "surf/h1-client-rustls"]
40+
hyper-client = ["surf", "surf/hyper-client"]
41+
reqwest-client = ["reqwest", "reqwest/native-tls-alpn"]
42+
reqwest-client-rustls = ["reqwest", "reqwest/rustls-tls-webpki-roots"]
43+
wasm-client = ["surf", "surf/wasm-client"]
3844

3945
[dev-dependencies]
40-
async-std = { version = "1.6.5", features = ["attributes"] }
41-
tokio = { version = "0.2.22", features = ["rt-threaded", "macros"] }
46+
async-std = { version = "1.6.5", features = ["attributes", "tokio02", "tokio1"] }
47+
tokio = { version = "1.7", features = ["macros", "rt-multi-thread"] }

influxdb/src/client/mod.rs

+52-23
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
//! ```
1717
1818
use futures::prelude::*;
19-
use surf::{self, Client as SurfClient, StatusCode};
19+
use http::StatusCode;
20+
#[cfg(feature = "reqwest")]
21+
use reqwest::{Client as HttpClient, Response as HttpResponse};
22+
#[cfg(feature = "surf")]
23+
use surf::{Client as HttpClient, Response as HttpResponse};
2024

2125
use crate::query::QueryType;
2226
use crate::Error;
@@ -29,7 +33,7 @@ use std::sync::Arc;
2933
pub struct Client {
3034
pub(crate) url: Arc<String>,
3135
pub(crate) parameters: Arc<HashMap<&'static str, String>>,
32-
pub(crate) client: SurfClient,
36+
pub(crate) client: HttpClient,
3337
}
3438

3539
impl Client {
@@ -57,7 +61,7 @@ impl Client {
5761
Client {
5862
url: Arc::new(url.into()),
5963
parameters: Arc::new(parameters),
60-
client: SurfClient::new(),
64+
client: HttpClient::new(),
6165
}
6266
}
6367

@@ -112,10 +116,25 @@ impl Client {
112116
error: format!("{}", err),
113117
})?;
114118

115-
let build = res.header("X-Influxdb-Build").unwrap().as_str();
116-
let version = res.header("X-Influxdb-Version").unwrap().as_str();
119+
const BUILD_HEADER: &str = "X-Influxdb-Build";
120+
const VERSION_HEADER: &str = "X-Influxdb-Version";
117121

118-
Ok((build.to_owned(), version.to_owned()))
122+
#[cfg(feature = "reqwest")]
123+
let (build, version) = {
124+
let hdrs = res.headers();
125+
(
126+
hdrs.get(BUILD_HEADER).and_then(|value| value.to_str().ok()),
127+
hdrs.get(VERSION_HEADER)
128+
.and_then(|value| value.to_str().ok()),
129+
)
130+
};
131+
132+
#[cfg(feature = "surf")]
133+
let build = res.header(BUILD_HEADER).map(|value| value.as_str());
134+
#[cfg(feature = "surf")]
135+
let version = res.header(VERSION_HEADER).map(|value| value.as_str());
136+
137+
Ok((build.unwrap().to_owned(), version.unwrap().to_owned()))
119138
}
120139

121140
/// Sends a [`ReadQuery`](crate::ReadQuery) or [`WriteQuery`](crate::WriteQuery) to the InfluxDB Server.
@@ -184,32 +203,31 @@ impl Client {
184203

185204
self.client.post(url).body(query.get()).query(&parameters)
186205
}
187-
}
188-
.map_err(|err| Error::UrlConstructionError {
206+
};
207+
208+
#[cfg(feature = "surf")]
209+
let request_builder = request_builder.map_err(|err| Error::UrlConstructionError {
189210
error: err.to_string(),
190211
})?;
191212

192-
let request = request_builder.build();
193-
let mut res = self
194-
.client
195-
.send(request)
213+
let res = request_builder
214+
.send()
196215
.map_err(|err| Error::ConnectionError {
197216
error: err.to_string(),
198217
})
199218
.await?;
219+
check_status(&res)?;
200220

201-
match res.status() {
202-
StatusCode::Unauthorized => return Err(Error::AuthorizationError),
203-
StatusCode::Forbidden => return Err(Error::AuthenticationError),
204-
_ => {}
205-
}
221+
#[cfg(feature = "reqwest")]
222+
let body = res.text();
223+
#[cfg(feature = "surf")]
224+
let mut res = res;
225+
#[cfg(feature = "surf")]
226+
let body = res.body_string();
206227

207-
let s = res
208-
.body_string()
209-
.await
210-
.map_err(|_| Error::DeserializationError {
211-
error: "response could not be converted to UTF-8".to_string(),
212-
})?;
228+
let s = body.await.map_err(|_| Error::DeserializationError {
229+
error: "response could not be converted to UTF-8".to_string(),
230+
})?;
213231

214232
// todo: improve error parsing without serde
215233
if s.contains("\"error\"") {
@@ -222,6 +240,17 @@ impl Client {
222240
}
223241
}
224242

243+
pub(crate) fn check_status(res: &HttpResponse) -> Result<(), Error> {
244+
let status = res.status();
245+
if status == StatusCode::UNAUTHORIZED.as_u16() {
246+
Err(Error::AuthorizationError)
247+
} else if status == StatusCode::FORBIDDEN.as_u16() {
248+
Err(Error::AuthenticationError)
249+
} else {
250+
Ok(())
251+
}
252+
}
253+
225254
#[cfg(test)]
226255
mod tests {
227256
use super::Client;

influxdb/src/integrations/serde_integration/mod.rs

+17-20
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,9 @@
4848
4949
mod de;
5050

51-
use surf::StatusCode;
52-
5351
use serde::{de::DeserializeOwned, Deserialize};
5452

55-
use crate::{Client, Error, Query, ReadQuery};
53+
use crate::{client::check_status, Client, Error, Query, ReadQuery};
5654

5755
#[derive(Deserialize)]
5856
#[doc(hidden)]
@@ -143,30 +141,29 @@ impl Client {
143141
let url = &format!("{}/query", &self.url);
144142
let mut parameters = self.parameters.as_ref().clone();
145143
parameters.insert("q", read_query);
146-
let request = self
147-
.client
148-
.get(url)
149-
.query(&parameters)
150-
.map_err(|err| Error::UrlConstructionError {
151-
error: err.to_string(),
152-
})?
153-
.build();
144+
let request_builder = self.client.get(url).query(&parameters);
145+
146+
#[cfg(feature = "surf")]
147+
let request_builder = request_builder.map_err(|err| Error::UrlConstructionError {
148+
error: err.to_string(),
149+
})?;
154150

155-
let mut res = self
156-
.client
157-
.send(request)
151+
let res = request_builder
152+
.send()
158153
.await
159154
.map_err(|err| Error::ConnectionError {
160155
error: err.to_string(),
161156
})?;
157+
check_status(&res)?;
162158

163-
match res.status() {
164-
StatusCode::Unauthorized => return Err(Error::AuthorizationError),
165-
StatusCode::Forbidden => return Err(Error::AuthenticationError),
166-
_ => {}
167-
}
159+
#[cfg(feature = "reqwest")]
160+
let body = res.bytes();
161+
#[cfg(feature = "surf")]
162+
let mut res = res;
163+
#[cfg(feature = "surf")]
164+
let body = res.body_bytes();
168165

169-
let body = res.body_bytes().await.map_err(|err| Error::ProtocolError {
166+
let body = body.await.map_err(|err| Error::ProtocolError {
170167
error: err.to_string(),
171168
})?;
172169

influxdb/src/lib.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
//! use influxdb::InfluxDbWriteable;
3131
//! use chrono::{DateTime, Utc};
3232
//!
33-
//! #[async_std::main]
34-
//! // or #[tokio::main] if you prefer
33+
//! #[tokio::main]
34+
//! // or #[async_std::main] if you prefer
3535
//! async fn main() {
3636
//! // Connect to db `test` on `http://localhost:8086`
3737
//! let client = Client::new("http://localhost:8086", "test");
@@ -69,11 +69,21 @@
6969
//!
7070
//! # Choice of HTTP backend
7171
//!
72-
//! To communicate with InfluxDB, you can choose the HTTP backend to be used configuring the appropriate feature:
72+
//! To communicate with InfluxDB, you can choose the HTTP backend to be used configuring the appropriate feature. We recommend sticking with the default reqwest-based client, unless you really need async-std compatibility.
7373
//!
74-
//! - **[hyper](https://github.com/hyperium/hyper)** (used by default)
74+
//! - **[hyper](https://github.com/hyperium/hyper)** (through reqwest, used by default), with [rustls](https://github.com/ctz/rustls)
75+
//! ```toml
76+
//! influxdb = { version = "0.4.0", features = ["derive"] }
77+
//! ```
78+
//!
79+
//! - **[hyper](https://github.com/hyperium/hyper)** (through reqwest), with native TLS (OpenSSL)
80+
//! ```toml
81+
//! influxdb = { version = "0.4.0", default-features = false, features = ["derive", "use-serde", "reqwest-client"] }
82+
//! ```
83+
//!
84+
//! - **[hyper](https://github.com/hyperium/hyper)** (through surf), use this if you need tokio 0.2 compatibility
7585
//! ```toml
76-
//! influxdb = { version = "0.4.0", features = ["derive"] }
86+
//! influxdb = { version = "0.4.0", default-features = false, features = ["derive", "use-serde", "curl-client"] }
7787
//! ```
7888
//! - **[curl](https://github.com/alexcrichton/curl-rust)**, using [libcurl](https://curl.se/libcurl/)
7989
//! ```toml
@@ -99,6 +109,12 @@
99109
#![allow(clippy::needless_doctest_main)]
100110
#![allow(clippy::needless_lifetimes)] // False positive in client/mod.rs query fn
101111

112+
#[cfg(all(feature = "reqwest", feature = "surf"))]
113+
compile_error!("You need to choose between reqwest and surf; enabling both is not supported");
114+
115+
#[cfg(not(any(feature = "reqwest", feature = "surf")))]
116+
compile_error!("You need to choose an http client; consider not disabling default features");
117+
102118
mod client;
103119
mod error;
104120
mod query;

0 commit comments

Comments
 (0)