From 33eb0c71f866a5b3b1fda71a818808c4c7e0ffdb Mon Sep 17 00:00:00 2001 From: Jez Cope Date: Sat, 3 Jul 2021 16:49:54 +0100 Subject: [PATCH] Improve error handling with anyhow --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/commands.rs | 36 +++++++++++++++++++++++++----------- src/main.rs | 7 +++++-- src/session.rs | 17 +++++++++++++---- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16350cb..d672487 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anyhow" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" + [[package]] name = "assign" version = "1.1.1" @@ -1218,6 +1224,7 @@ dependencies = [ name = "mxadm" version = "0.1.0" dependencies = [ + "anyhow", "clap", "directories", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index fe5ae25..fb65645 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ serde = "1.0" serde-lexpr = "0.1.0" directories = "3.0" lazy_static = "1.4.0" +anyhow = "1.0.41" diff --git a/src/commands.rs b/src/commands.rs index eb140b7..99b0a11 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,3 +1,4 @@ +use anyhow::{Context, Result}; use matrix_sdk::{ ruma::{api::client::r0::alias, RoomAliasId, RoomId, UserId}, Client, Session, SyncSettings, @@ -8,7 +9,7 @@ use std::io::{self, Write}; use crate::session::{build_client_config, restore_session, save_session}; -type CommandResult = Result<(), Box>; +type CommandResult = Result<()>; macro_rules! room_fmt { () => { @@ -18,7 +19,8 @@ macro_rules! room_fmt { pub async fn login(username: Option<&str>) -> CommandResult { let user_id = match username { - Some(s) => UserId::try_from(s)?, + Some(s) => UserId::try_from(s) + .with_context(|| format!("Failed to parse '{}' as User ID", username))?, None => { let mut s = String::new(); @@ -27,17 +29,20 @@ pub async fn login(username: Option<&str>) -> CommandResult { let stdin = io::stdin(); stdin.read_line(&mut s)?; - UserId::try_from(s.trim_end())? + UserId::try_from(s.trim_end()) + .with_context(|| format!("Failed to parse '{}' as User ID", s))? } }; let password = prompt_password_stderr("Password: ")?; - let client = - Client::new_from_user_id_with_config(user_id.clone(), build_client_config()).await?; + let client = Client::new_from_user_id_with_config(user_id.clone(), build_client_config()) + .await + .context("Unable to initialise client")?; let response = client .login(user_id.localpart(), &password, None, Some("mxadm")) - .await?; + .await + .context("Login failed")?; println!( "{} logged in? {}", client.homeserver().await, @@ -81,7 +86,10 @@ pub async fn list_rooms() -> CommandResult { print!("Syncing..."); io::stderr().flush().unwrap(); - client.sync_once(sync_settings).await?; + client + .sync_once(sync_settings) + .await + .context("Sync failed")?; println!(" done"); println!("Joined rooms:"); @@ -100,8 +108,10 @@ pub async fn list_rooms() -> CommandResult { } pub async fn add_alias(room_id: &str, alias: &str) -> CommandResult { - let room_id = RoomId::try_from(room_id)?; - let alias_id = RoomAliasId::try_from(alias)?; + let room_id = RoomId::try_from(room_id) + .with_context(|| format!("Failed to parse '{}' as room ID", room_id))?; + let alias_id = RoomAliasId::try_from(alias) + .with_context(|| format!("Failed to parse '{}' as room alias", alias))?; let client = restore_session().await?; let request = alias::create_alias::Request::new(&alias_id, &room_id); @@ -111,11 +121,15 @@ pub async fn add_alias(room_id: &str, alias: &str) -> CommandResult { } pub async fn del_alias(alias: &str) -> CommandResult { - let alias_id = RoomAliasId::try_from(alias)?; + let alias_id = RoomAliasId::try_from(alias) + .with_context(|| format!("Failed to parse '{}' as room alias", alias))?; let client = restore_session().await?; let request = alias::delete_alias::Request::new(&alias_id); - client.send(request, None).await?; + client + .send(request, None) + .await + .with_context(|| format!("Failed to delete alias '{}'", alias))?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 523af0f..673e61f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,14 +2,17 @@ extern crate clap; #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate anyhow; mod commands; mod session; +use anyhow::Result; use clap::{App, SubCommand}; #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> Result<()> { let matches = App::new(crate_name!()) .version(crate_version!()) .about(crate_description!()) @@ -55,7 +58,7 @@ async fn main() -> Result<(), Box> { ("del-alias", Some(submatches)) => { commands::del_alias(submatches.value_of("alias").unwrap()).await? } - ("", None) => eprintln!("No subcommand given"), + ("", None) => bail!("No subcommand given"), (c, _) => { todo!("Subcommand '{}' not implemented yet!", c); } diff --git a/src/session.rs b/src/session.rs index 4df994b..e50a36d 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,7 +1,9 @@ +use anyhow::{Context, Result}; use directories::ProjectDirs; use matrix_sdk::{Client, ClientConfig, Session}; use serde_lexpr; use std::fs::{create_dir_all, File}; +use std::io::ErrorKind; lazy_static! { static ref PROJECT_DIRS: ProjectDirs = ProjectDirs::from("me", "petrichor", "mxadm") @@ -13,18 +15,25 @@ pub fn build_client_config() -> ClientConfig { ClientConfig::new().store_path(PROJECT_DIRS.cache_dir().join("store")) } -pub fn save_session(session: Session) -> Result<(), Box> { +pub fn save_session(session: Session) -> Result<()> { let cache_dir = PROJECT_DIRS.cache_dir(); if !cache_dir.exists() { - create_dir_all(cache_dir)?; + create_dir_all(cache_dir) + .with_context(|| format!("Failed to create cache directory {}", cache_dir.display()))?; } let mut session_file = File::create(cache_dir.join(SESSION_FILE))?; serde_lexpr::to_writer(&mut session_file, &session)?; Ok(()) } -pub async fn restore_session() -> Result> { - let session_file = File::open(PROJECT_DIRS.cache_dir().join(SESSION_FILE))?; +pub async fn restore_session() -> Result { + let session_file = match File::open(PROJECT_DIRS.cache_dir().join(SESSION_FILE)) { + Err(e) => match e.kind() { + ErrorKind::NotFound => bail!("Session file not found: try `mxadm login` first"), + _ => return Err(e).context("Unable to open session file"), + }, + Ok(f) => f, + }; let session_info: Session = serde_lexpr::from_reader(session_file)?; let client =