Skip to content

Commit c05fcac

Browse files
committed
Update deps and replace tokio/reqwest with smol/isahc
Signed-off-by: Mohammad AlSaleh <[email protected]>
1 parent 0692a14 commit c05fcac

8 files changed

+83
-113
lines changed

Cargo.toml

+4-5
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,15 @@ clap = {version = "2" , features = ["yaml"]}
1111
time = "0.1"
1212
serde = { version = "1", features = ["derive"] }
1313
serde_json = "1"
14-
semver = "0.10"
14+
semver = "0.11"
1515
regex = "1"
1616
lazy_static = "1"
17-
reqwest = { version = "0.10", features = ["gzip"] }
18-
bytes = "0.5"
19-
tokio = { version = "0.2", features = ["full"] }
17+
isahc = { version = "1", default_features = false, features = ["http2"]}
18+
smol = "1"
2019
async-trait = "0.1"
2120
futures = "0.3"
2221
fern = "0.6"
2322
chrono = "0.4"
2423
log = "0.4"
25-
crates-index = "0.14"
24+
crates-index = "0.16"
2625
once_cell = "1"

src/bin/cargo-esr.rs

+5-32
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ async fn run() {
161161
},
162162
false => match (search_by_relevance, search_by_total_downloads, search_by_recent_downloads) {
163163
// default
164-
(false, false, _) => "per_page=".to_string() + search_limit + "&q=" + &search_str + "&sort=recent-downloads",
165-
(_, true, _) => "per_page=".to_string() + search_limit + "&q=" + &search_str + "&sort=downloads",
166-
(true, _, _) => "per_page=".to_string() + search_limit + "&q=" + &search_str,
164+
(false, false, _) => "per_page=".to_string() + search_limit + "&q=" + &*search_str + "&sort=recent-downloads",
165+
(_, true, _) => "per_page=".to_string() + search_limit + "&q=" + &*search_str + "&sort=downloads",
166+
(true, _, _) => "per_page=".to_string() + search_limit + "&q=" + &*search_str,
167167
},
168168

169169
};
@@ -177,19 +177,7 @@ async fn run() {
177177
std::process::exit(1);
178178
}
179179

