From ec92f930344d364e3be359a41aebea78f8205fa7 Mon Sep 17 00:00:00 2001 From: Sam Tay Date: Wed, 17 Jun 2020 23:30:33 -0700 Subject: Use async http requests via tokio --- src/stackexchange.rs | 79 ++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 43 deletions(-) (limited to 'src/stackexchange.rs') diff --git a/src/stackexchange.rs b/src/stackexchange.rs index e9bc6d9..2b4da67 100644 --- a/src/stackexchange.rs +++ b/src/stackexchange.rs @@ -1,5 +1,4 @@ -use flate2::read::GzDecoder; -use reqwest::blocking::Client; +use reqwest::Client; use reqwest::Url; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -83,9 +82,10 @@ impl StackExchange { // TODO also return a future with the rest of the questions /// Search query at stack exchange and get the top answer body - pub fn search_lucky(&self, q: &str) -> Result { + pub async fn search_lucky(&self, q: &str) -> Result { let ans = self - .search_advanced(q, 1)? + .search_advanced(q, 1) + .await? .into_iter() .next() .ok_or(Error::NoResults)? @@ -99,15 +99,15 @@ impl StackExchange { } /// Search query at stack exchange and get a list of relevant questions - pub fn search(&self, q: &str) -> Result> { - self.search_advanced(q, self.config.limit) + pub async fn search(&self, q: &str) -> Result> { + self.search_advanced(q, self.config.limit).await } /// Search against the search/advanced endpoint with a given query. /// Only fetches questions that have at least one answer. /// TODO async /// TODO parallel requests over multiple sites - fn search_advanced(&self, q: &str, limit: u16) -> Result> { - let resp_body = self + async fn search_advanced(&self, q: &str, limit: u16) -> Result> { + Ok(self .client .get(stackexchange_url("search/advanced")) .header("Accepts", "application/json") @@ -120,24 +120,18 @@ impl StackExchange { ("order", "desc"), ("sort", "relevance"), ]) - .send()?; - - let gz = GzDecoder::new(resp_body); - let wrapper: ResponseWrapper = serde_json::from_reader(gz).map_err(|e| { - Error::StackExchange(format!( - "Error decoding questions from the StackExchange API: {}", - e - )) - })?; - let qs = wrapper + .send() + .await? + .json::>() + .await? .items .into_iter() .map(|mut q| { + // TODO parallelize this (and preprocess stuff too) q.answers.sort_unstable_by_key(|a| -a.score); q }) - .collect(); - Ok(qs) + .collect()) } fn get_default_opts(&self) -> HashMap<&str, &str> { @@ -163,10 +157,10 @@ impl LocalStorage { } // TODO inform user if we are downloading - pub fn sites(&mut self) -> Result<&Vec> { + pub async fn sites(&mut self) -> Result<&Vec> { // Stop once Option ~ Some or Result ~ Err if self.sites.is_none() && !self.fetch_local_sites()? { - self.fetch_remote_sites()?; + self.fetch_remote_sites().await?; } match &self.sites { Some(sites) if sites.is_empty() => Err(Error::EmptySites), @@ -175,13 +169,14 @@ impl LocalStorage { } } - pub fn update_sites(&mut self) -> Result<()> { - self.fetch_remote_sites() + pub async fn update_sites(&mut self) -> Result<()> { + self.fetch_remote_sites().await } - pub fn validate_site(&mut self, site_code: &str) -> Result { + pub async fn validate_site(&mut self, site_code: &str) -> Result { Ok(self - .sites()? + .sites() + .await? .iter() .any(|site| site.api_site_parameter == *site_code)) } @@ -198,23 +193,21 @@ impl LocalStorage { } // TODO decide whether or not I should give LocalStorage an api key.. - fn fetch_remote_sites(&mut self) -> Result<()> { - let resp_body = Client::new() - .get(stackexchange_url("sites")) - .header("Accepts", "application/json") - .query(&[ - ("pagesize", SE_SITES_PAGESIZE.to_string()), - ("page", "1".to_string()), - ]) - .send()?; - let gz = GzDecoder::new(resp_body); - let wrapper: ResponseWrapper = serde_json::from_reader(gz).map_err(|e| { - Error::StackExchange(format!( - "Error decoding sites from the StackExchange API: {}", - e - )) - })?; - self.sites = Some(wrapper.items); + async fn fetch_remote_sites(&mut self) -> Result<()> { + self.sites = Some( + Client::new() + .get(stackexchange_url("sites")) + .header("Accepts", "application/json") + .query(&[ + ("pagesize", SE_SITES_PAGESIZE.to_string()), + ("page", "1".to_string()), + ]) + .send() + .await? + .json::>() + .await? + .items, + ); self.store_local_sites() } -- cgit v1.2.3