diff options
author | Thang Pham <phamducthang1234@gmail.com> | 2021-12-15 02:11:34 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-14 12:11:34 -0500 |
commit | 78ba9882c7bd8d95675345181a781b91781c9bf9 (patch) | |
tree | 037629769c48271506453d0f0207fdb22b42be36 | |
parent | be6b431b975839e15bf703beee2bab7348095bac (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.md | 2 | ||||
-rw-r--r-- | hackernews_tui/src/client/mod.rs | 169 | ||||
-rw-r--r-- | hackernews_tui/src/view/comment_view.rs | 5 |
3 files changed, 89 insertions, 87 deletions
@@ -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() { |