180-
let crates_scores_res = match Scores::collect_scores(
181-
crates,
182-
&gh_token,
183-
crate_only,
184-
repo_only)
185-
.await {
186-
Ok(res) => res,
187-
Err(_) => {
188-
EsrPrinter::err("A tokio task or more returned errors.");
189-
std::process::exit(1);
190-
},
191-
};
192-
180+
let crates_scores_res = Scores::collect_scores(crates, &gh_token, crate_only, repo_only).await;
193181
Scores::search_results(&*crates_scores_res, sort_positive, results_limit_num).println();
194182
},
195183
Err(ref e) => {
@@ -204,20 +192,5 @@ async fn run() {
204192
}
205193

206194
fn main() {
207-
208-
// build runtime
209-
let runtime_res = tokio::runtime::Builder::new()
210-
.enable_all()
211-
//.basic_scheduler()
212-
.threaded_scheduler()
213-
.core_threads(16)
214-
.build();
215-
216-
match runtime_res {
217-
Ok(mut runtime) => runtime.block_on(run()),
218-
Err(_) => {
219-
EsrPrinter::err("Failed to create tokio runtime.").println();
220-
std::process::exit(1);
221-
},
222-
}
195+
smol::block_on(run());
223196
}

src/esr_crate.rs

+27-26
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use semver::{Version, VersionReq};
1414
use serde::Deserialize;
1515
use async_trait::async_trait;
1616
use futures::future;
17-
use tokio::task;
1817
use once_cell::sync::OnceCell;
1918

2019
use crate::esr_errors::{Result, EsrError};
@@ -107,26 +106,28 @@ struct Dependant {
107106
impl Dependant {
108107
async fn dependants_from_id(id: String) -> Result<Vec<Self>> {
109108
log::debug!("Getting dependats from index for {}", id);
110-
let mut ret = Vec::with_capacity(64);
111-
for cr in get_index()?.crates() {
112-
let latest_version = cr.latest_version();
113-
let match_opt = latest_version
114-
.dependencies()
115-
.iter()
116-
.find(|dep| !latest_version.is_yanked() && dep.crate_name() == id);
117-
118-
if let Some(dep) = match_opt {
119-
ret.push(
120-
Self {
121-
crate_name: cr.name().into(),
122-
default_features: dep.has_default_features() && !dep.is_optional(),
123-
optional: dep.is_optional(),
124-
req: dep.requirement().into(),
125-
}
126-
);
109+
smol::spawn( async move {
110+
let mut ret = Vec::with_capacity(64);
111+
for cr in get_index()?.crates() {
112+
let latest_version = cr.latest_version();
113+
let match_opt = latest_version
114+
.dependencies()
115+
.iter()
116+
.find(|dep| !latest_version.is_yanked() && dep.crate_name() == id);
117+
118+
if let Some(dep) = match_opt {
119+
ret.push(
120+
Self {
121+
crate_name: cr.name().into(),
122+
default_features: dep.has_default_features() && !dep.is_optional(),
123+
optional: dep.is_optional(),
124+
req: dep.requirement().into(),
125+
}
126+
);
127+
}
127128
}
128-
}
129-
Ok(ret)
129+
Ok(ret)
130+
}).await
130131
}
131132
}
132133

@@ -288,8 +289,8 @@ impl CrateScoreInfo {
288289
async fn from_crate_info(crate_info: &CrateInfo) -> Result<Self> {
289290
let general_info = &crate_info.general_info;
290291

291-
let owners_info_fut = task::spawn(CrateOwners::from_id_owned(general_info.id.clone()));
292-
let dependants_info_fut = task::spawn(Dependant::dependants_from_id(general_info.id.clone()));
292+
let owners_info_fut = smol::spawn(CrateOwners::from_id_owned(general_info.id.clone()));
293+
let dependants_info_fut = smol::spawn(Dependant::dependants_from_id(general_info.id.clone()));
293294

294295
let has_desc = general_info.description.is_some() as usize;
295296
let has_docs = general_info.documentation.is_some() as usize;
@@ -315,8 +316,8 @@ impl CrateScoreInfo {
315316
None => esr_util::age_in_months(&esr_util::crate_to_iso8601(&general_info.created_at))?,
316317
};
317318

318-
let dependants_info = dependants_info_fut.await??;
319-
let owners_info = owners_info_fut.await??;
319+
let dependants_info = dependants_info_fut.await?;
320+
let owners_info = owners_info_fut.await?;
320321

321322
// Reverse dependencies
322323
let dependants = dependants_info.len();
@@ -347,13 +348,13 @@ impl CrateScoreInfo {
347348

348349
let owners_crates = owners_ids
349350
.into_iter()
350-
.map(|id| task::spawn(CrateSearch::from_id_owned(id)));
351+
.map(|id| smol::spawn(CrateSearch::from_id_owned(id)));
351352

352353
let owners_crates = future::join_all(owners_crates)
353354
.await
354355
.into_iter()
355356
.map(|t| t.map_err(|e| e.into()))
356-
.collect::<Result<Result<Vec<_>>>>()??;
357+
.collect::<Result<Vec<_>>>()?;
357358

358359
let owners_crates_flat: Vec<_> = owners_crates.iter()
359360
.flat_map(|search| search.crates.iter())

src/esr_errors.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ pub enum EsrError {
1919
TimeParse(time::ParseError),
2020
SerdeJson(serde_json::Error),
2121
Regex(regex::Error),
22-
Reqwest(reqwest::Error),
22+
Isahc(isahc::Error),
2323
CratesIndex(String),
24-
TokioTaskJoin(tokio::task::JoinError),
2524
Other(String),
2625
}
2726

@@ -32,9 +31,8 @@ impl fmt::Display for EsrError {
3231
EsrError::TimeParse(ref e) => write!(f, "Time parsing Error: {}", e),
3332
EsrError::SerdeJson(ref e) => write!(f, "Deserialization Error: {}", e),
3433
EsrError::Regex(ref e) => write!(f, "Regex Error: {}", e),
35-
EsrError::Reqwest(ref e) => write!(f, "Reqwest Error: {}", e),
34+
EsrError::Isahc(ref e) => write!(f, "isahc Error: {}", e),
3635
EsrError::CratesIndex(ref e) => write!(f, "CratesIndex Error: {}", e),
37-
EsrError::TokioTaskJoin(ref e) => write!(f, "tokio task join Error: {}", e),
3836
EsrError::Other(ref e) => write!(f, "Error: {}", e),
3937
}
4038
}
@@ -64,15 +62,9 @@ impl From<regex::Error> for EsrError {
6462
}
6563
}
6664

67-
impl From<tokio::task::JoinError> for EsrError {
68-
fn from(e: tokio::task::JoinError) -> Self {
69-
EsrError::TokioTaskJoin(e)
70-
}
71-
}
72-
73-
impl From<reqwest::Error> for EsrError {
74-
fn from(e: reqwest::Error) -> Self {
75-
EsrError::Reqwest(e)
65+
impl From<isahc::Error> for EsrError {
66+
fn from(e: isahc::Error) -> Self {
67+
EsrError::Isahc(e)
7668
}
7769
}
7870

src/esr_from.rs

+27-17
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,29 @@
99
file, You can obtain one at <http://mozilla.org/MPL/2.0/>.
1010
*/
1111

12+
use once_cell::sync::OnceCell;
1213
use serde::{Deserialize, de::DeserializeOwned};
13-
use reqwest::Client;
14-
use bytes::Bytes;
14+
use isahc::{HttpClientBuilder, HttpClient, AsyncReadResponseExt};
15+
use isahc::config::{Configurable, RedirectPolicy};
1516
use async_trait::async_trait;
1617
use futures::future;
1718

1819
use crate::esr_errors::Result;
1920

21+
fn get_static_client() -> Result<&'static HttpClient> {
22+
static RET: OnceCell<HttpClient> = OnceCell::new();
23+
let init = || HttpClientBuilder::new()
24+
//.connect_timeout(Duration::from_secs(5))
25+
.max_connections(32)
26+
.redirect_policy(RedirectPolicy::Limit(5))
27+
.auto_referer()
28+
.default_header("User-Agent", "cargo-esr/0.1")
29+
.build();
30+
let ret = RET.get_or_try_init(init)?;
31+
Ok(ret)
32+
33+
}
34+
2035
#[derive(Deserialize, Debug, Clone)]
2136
pub struct Meta {
2237
pub total: usize,
@@ -36,7 +51,7 @@ pub trait EsrFromMulti: EsrFrom + Sync + Send + 'static {
3651
let num_pages = (total as f64 / 100.0).ceil() as usize;
3752

3853
let more_pages_iter = (2..=num_pages)
39-
.map(|page| url.to_owned() + &format!("&page={}", page))
54+
.map(|page| url.to_owned() + &*format!("&page={}", page))
4055
.map(|page_url| Self::from_url_owned(page_url));
4156

4257

@@ -84,30 +99,25 @@ pub trait EsrFrom: Sized + Sync + Send + DeserializeOwned {
8499
}
85100
}
86101

87-
async fn bytes_from_url(url: &str) -> Result<Bytes> {
88-
let client = Client::builder().build()?;
89-
102+
async fn bytes_from_url(url: &str) -> Result<Vec<u8>> {
103+
let client = get_static_client()?;
90104
log::debug!("Getting data from '{}'", url);
91105

92106
// Creating an outgoing request.
93-
let ret = client.get(url)
94-
.header("user-agent", "cargo-esr/0.1")
95-
.send()
96-
.await?
97-
.error_for_status()?
98-
.bytes()
99-
.await?;
107+
let mut response = client.get_async(url).await?;
108+
let mut buf = Vec::with_capacity(64*1024);
109+
response.copy_to(&mut buf).await?;
100110

101-
log::debug!("Got data from '{}' (len={})", url, ret.len());
111+
log::debug!("Got data from '{}' (len={})", url, buf.len());
102112

103-
Ok(ret)
113+
Ok(buf)
104114
}
105115

106-
async fn bytes_from_id(id: &str) -> Result<Bytes> {
116+
async fn bytes_from_id(id: &str) -> Result<Vec<u8>> {
107117
Self::bytes_from_url(&*Self::url_from_id(id)).await
108118
}
109119

110-
async fn bytes_from_id_with_token(id: &str, token: &str) -> Result<Bytes> {
120+
async fn bytes_from_id_with_token(id: &str, token: &str) -> Result<Vec<u8>> {
111121
Self::bytes_from_url(&*Self::url_from_id_and_token(id, token)).await
112122
}
113123

src/esr_github.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
*/
1111

1212
use serde::Deserialize;
13-
use tokio::task;
1413

1514
use crate::esr_from::EsrFrom;
1615
use crate::esr_util;
@@ -94,16 +93,16 @@ impl RepoInfo {
9493

9594
pub async fn from_id_with_token(id: String, token: String) -> Result<Self> {
9695
// pulls is slow, so we spawn it first
97-
let last_100_pull_requests_fut = task::spawn(RepoPullRequests::from_id_with_token_owned(id.clone(), token.clone()));
98-
let last_100_closed_issues_fut = task::spawn(RepoClosedIssues::from_id_with_token_owned(id.clone(), token.clone()));
99-
let top_100_contributors_fut = task::spawn(RepoContributors::from_id_with_token_owned(id.clone(), token.clone()));
100-
let general_info_fut = task::spawn(RepoGeneralInfo::from_id_with_token_owned(id, token));
96+
let last_100_pull_requests_fut = smol::spawn(RepoPullRequests::from_id_with_token_owned(id.clone(), token.clone()));
97+
let last_100_closed_issues_fut = smol::spawn(RepoClosedIssues::from_id_with_token_owned(id.clone(), token.clone()));
98+
let top_100_contributors_fut = smol::spawn(RepoContributors::from_id_with_token_owned(id.clone(), token.clone()));
99+
let general_info_fut = smol::spawn(RepoGeneralInfo::from_id_with_token_owned(id, token));
101100

102101
Ok(Self {
103-
general_info: general_info_fut.await??,
104-
last_100_closed_issues: last_100_closed_issues_fut.await??,
105-
last_100_pull_requests: last_100_pull_requests_fut.await??,
106-
top_100_contributors: top_100_contributors_fut.await??,
102+
general_info: general_info_fut.await?,
103+
last_100_closed_issues: last_100_closed_issues_fut.await?,
104+
last_100_pull_requests: last_100_pull_requests_fut.await?,
105+
top_100_contributors: top_100_contributors_fut.await?,
107106
})
108107
}
109108
}

src/esr_printer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl EsrPrinter {
131131
} else {
132132
score_formatted += sep() + TermString::new(YELLOW_BOLD(), &*line.0) + sep();
133133
score_formatted += TermString::new(GREEN_BOLD(), &*line.1) + sep();
134-
score_formatted += TermString::new(GREEN_BOLD(), format!("{: ^11}", "+".to_string() + &line.2)) + sep() + "\n";
134+
score_formatted += TermString::new(GREEN_BOLD(), format!("{: ^11}", "+".to_string() + &*line.2)) + sep() + "\n";
135135
score_formatted += frame_line();
136136
}
137137
}

src/esr_score.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use crate::esr_util;
1717
use crate::esr_errors::Result;
1818

1919
use term_string::TermString;
20-
use tokio::task;
2120

2221
use std::f64;
2322
use std::default::Default;
@@ -34,12 +33,12 @@ impl Scores {
3433

3534
let repo_score_res = cr_info.github_id()
3635
.ok_or("Failed to get GitHub id")
37-
.map(|gh_id| task::spawn(RepoInfoWithScore::from_id_with_token(gh_id, gh_token)));
36+
.map(|gh_id| smol::spawn(RepoInfoWithScore::from_id_with_token(gh_id, gh_token)));
3837

3938
let cr_score = CrateInfoWithScore::from_info(cr_info).await?;
4039

4140
match repo_score_res {
42-
Ok(repo_score) => Ok(Scores::CrateAndRepo(cr_score, repo_score.await?)),
41+
Ok(repo_score) => Ok(Scores::CrateAndRepo(cr_score, repo_score.await)),
4342
Err(_) => Ok(Scores::CrateOnly(cr_score)),
4443
}
4544
}
@@ -126,33 +125,30 @@ impl Scores {
126125

127126
pub async fn collect_scores(crates: &[CrateGeneralInfo], token: &str,
128127
crate_only: bool,
129-
repo_only: bool) -> Result<Vec<(String, Result<Self>)>> {
128+
repo_only: bool) -> Vec<(String, Result<Self>)> {
130129

131130
let task_iter = if crate_only {
132131
crates
133132
.iter()
134133
.map(|cr| String::from(cr.get_id()))
135-
.map(|id| task::spawn(async { (id.clone(), Scores::from_id_crate_only(id).await) }))
134+
.map(|id| smol::spawn(async { (id.clone(), Scores::from_id_crate_only(id).await) }))
136135
.collect::<Vec<_>>()
137136

138137
} else if repo_only {
139138
crates
140139
.iter()
141140
.map(|cr| (String::from(cr.get_id()), String::from(token)))
142-
.map(|(id, token)| task::spawn(async { (id.clone(), Scores::from_id_with_token_repo_only(id, token).await) }))
141+
.map(|(id, token)| smol::spawn(async { (id.clone(), Scores::from_id_with_token_repo_only(id, token).await) }))
143142
.collect::<Vec<_>>()
144143
} else {
145144
crates
146145
.iter()
147146
.map(|cr| (String::from(cr.get_id()), String::from(token)))
148-
.map(|(id, token)| task::spawn(async { (id.clone(), Scores::from_id_with_token(id, token).await) }))
147+
.map(|(id, token)| smol::spawn(async { (id.clone(), Scores::from_id_with_token(id, token).await) }))
149148
.collect::<Vec<_>>()
150149
};
151150

152151
futures::future::join_all(task_iter).await
153-
.into_iter()
154-
.map(|res| res.map_err(|e| e.into()))
155-
.collect::<Result<Vec<_>>>()
156152
}
157153

158154
fn info_pair(&self, id: &str, sort_positive: bool) -> (f64, TermString) {

0 commit comments

Comments
 (0)