From: Simon Tatham Date: Sun, 31 Dec 2023 11:26:32 +0000 (+0000) Subject: Reorganise startup to pass in a config location. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=7e3b6a63126cf76c95c94c8961cc89ba12fb4e2b;p=mastodonochrome.git Reorganise startup to pass in a config location. This begins to set up for specifying a non-default one on the command line, which I'm going to need in order to start doing testing that depends on a local test Mastodon instance. --- diff --git a/src/auth.rs b/src/auth.rs index 3cfae97..098db84 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; -use xdg::BaseDirectories; + +use super::config::ConfigLocation; #[derive(Debug)] pub enum AuthError { @@ -34,14 +35,8 @@ pub struct AuthConfig { } impl AuthConfig { - pub fn load() -> Result { - let xdg_dirs = match BaseDirectories::with_prefix("mastodonochrome") { - Err(e) => Err(AuthError::Bad( - format!("unable to get config directory: {}", e))), - Ok(d) => Ok(d), - }?; - - let authfile = xdg_dirs.get_config_file("auth"); + pub fn load(cfgloc: &ConfigLocation) -> Result { + let authfile = cfgloc.get_path("auth"); let authdata = match std::fs::read_to_string(&authfile) { Err(e) => Err(AuthError::Nonexistent( format!("unable to read config file '{}': {}", diff --git a/src/client.rs b/src/client.rs index de523db..6a366c2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet, VecDeque}; use std::io::Read; use super::auth::{AuthConfig,AuthError}; +use super::config::ConfigLocation; use super::types::*; #[derive(Hash, Debug, PartialEq, Eq, Clone, Copy)] @@ -150,9 +151,9 @@ pub enum FeedExtend { } impl Client { - pub fn new() -> Result { + pub fn new(cfgloc: &ConfigLocation) -> Result { Ok(Client { - auth: AuthConfig::load()?, + auth: AuthConfig::load(cfgloc)?, client: reqwest::blocking::Client::new(), accounts: HashMap::new(), statuses: HashMap::new(), diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..549ae0d --- /dev/null +++ b/src/config.rs @@ -0,0 +1,39 @@ +use std::path::PathBuf; + +#[derive(Debug)] +pub enum ConfigError { + XDG(xdg::BaseDirectoriesError), +} + +impl std::fmt::Display for ConfigError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> + Result<(), std::fmt::Error> + { + match self { + ConfigError::XDG(e) => { e.fmt(f) }, + } + } +} + +impl From for ConfigError { + fn from(err: xdg::BaseDirectoriesError) -> Self { + ConfigError::XDG(err) + } +} + +pub struct ConfigLocation { + dir: PathBuf, +} + +impl ConfigLocation { + pub fn default() -> Result { + let base_dirs = xdg::BaseDirectories::with_prefix("mastodonochrome")?; + Ok(ConfigLocation { + dir: base_dirs.get_config_home(), + }) + } + + pub fn get_path(&self, leaf: &str) -> PathBuf { + self.dir.join(leaf) + } +} diff --git a/src/lib.rs b/src/lib.rs index 0b185a4..9acfb73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod types; pub mod auth; +pub mod config; pub mod html; pub mod scan_re; pub mod coloured_string; diff --git a/src/main.rs b/src/main.rs index 3ac0e40..4a2cfd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,46 @@ -use std::io::Write; -use std::io::stderr; +use std::fmt::Display; use std::process::ExitCode; -use mastodonochrome::tui::Tui; +use mastodonochrome::config::{ConfigLocation, ConfigError}; +use mastodonochrome::tui::{Tui, TuiError}; + +#[derive(Debug)] +pub struct TopLevelError { + message: String, +} + +impl Display for TopLevelError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> + Result<(), std::fmt::Error> + { + write!(f, "mastodonochrome: error: {}", self.message) + } +} + +trait TopLevelErrorCandidate: Display {} + +impl From for TopLevelError { + fn from(err: E) -> Self { + TopLevelError { + message: err.to_string(), + } + } +} + +impl TopLevelErrorCandidate for ConfigError {} +impl TopLevelErrorCandidate for TuiError {} + +fn main_inner() -> Result<(), TopLevelError> { + let cfgloc = ConfigLocation::default()?; + Tui::run(&cfgloc)?; + Ok(()) +} fn main() -> ExitCode { - match Tui::run() { + match main_inner() { Ok(_) => ExitCode::from(0), Err(e) => { - let _ = writeln!(&mut stderr(), "mastodonochrome: error: {}", e); + let _ = eprintln!("{}", e); ExitCode::from(1) } } diff --git a/src/tui.rs b/src/tui.rs index 5fd893d..6f78573 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -17,6 +17,7 @@ use unicode_width::UnicodeWidthStr; use super::activity_stack::*; use super::client::{Client, ClientError, FeedId, StreamId, StreamUpdate}; use super::coloured_string::{ColouredString, ColouredStringSlice}; +use super::config::ConfigLocation; use super::menu::*; use super::file::*; use super::auth::AuthError; @@ -192,12 +193,7 @@ impl std::fmt::Display for TuiError { } impl Tui { - pub fn run() -> Result<(), TuiError> { - stdout().execute(EnterAlternateScreen)?; - enable_raw_mode()?; - let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; - terminal.clear()?; - + pub fn run(cfgloc: &ConfigLocation) -> Result<(), TuiError> { let (sender, receiver) = std::sync::mpsc::sync_channel(1); let input_sender = sender.clone(); @@ -211,7 +207,12 @@ impl Tui { } }); - let client = Client::new()?; + let client = Client::new(cfgloc)?; + + stdout().execute(EnterAlternateScreen)?; + enable_raw_mode()?; + let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; + terminal.clear()?; let mut tui = Tui { terminal: terminal, @@ -221,22 +222,7 @@ impl Tui { client: client, }; - { - let sender = tui.subthread_sender.clone(); - tui.client.start_streaming_thread( - &StreamId::User, Box::new(move |update| { - if let Err(_) = sender.send( - SubthreadEvent::StreamEv(update)) { - // It would be nice to do something about this - // error, but what _can_ we do? We can hardly send - // an error notification back to the main thread, - // because that communication channel is just what - // we've had a problem with. - } - }))?; - } - - let result = tui.main_loop(); + let result = tui.run_inner(); disable_raw_mode()?; stdout().execute(LeaveAlternateScreen)?; @@ -294,6 +280,25 @@ impl Tui { } } + fn run_inner(&mut self) -> Result<(), TuiError> { + { + let sender = self.subthread_sender.clone(); + self.client.start_streaming_thread( + &StreamId::User, Box::new(move |update| { + if let Err(_) = sender.send( + SubthreadEvent::StreamEv(update)) { + // It would be nice to do something about this + // error, but what _can_ we do? We can hardly send + // an error notification back to the main thread, + // because that communication channel is just what + // we've had a problem with. + } + }))?; + } + + self.main_loop() + } + fn main_loop(&mut self) -> Result<(), TuiError> { 'outer: loop { let state = &mut self.state;