From 846a6f8b425669c49db46d57b421fca9de892920 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 26 Jan 2024 08:52:14 +0000 Subject: [PATCH] Store a log of errors in the Client. Each entry is a ClientError and a datestamp. But errors generated in the client don't _automatically_ get added to this log: they get passed back to the caller of an individual Client method, the same as they always have. That way the caller can decide whether the error is one it can handle in some other way, and only if all else fails, call client.add_to_error_log(). The next plan is for every client.add_to_error_log() to be followed by throwing the TUI into the Error Log file. --- src/client.rs | 34 ++++++++++++++++++++++++++++++++++ src/editor.rs | 14 ++++++++------ src/posting.rs | 6 +++++- src/tui.rs | 20 ++++++++++++++++---- 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/client.rs b/src/client.rs index 88afc89..98e1acf 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use reqwest::Url; use std::collections::{HashMap, HashSet, VecDeque}; use std::fs::File; @@ -61,6 +62,33 @@ pub struct Feed { extend_future: Option>, } +#[derive(Debug)] +pub struct ErrorLog { + items: VecDeque<(ClientError, DateTime)>, + origin: isize, +} + +impl ErrorLog { + fn new() -> Self { + ErrorLog { + items: VecDeque::new(), + origin: 0, // FIXME: eventually prune these at the front + } + } + + pub fn push_now(&mut self, error: ClientError) { + self.items.push_back((error, Utc::now())); + } + + pub fn get_bounds(&self) -> (isize, isize) { + (self.origin, self.origin + self.items.len() as isize) + } + + pub fn get(&self, index: isize) -> (ClientError, DateTime) { + self.items[(index - self.origin) as usize].clone() + } +} + #[derive(Debug, PartialEq, Eq, Clone)] pub enum Followness { NotFollowing, @@ -118,6 +146,7 @@ pub struct Client { instance: Option, permit_write: bool, logfile: Option, + error_log: ErrorLog, } #[derive(Debug, PartialEq, Eq, Clone)] @@ -520,6 +549,7 @@ impl Client { instance: None, permit_write: false, logfile: None, + error_log: ErrorLog::new(), }) } @@ -1741,4 +1771,8 @@ impl Client { Err(ClientError::from_response(urlstr, rsp)) } } + + pub fn add_to_error_log(&mut self, err: ClientError) { + self.error_log.push_now(err); + } } diff --git a/src/editor.rs b/src/editor.rs index 9f1fbe4..7c2834c 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -950,9 +950,10 @@ pub fn get_user_to_examine() -> Box { ), // FIXME: it would be nice to discriminate errors - // better here, and maybe return anything worse - // than 'user not found' to the Error Log - Err(_) => LogicalAction::PopOverlayBeep, + // better here, and do something a bit less + // terrifying for plain "account not found", like + // allowing the user to re-edit + Err(err) => LogicalAction::Error(err), } } }), @@ -973,9 +974,10 @@ pub fn get_post_id_to_read() -> Box { ), // FIXME: it would be nice to discriminate errors - // better here, and maybe return anything worse - // than 'post not found' to the Error Log - Err(_) => LogicalAction::PopOverlayBeep, + // better here, and do something a bit less + // terrifying for plain "status not found", like + // allowing the user to re-edit + Err(err) => LogicalAction::Error(err), } } }), diff --git a/src/posting.rs b/src/posting.rs index 79ae0d9..e4d5155 100644 --- a/src/posting.rs +++ b/src/posting.rs @@ -252,7 +252,11 @@ impl PostMenu { match client.post_status(&self.post) { Ok(_) => LogicalAction::Pop, - Err(_) => LogicalAction::Beep, // FIXME: report the error! + + // FIXME: if we can identify errors of the form "refusal + // to post because of something the user can reasonably + // fix", we should stay in this menu and let them retry + Err(err) => LogicalAction::Error(err), } } } diff --git a/src/tui.rs b/src/tui.rs index dfe2ddd..1d1c36b 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -530,8 +530,11 @@ impl Tui { vec![Todo::Stream(feeds_updated)] } - // FIXME: errors here should go in the Error Log - _ => Vec::new(), + Err(err) => { + self.client.add_to_error_log(err); + // FIXME: throw user into the Error Log + Vec::new() + } } } Ok(SubthreadEvent::LDBCheckpointTimer) => { @@ -807,7 +810,10 @@ impl TuiLogicalState { self.pop_overlay_activity(); self.activity_state_mut().got_search_expression(dir, regex) } - LogicalAction::Error(_) => break PhysicalAction::Beep, // FIXME: Error Log + LogicalAction::Error(err) => { + client.add_to_error_log(err); + break PhysicalAction::Beep; + } LogicalAction::PostComposed(post) => { let newact = match self.activity_stack.top() { Activity::Compose( @@ -1098,7 +1104,13 @@ impl TuiLogicalState { } }; - result.expect("FIXME: need to implement the Error Log here") + match result { + Ok(state) => state, + Err(err) => { + client.add_to_error_log(err); + panic!("FIXME: need to implement the Error Log here"); + } + } } fn save_ldb(&self) -> Result<(), TuiError> { -- 2.30.2