summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThang Pham <phamducthang1234@gmail.com>2021-12-15 02:11:34 +0900
committerGitHub <noreply@github.com>2021-12-14 12:11:34 -0500
commit78ba9882c7bd8d95675345181a781b91781c9bf9 (patch)
tree037629769c48271506453d0f0207fdb22b42be36
parentbe6b431b975839e15bf703beee2bab7348095bac (diff)
Add a client logger (#53)
## Brief description of changes - add a client logger to record API response time - preserve the initial comment order in `Client::load_comments` - limit the number of updated comments in each `CommentView::try_update_comments` call
-rw-r--r--README.md2
-rw-r--r--hackernews_tui/src/client/mod.rs169
-rw-r--r--hackernews_tui/src/view/comment_view.rs5
3 files changed, 89 insertions, 87 deletions
diff --git a/README.md b/README.md
index 0966144..b943348 100644
--- a/README.md
+++ b/README.md
@@ -139,7 +139,7 @@ List of demo videos:
## Default Shortcuts
-In each `View`, press `?` to see a list of supported keyboard shortcuts and their functionalities:
+In each `View`, press `?` to see a list of supported keyboard shortcuts and their functionalities. Note that the shortcuts are fully [customizable](#user-defined-shortcuts).
![Example of a Help View](https://raw.githubusercontent.com/aome510/hackernews-TUI/main/examples/assets/help_view.png)
diff --git a/hackernews_tui/src/client/mod.rs b/hackernews_tui/src/client/mod.rs
index c966a79..1dc9c20 100644
--- a/hackernews_tui/src/client/mod.rs
+++ b/hackernews_tui/src/client/mod.rs
@@ -27,6 +27,17 @@ pub struct HNClient {
client: ureq::Agent,
}
+macro_rules! log {
+ ($e:expr, $desc:expr) => {{
+ let time = std::time::SystemTime::now();
+ let result = $e;
+ if let Ok(elapsed) = time.elapsed() {
+ info!("{} took {}ms", $desc, elapsed.as_millis());
+ }
+ result
+ }};
+}
+
impl HNClient {
/// Create a new Hacker News Client
pub fn new() -> Result<HNClient> {
@@ -45,22 +56,24 @@ impl HNClient {
T: serde::de::DeserializeOwned,
{
let request_url = format!("{}/items/{}", HN_ALGOLIA_PREFIX, id);
- let time = std::time::SystemTime::now();
- let item = self.client.get(&request_url).call()?.into_json::<T>()?;
- if let Ok(elapsed) = time.elapsed() {
- info!("get item id={} took {}ms", id, elapsed.as_millis());
- }
+ let item = log!(
+ self.client.get(&request_url).call()?.into_json::<T>()?,
+ format!("get HN item (id={}) using {}", id, request_url)
+ );
Ok(item)
}
+
/// Lazily load a story's comments
pub fn lazy_load_story_comments(&self, story_id: u32) -> Result<CommentReceiver> {
let request_url = format!("{}/item/{}.json", HN_OFFICIAL_PREFIX, story_id);
- let mut ids = self
- .client
- .get(&request_url)
- .call()?
- .into_json::<HNStoryResponse>()?
- .kids;
+ let mut ids = log!(
+ self.client
+ .get(&request_url)
+ .call()?
+ .into_json::<HNStoryResponse>()?
+ .kids,
+ format!("get story (id={}) using {}", story_id, request_url)
+ );
let (sender, receiver) = crossbeam_channel::bounded(32);
let client = self.clone();
@@ -92,21 +105,23 @@ impl HNClient {
return Ok(());
}
- ids.drain(0..size)
+ let responses = ids
+ .drain(0..size)
.collect::<Vec<_>>()
.into_par_iter()
- .map(|id| {
- match client.get_item_from_id::<CommentResponse>(id) {
- Ok(response) => {
- sender.send(response.into())?;
- }
- Err(err) => {
- warn!("failed to get comment with id={}: {}", id, err);
- }
- };
- Ok(())
+ .map(|id| match client.get_item_from_id::<CommentResponse>(id) {
+ Ok(response) => Some(response),
+ Err(err) => {
+ warn!("failed to get comment (id={}): {}", id, err);
+ None
+ }
})
- .collect::<Result<_>>()?;
+ .flatten()
+ .collect::<Vec<_>>();
+
+ for response in responses {
+ sender.send(response.into())?;
+ }
Ok(())
}
@@ -114,15 +129,13 @@ impl HNClient {
/// Get a story based on its id
pub fn get_story_from_story_id(&self, id: u32) -> Result<Story> {
let request_url = format!("{}/search?tags=story,story_{}", HN_ALGOLIA_PREFIX, id);
- let time = std::time::SystemTime::now();
- let response = self
- .client
- .get(&request_url)
- .call()?
- .into_json::<StoriesResponse>()?;
- if let Ok(elapsed) = time.elapsed() {
- info!("get story (id={}) took {}ms", id, elapsed.as_millis());
- }
+ let response = log!(
+ self.client
+ .get(&request_url)
+ .call()?
+ .into_json::<StoriesResponse>()?,
+ format!("get story (id={}) using {}", id, request_url)
+ );
let stories: Vec<Story> = response.into();
Ok(stories.first().unwrap().clone())
@@ -144,22 +157,17 @@ impl HNClient {
search_story_limit,
page
);
- let time = std::time::SystemTime::now();
- let response = self
- .client
- .get(&request_url)
- .query("query", query)
- .call()?
- .into_json::<StoriesResponse>()?;
- if let Ok(elapsed) = time.elapsed() {
- info!(
- "get matched stories with query {} (by_date={}, page={}) took {}ms",
- query,
- by_date,
- page,
- elapsed.as_millis()
- );
- }
+ let response = log!(
+ self.client
+ .get(&request_url)
+ .query("query", query)
+ .call()?
+ .into_json::<StoriesResponse>()?,
+ format!(
+ "get matched stories with query {} (by_date={}, page={}) using {}",
+ query, by_date, page, request_url
+ )
+ );
Ok(response.into())
}
@@ -198,19 +206,13 @@ impl HNClient {
numeric_filters: query::StoryNumericFilters,
) -> Result<Vec<Story>> {
let request_url = format!("{}/topstories.json", HN_OFFICIAL_PREFIX);
- let time = std::time::SystemTime::now();
- let stories = self
- .client
- .get(&request_url)
- .call()?
- .into_json::<Vec<u32>>()?;
- if let Ok(elapsed) = time.elapsed() {
- info!(
- "get front_page story ids using {} took {}ms",
- request_url,
- elapsed.as_millis()
- );
- }
+ let stories = log!(
+ self.client
+ .get(&request_url)
+ .call()?
+ .into_json::<Vec<u32>>()?,
+ format!("get front page stories using {}", request_url)
+ );
let start_id = story_limit * page;
if start_id >= stories.len() {
@@ -231,18 +233,16 @@ impl HNClient {
numeric_filters.query(),
);
- let response = self
- .client
- .get(&request_url)
- .call()?
- .into_json::<StoriesResponse>()?;
- if let Ok(elapsed) = time.elapsed() {
- info!(
- "get stories (tag=front_page, by_date=false, page={}) took {}ms",
- page,
- elapsed.as_millis()
- );
- }
+ let response = log!(
+ self.client
+ .get(&request_url)
+ .call()?
+ .into_json::<StoriesResponse>()?,
+ format!(
+ "get stories (tag=front_page, by_date=false, page={}) using {}",
+ page, request_url
+ )
+ );
Ok(self.reoder_front_page_stories(response.into(), ids))
}
@@ -273,21 +273,20 @@ impl HNClient {
numeric_filters.query(),
);
- let time = std::time::SystemTime::now();
- let response = self
- .client
- .get(&request_url)
- .call()?
- .into_json::<StoriesResponse>()?;
- if let Ok(elapsed) = time.elapsed() {
- info!(
- "get stories (tag={}, by_date={}, page={}) took {}ms",
+ let response = log!(
+ self.client
+ .get(&request_url)
+ .call()?
+ .into_json::<StoriesResponse>()?,
+ format!(
+ "get stories (tag={}, by_date={}, page={}, numeric_filters={}) using {}",
tag,
by_date,
page,
- elapsed.as_millis()
- );
- }
+ numeric_filters.query(),
+ request_url
+ )
+ );
Ok(response.into())
}
diff --git a/hackernews_tui/src/view/comment_view.rs b/hackernews_tui/src/view/comment_view.rs
index b78d286..55b466c 100644
--- a/hackernews_tui/src/view/comment_view.rs
+++ b/hackernews_tui/src/view/comment_view.rs
@@ -36,10 +36,13 @@ impl CommentView {
/// then update the internal comment data accordingly.
pub fn try_update_comments(&mut self) {
let mut new_comments = vec![];
- while !self.receiver.is_empty() {
+ // limit the number of top comments updated each time
+ let mut limit = 5;
+ while !self.receiver.is_empty() && limit > 0 {
if let Ok(mut comments) = self.receiver.try_recv() {
new_comments.append(&mut comments);
}
+ limit -= 1;
}
if new_comments.is_empty() {