Skip to content
This repository has been archived by the owner on Mar 18, 2023. It is now read-only.

Commit

Permalink
🐛 Switching from surf to reqwest to get HTTP/2 on rustls
Browse files Browse the repository at this point in the history
  • Loading branch information
eigenein committed Jul 5, 2021
1 parent bc2d35c commit fb267b4
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 319 deletions.
293 changes: 79 additions & 214 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 8 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "blitz-dashboard"
version = "0.4.3"
version = "0.4.4"
authors = ["Pavel Perestoronin <[email protected]>"]
edition = "2018"
description = "World of Tanks Blitz player's web dashboard"
Expand All @@ -26,7 +26,6 @@ itertools = "0.10.0"
log = "0.4.14"
maud = "0.22.2"
ordered-float = "2.5.1"
serde_json = "1.0.59"
serde_qs = "0.8.4"
simplelog = "0.10.0"

Expand All @@ -35,10 +34,10 @@ version = "0.16.0"
default-features = false
features = ["h1-server"]

[dependencies.surf]
version = "2.2.0"
[dependencies.reqwest]
version = "0.11.4"
default-features = false
features = ["curl-client"]
features = ["rustls-tls", "gzip", "brotli", "deflate", "json"]

[dependencies.http-types]
version = "2.11.1"
Expand All @@ -50,16 +49,12 @@ features = ["serde"]

[dependencies.async-std]
version = "1.6.0"
features = ["attributes"]
features = ["attributes", "tokio1"]

[dependencies.moka]
version = "0.4.0"
features = ["future"]

# [dependencies.openssl]
# version = "0.10"
# features = ["vendored"]

[dependencies.sentry]
version = "0.22.0"
default-features = false
Expand All @@ -73,3 +68,6 @@ features = ["derive"]
version = "0.5.5"
default-features = false
features = ["runtime-async-std-rustls", "postgres", "chrono"]

[dev-dependencies]
serde_json = "1.0.59"
2 changes: 2 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[[bans.deny]]
name = "openssl-sys"
11 changes: 8 additions & 3 deletions src/database.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::str::FromStr;
use std::time::Duration as StdDuration;

use anyhow::Context;
use chrono::{DateTime, Duration, Utc};
use sqlx::postgres::{PgPoolOptions, PgRow};
use sqlx::{Executor, FromRow, PgPool, Postgres, Row, Transaction};
use log::LevelFilter;
use sqlx::postgres::{PgConnectOptions, PgPoolOptions, PgRow};
use sqlx::{ConnectOptions, Executor, FromRow, PgPool, Postgres, Row, Transaction};

use crate::metrics::Stopwatch;
use crate::models::{
Expand All @@ -20,8 +22,11 @@ pub struct Statistics {
/// Open and initialize the database.
pub async fn open(uri: &str) -> crate::Result<PgPool> {
log::info!("Connecting to the database…");
let mut options = PgConnectOptions::from_str(uri)?;
options.log_statements(LevelFilter::Trace);
options.log_slow_statements(LevelFilter::Warn, StdDuration::from_secs(1));
let inner = PgPoolOptions::new()
.connect(uri)
.connect_with(options)
.await
.context("failed to connect")?;

Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async fn main() -> crate::Result {
}

async fn run_subcommand(opts: Opts) -> crate::Result {
let api = WargamingApi::new(&opts.application_id);
let api = WargamingApi::new(&opts.application_id)?;
let database = crate::database::open(&opts.database).await?;
match opts.subcommand {
Subcommand::Web(opts) => web::run(&opts.host, opts.port, api, database).await,
Expand Down
1 change: 1 addition & 0 deletions src/tankopedia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub async fn run(api: WargamingApi, database: PgPool) -> crate::Result {
.collect::<Vec<Vehicle>>(),
)
.await?;
log::info!("Committing…");
transaction.commit().await?;
Ok(())
}
55 changes: 36 additions & 19 deletions src/wargaming.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use std::time::Duration as StdDuration;
use std::time::{Duration as StdDuration, Instant};

use anyhow::{anyhow, Context};
use clap::{crate_name, crate_version};
use itertools::{merge_join_by, EitherOrBoth, Itertools};
use reqwest::header::{HeaderMap, HeaderValue};
use reqwest::Url;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use surf::Url;

use crate::models;

mod middleware;

#[derive(Clone)]
pub struct WargamingApi {
application_id: Arc<String>,
client: surf::Client,
client: reqwest::Client,
request_counter: Arc<AtomicU32>,
}

/// Generic Wargaming.net API response.
Expand All @@ -25,17 +27,21 @@ struct Response<T> {
}

impl WargamingApi {
pub fn new(application_id: &str) -> WargamingApi {
Self {
pub fn new(application_id: &str) -> crate::Result<WargamingApi> {
let mut headers = HeaderMap::new();
headers.insert(
"User-Agent",
HeaderValue::from_static(concat!(crate_name!(), "/", crate_version!())),
);
Ok(Self {
application_id: Arc::new(application_id.to_string()),
client: surf::client()
.with(middleware::UserAgent)
.with(middleware::TimeoutAndRetry {
timeout: StdDuration::from_millis(1000),
n_retries: 3,
})
.with(middleware::Logger),
}
client: reqwest::ClientBuilder::new()
.default_headers(headers)
.https_only(true)
.timeout(StdDuration::from_secs(3))
.build()?,
request_counter: Arc::new(AtomicU32::new(1)),
})
}

/// See: <https://developers.wargaming.net/reference/all/wotb/account/list/>.
Expand Down Expand Up @@ -171,15 +177,26 @@ impl WargamingApi {
}

async fn call<T: DeserializeOwned>(&self, url: &Url) -> crate::Result<T> {
Ok(self
let request_id = self.request_counter.fetch_add(1, Ordering::Relaxed);
log::debug!("Sending #{} {}", request_id, url);
let start_instant = Instant::now();
let response = self
.client
.get(url.as_str())
.send()
.await
.map_err(surf::Error::into_inner)
.context("failed to send the Wargaming.net API request")?;
log::debug!(
"Done #{} [{}] {:?}",
request_id,
response.status(),
Instant::now() - start_instant,
);
Ok(response
.error_for_status()
.context("Wargaming.net API request has failed")?
.body_json::<Response<T>>()
.json::<Response<T>>()
.await
.map_err(surf::Error::into_inner)
.context("failed to parse JSON")?
.data)
}
Expand Down
71 changes: 0 additions & 71 deletions src/wargaming/middleware.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/web/player/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl ViewModel {
fn parse_account_id(request: &Request<State>) -> crate::Result<i32> {
request
.param("account_id")
.map_err(surf::Error::into_inner)
.map_err(tide::Error::into_inner)
.context("missing account ID")?
.parse()
.context("invalid account ID")
Expand Down

0 comments on commit fb267b4

Please sign in to comment.