[fractal] Return errors without conversion



commit b1d7311bb22746672e7ab0221bd8a7594c0abdb9
Author: Alejandro Domínguez <adomu net-c com>
Date:   Sun Jul 12 03:17:52 2020 +0200

    Return errors without conversion

 fractal-gtk/src/appop/user.rs        |   9 +-
 fractal-gtk/src/backend/directory.rs |  23 +--
 fractal-gtk/src/backend/media.rs     |  20 ++-
 fractal-gtk/src/backend/mod.rs       |  56 +++++--
 fractal-gtk/src/backend/register.rs  |  23 ++-
 fractal-gtk/src/backend/room.rs      | 302 +++++++++++++++++++----------------
 fractal-gtk/src/backend/user.rs      | 193 +++++++++++-----------
 fractal-gtk/src/error.rs             |   5 +-
 8 files changed, 346 insertions(+), 285 deletions(-)
---
diff --git a/fractal-gtk/src/appop/user.rs b/fractal-gtk/src/appop/user.rs
index 33bef69e..ab37b1f4 100644
--- a/fractal-gtk/src/appop/user.rs
+++ b/fractal-gtk/src/appop/user.rs
@@ -3,7 +3,6 @@ use gtk::prelude::*;
 use crate::backend::{user, HandleError};
 use glib::clone;
 
-use std::path::PathBuf;
 use std::thread;
 
 use crate::app::App;
@@ -32,8 +31,8 @@ impl AppOp {
         }));
 
         thread::spawn(clone!(@strong login_data => move || {
-            match user::get_avatar(login_data.server_url, login_data.uid) {
-                Ok(path) => {
+            match user::get_user_avatar(login_data.server_url, &login_data.uid) {
+                Ok((_, path)) => {
                     APPOP!(set_avatar, (path));
                 }
                 Err(err) => {
@@ -146,10 +145,10 @@ impl AppOp {
         });
     }
 
-    pub fn set_avatar(&mut self, path: PathBuf) {
+    pub fn set_avatar(&mut self, path: String) {
         let login_data = unwrap_or_unit_return!(self.login_data.clone());
         self.set_login_data(LoginData {
-            avatar: Some(path),
+            avatar: Some(path.into()),
             ..login_data
         });
     }
diff --git a/fractal-gtk/src/backend/directory.rs b/fractal-gtk/src/backend/directory.rs
index 3fbb8b67..8515ec23 100644
--- a/fractal-gtk/src/backend/directory.rs
+++ b/fractal-gtk/src/backend/directory.rs
@@ -1,9 +1,8 @@
-use fractal_api::url::{Host, Url};
+use fractal_api::reqwest::Error as ReqwestError;
+use fractal_api::url::{Host, ParseError as UrlError, Url};
 
 use crate::globals;
 
-use crate::error::Error;
-
 use crate::backend::HTTP_CLIENT;
 use crate::util::cache_dir_path;
 
@@ -28,8 +27,8 @@ use crate::APPOP;
 #[derive(Debug)]
 pub struct DirectoryProtocolsError;
 
-impl<T: Into<Error>> From<T> for DirectoryProtocolsError {
-    fn from(_: T) -> Self {
+impl From<ReqwestError> for DirectoryProtocolsError {
+    fn from(_: ReqwestError) -> Self {
         Self
     }
 }
@@ -57,11 +56,14 @@ pub fn protocols(
 }
 
 #[derive(Debug)]
-pub struct DirectorySearchError;
+pub enum DirectorySearchError {
+    InvalidHomeserverUrl(UrlError),
+    Reqwest(ReqwestError),
+}
 
-impl<T: Into<Error>> From<T> for DirectorySearchError {
-    fn from(_: T) -> Self {
-        Self
+impl From<ReqwestError> for DirectorySearchError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
@@ -97,7 +99,8 @@ pub fn room_search(
                 .unwrap_or_else(|| Host::parse(&hs))
                 .map(Some)
         })
-        .unwrap_or(Ok(None))?;
+        .unwrap_or(Ok(None))
+        .map_err(DirectorySearchError::InvalidHomeserverUrl)?;
 
     let params = PublicRoomsParameters {
         access_token,
diff --git a/fractal-gtk/src/backend/media.rs b/fractal-gtk/src/backend/media.rs
index 9b46553a..a88fe1e7 100644
--- a/fractal-gtk/src/backend/media.rs
+++ b/fractal-gtk/src/backend/media.rs
@@ -1,7 +1,7 @@
 use super::MediaError;
-use crate::error::Error;
 use crate::globals;
-use fractal_api::identifiers::{EventId, RoomId};
+use fractal_api::identifiers::{Error as IdError, EventId, RoomId};
+use fractal_api::reqwest::Error as ReqwestError;
 use fractal_api::url::Url;
 use std::sync::mpsc::Sender;
 
@@ -72,13 +72,24 @@ pub fn get_media_list_async(
     });
 }
 
+enum GetRoomMediaListError {
+    Reqwest(ReqwestError),
+    EventsDeserialization(IdError),
+}
+
+impl From<ReqwestError> for GetRoomMediaListError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
+    }
+}
+
 fn get_room_media_list(
     baseu: Url,
     access_token: AccessToken,
     room_id: &RoomId,
     limit: u64,
     prev_batch: String,
-) -> Result<MediaList, Error> {
+) -> Result<MediaList, GetRoomMediaListError> {
     let params = GetMessagesEventsParams {
         access_token,
         from: prev_batch,
@@ -97,7 +108,8 @@ fn get_room_media_list(
 
     let prev_batch = response.end.unwrap_or_default();
     let evs = response.chunk.iter().rev();
-    let media_list = Message::from_json_events_iter(room_id, evs)?;
+    let media_list = Message::from_json_events_iter(room_id, evs)
+        .map_err(GetRoomMediaListError::EventsDeserialization)?;
 
     Ok((media_list, prev_batch))
 }
diff --git a/fractal-gtk/src/backend/mod.rs b/fractal-gtk/src/backend/mod.rs
index 23d5910c..af2f8499 100644
--- a/fractal-gtk/src/backend/mod.rs
+++ b/fractal-gtk/src/backend/mod.rs
@@ -1,14 +1,16 @@
 use fractal_api::identifiers::{EventId, RoomId};
-use fractal_api::url::Url;
+use fractal_api::reqwest::Error as ReqwestError;
+use fractal_api::url::{ParseError as UrlError, Url};
 use lazy_static::lazy_static;
 use log::error;
 use regex::Regex;
 use std::fmt::Debug;
 use std::fs::write;
-use std::io::Read;
+use std::io::{Error as IoError, Read};
 use std::path::Path;
 use std::sync::{Arc, Condvar, Mutex};
 use std::thread;
+use std::time::SystemTimeError;
 
 use crate::client::Client;
 use crate::error::Error;
@@ -100,7 +102,7 @@ pub fn get_prev_batch_from(
     access_token: AccessToken,
     room_id: &RoomId,
     event_id: &EventId,
-) -> Result<String, Error> {
+) -> Result<String, ReqwestError> {
     let params = GetContextParameters {
         access_token,
         limit: 0,
@@ -115,11 +117,29 @@ pub fn get_prev_batch_from(
 }
 
 #[derive(Debug)]
-pub struct MediaError(pub(self) Error);
+pub enum MediaError {
+    InvalidMxcUrl(Option<UrlError>),
+    InvalidDownloadPath(Error),
+    Reqwest(ReqwestError),
+    Io(IoError),
+    SystemTime(SystemTimeError),
+}
 
-impl<T: Into<Error>> From<T> for MediaError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for MediaError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
+    }
+}
+
+impl From<IoError> for MediaError {
+    fn from(err: IoError) -> Self {
+        Self::Io(err)
+    }
+}
+
+impl From<SystemTimeError> for MediaError {
+    fn from(err: SystemTimeError) -> Self {
+        Self::SystemTime(err)
     }
 }
 
@@ -131,18 +151,21 @@ pub fn dw_media(
     media_type: ContentType,
     dest: Option<String>,
 ) -> Result<String, MediaError> {
-    let mxc_url = Url::parse(mxc)?;
+    let mxc_url = Url::parse(mxc).map_err(|url_err| MediaError::InvalidMxcUrl(Some(url_err)))?;
 
     if mxc_url.scheme() != "mxc" {
-        return Err(MediaError(Error::BackendError));
+        return Err(MediaError::InvalidMxcUrl(None));
     }
 
-    let server = mxc_url.host().ok_or(Error::BackendError)?.to_owned();
+    let server = mxc_url
+        .host()
+        .ok_or(MediaError::InvalidMxcUrl(None))?
+        .to_owned();
     let media_id = mxc_url
         .path_segments()
         .and_then(|mut ps| ps.next())
         .filter(|s| !s.is_empty())
-        .ok_or(Error::BackendError)?;
+        .ok_or(MediaError::InvalidMxcUrl(None))?;
 
     let request = if let ContentType::Thumbnail(width, height) = media_type {
         let params = GetContentThumbnailParameters {
@@ -158,10 +181,11 @@ pub fn dw_media(
     }?;
 
     let fname = match dest {
-        None if media_type.is_thumbnail() => cache_dir_path(Some("thumbs"), &media_id)?,
-        None => cache_dir_path(Some("medias"), &media_id)?,
-        Some(ref d) => d.clone(),
-    };
+        None if media_type.is_thumbnail() => cache_dir_path(Some("thumbs"), &media_id),
+        None => cache_dir_path(Some("medias"), &media_id),
+        Some(ref d) => Ok(d.clone()),
+    }
+    .map_err(MediaError::InvalidDownloadPath)?;
 
     let fpath = Path::new(&fname);
 
@@ -175,7 +199,7 @@ pub fn dw_media(
             .get_client()
             .execute(request)?
             .bytes()
-            .collect::<Result<Vec<u8>, std::io::Error>>()
+            .collect::<Result<Vec<u8>, IoError>>()
             .and_then(|media| write(&fname, media))
             .and(Ok(fname))
             .map_err(Into::into)
diff --git a/fractal-gtk/src/backend/register.rs b/fractal-gtk/src/backend/register.rs
index c99c45b2..bc739401 100644
--- a/fractal-gtk/src/backend/register.rs
+++ b/fractal-gtk/src/backend/register.rs
@@ -1,8 +1,7 @@
 use fractal_api::identifiers::{DeviceId, UserId};
+use fractal_api::reqwest::Error as ReqwestError;
 use fractal_api::url::Url;
 
-use crate::error::Error;
-
 use crate::actions::AppState;
 use crate::backend::HTTP_CLIENT;
 use crate::globals;
@@ -27,8 +26,8 @@ use crate::APPOP;
 #[derive(Debug)]
 pub struct LoginError;
 
-impl<T: Into<Error>> From<T> for LoginError {
-    fn from(_: T) -> Self {
+impl From<ReqwestError> for LoginError {
+    fn from(_: ReqwestError) -> Self {
         Self
     }
 }
@@ -78,11 +77,11 @@ pub fn login(
 }
 
 #[derive(Debug)]
-pub struct LogoutError(Error);
+pub struct LogoutError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for LogoutError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for LogoutError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -97,12 +96,8 @@ pub fn logout(server: Url, access_token: AccessToken) -> Result<(), LogoutError>
     Ok(())
 }
 
-pub fn get_well_known(domain: Url) -> Result<DomainInfoResponse, Error> {
+pub fn get_well_known(domain: Url) -> Result<DomainInfoResponse, ReqwestError> {
     let request = domain_info(domain)?;
 
-    HTTP_CLIENT
-        .get_client()
-        .execute(request)?
-        .json()
-        .map_err(Into::into)
+    HTTP_CLIENT.get_client().execute(request)?.json()
 }
diff --git a/fractal-gtk/src/backend/room.rs b/fractal-gtk/src/backend/room.rs
index 970f3c9f..5ff84740 100644
--- a/fractal-gtk/src/backend/room.rs
+++ b/fractal-gtk/src/backend/room.rs
@@ -2,14 +2,15 @@ use log::error;
 use serde_json::json;
 
 use fractal_api::identifiers::{Error as IdError, EventId, RoomId, UserId};
+use fractal_api::reqwest::Error as ReqwestError;
 use fractal_api::url::Url;
 use std::fs;
+use std::io::Error as IoError;
 
 use std::collections::HashMap;
 use std::convert::TryFrom;
 use std::time::Duration;
 
-use crate::error::Error;
 use crate::globals;
 
 use crate::actions::AppState;
@@ -84,11 +85,14 @@ use crate::i18n::i18n;
 use crate::APPOP;
 
 #[derive(Debug)]
-pub struct RoomDetailError(Error);
+pub enum RoomDetailError {
+    MalformedKey,
+    Reqwest(ReqwestError),
+}
 
-impl<T: Into<Error>> From<T> for RoomDetailError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for RoomDetailError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
@@ -98,25 +102,25 @@ pub fn get_room_detail(
     base: Url,
     access_token: AccessToken,
     room_id: RoomId,
-    keys: String,
+    key: String,
 ) -> Result<(RoomId, String, String), RoomDetailError> {
+    let k = key.split('.').last().ok_or(RoomDetailError::MalformedKey)?;
     let params = GetStateEventsForKeyParameters { access_token };
 
-    let request = get_state_events_for_key(base, &params, &room_id, &keys)?;
+    let request = get_state_events_for_key(base, &params, &room_id, &key)?;
     let response: JsonValue = HTTP_CLIENT.get_client().execute(request)?.json()?;
 
-    let k = keys.split('.').last().ok_or(Error::BackendError)?;
     let value = response[&k].as_str().map(Into::into).unwrap_or_default();
 
-    Ok((room_id, keys, value))
+    Ok((room_id, key, value))
 }
 
 #[derive(Debug)]
-pub struct RoomAvatarError(Error);
+pub struct RoomAvatarError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for RoomAvatarError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for RoomAvatarError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -129,40 +133,29 @@ pub fn get_room_avatar(
 ) -> Result<(RoomId, Option<Url>), RoomAvatarError> {
     let params = GetStateEventsForKeyParameters { access_token };
 
-    get_state_events_for_key(base.clone(), &params, &room_id, "m.room.avatar")
-        .map_err(Into::into)
-        .and_then(|request| {
-            let response = HTTP_CLIENT
-                .get_client()
-                .execute(request)?
-                .json::<JsonValue>()?;
-
-            let avatar = response["url"].as_str().and_then(|s| Url::parse(s).ok());
-            let dest = cache_dir_path(None, &room_id.to_string()).ok();
-            if let Some(ref avatar) = avatar {
-                let _ = dw_media(
-                    base,
-                    avatar.as_str(),
-                    ContentType::default_thumbnail(),
-                    dest,
-                );
-            }
+    let request = get_state_events_for_key(base.clone(), &params, &room_id, "m.room.avatar")?;
+    let response: JsonValue = HTTP_CLIENT.get_client().execute(request)?.json()?;
 
-            Ok((room_id.clone(), avatar))
-        })
-        .or_else(|err| match err {
-            Error::MatrixError(errcode, _) if errcode == "M_NOT_FOUND" => Ok((room_id, None)),
-            error => Err(error),
-        })
-        .map_err(Into::into)
+    let avatar = response["url"].as_str().and_then(|s| Url::parse(s).ok());
+    let dest = cache_dir_path(None, &room_id.to_string()).ok();
+    if let Some(ref avatar) = avatar {
+        let _ = dw_media(
+            base,
+            avatar.as_str(),
+            ContentType::default_thumbnail(),
+            dest,
+        );
+    }
+
+    Ok((room_id, avatar))
 }
 
 #[derive(Debug)]
-pub struct RoomMembersError(Error);
+pub struct RoomMembersError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for RoomMembersError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for RoomMembersError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -184,11 +177,15 @@ pub fn get_room_members(
 }
 
 #[derive(Debug)]
-pub struct RoomMessagesToError(Error);
+pub enum RoomMessagesToError {
+    MessageNotSent,
+    Reqwest(ReqwestError),
+    EventsDeserialization(IdError),
+}
 
-impl<T: Into<Error>> From<T> for RoomMessagesToError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for RoomMessagesToError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
@@ -220,7 +217,8 @@ pub fn get_room_messages(
 
     let prev_batch = response.end;
     let evs = response.chunk.iter().rev();
-    let list = Message::from_json_events_iter(&room_id, evs)?;
+    let list = Message::from_json_events_iter(&room_id, evs)
+        .map_err(RoomMessagesToError::EventsDeserialization)?;
 
     Ok((list, room_id, prev_batch))
 }
@@ -231,7 +229,7 @@ pub fn get_room_messages_from_msg(
     room_id: RoomId,
     msg: Message,
 ) -> Result<(Vec<Message>, RoomId, Option<String>), RoomMessagesToError> {
-    let event_id = msg.id.as_ref().ok_or(Error::BackendError)?;
+    let event_id = msg.id.as_ref().ok_or(RoomMessagesToError::MessageNotSent)?;
 
     // first of all, we calculate the from param using the context api, then we call the
     // normal get_room_messages
@@ -287,7 +285,6 @@ pub fn send_msg(
     let txn_id = msg.get_txn_id();
 
     create_message_event(base, &params, &body, &room_id, "m.room.message", &txn_id)
-        .map_err::<Error, _>(Into::into)
         .and_then(|request| {
             let response = HTTP_CLIENT
                 .get_client()
@@ -300,11 +297,11 @@ pub fn send_msg(
 }
 
 #[derive(Debug)]
-pub struct SendTypingError(Error);
+pub struct SendTypingError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for SendTypingError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for SendTypingError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -326,10 +323,20 @@ pub fn send_typing(
 }
 
 #[derive(Debug)]
-pub struct SendMsgRedactionError;
+pub enum SendMsgRedactionError {
+    MessageNotSent,
+    Reqwest(ReqwestError),
+}
+
+impl From<ReqwestError> for SendMsgRedactionError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
+    }
+}
 
 impl HandleError for SendMsgRedactionError {
     fn handle_error(&self) {
+        error!("Error deleting message: {:?}", self);
         let error = i18n("Error deleting message");
         APPOP!(show_error, (error));
     }
@@ -342,7 +349,10 @@ pub fn redact_msg(
 ) -> Result<(EventId, Option<EventId>), SendMsgRedactionError> {
     let room_id = &msg.room;
     let txn_id = msg.get_txn_id();
-    let event_id = msg.id.clone().ok_or(SendMsgRedactionError)?;
+    let event_id = msg
+        .id
+        .as_ref()
+        .ok_or(SendMsgRedactionError::MessageNotSent)?;
 
     let params = RedactEventParameters { access_token };
 
@@ -350,25 +360,18 @@ pub fn redact_msg(
         reason: "Deletion requested by the sender".into(),
     };
 
-    redact_event(base, &params, &body, room_id, &event_id, &txn_id)
-        .map_err::<Error, _>(Into::into)
-        .and_then(|request| {
-            let response = HTTP_CLIENT
-                .get_client()
-                .execute(request)?
-                .json::<RedactEventResponse>()?;
+    let request = redact_event(base, &params, &body, room_id, event_id, &txn_id)?;
+    let response: RedactEventResponse = HTTP_CLIENT.get_client().execute(request)?.json()?;
 
-            Ok((event_id.clone(), response.event_id))
-        })
-        .or(Err(SendMsgRedactionError))
+    Ok((event_id.clone(), response.event_id))
 }
 
 #[derive(Debug)]
-pub struct JoinRoomError(Error);
+pub struct JoinRoomError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for JoinRoomError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for JoinRoomError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -405,11 +408,11 @@ pub fn join_room(
 }
 
 #[derive(Debug)]
-pub struct LeaveRoomError(Error);
+pub struct LeaveRoomError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for LeaveRoomError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for LeaveRoomError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -429,11 +432,11 @@ pub fn leave_room(
 }
 
 #[derive(Debug)]
-pub struct MarkedAsReadError(Error);
+pub struct MarkedAsReadError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for MarkedAsReadError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for MarkedAsReadError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -458,11 +461,11 @@ pub fn mark_as_read(
     Ok((room_id, event_id))
 }
 #[derive(Debug)]
-pub struct SetRoomNameError(Error);
+pub struct SetRoomNameError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for SetRoomNameError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for SetRoomNameError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -487,11 +490,11 @@ pub fn set_room_name(
 }
 
 #[derive(Debug)]
-pub struct SetRoomTopicError(Error);
+pub struct SetRoomTopicError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for SetRoomTopicError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for SetRoomTopicError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -516,17 +519,23 @@ pub fn set_room_topic(
 }
 
 #[derive(Debug)]
-pub struct SetRoomAvatarError(Error);
+pub enum SetRoomAvatarError {
+    Io(IoError),
+    Reqwest(ReqwestError),
+}
 
-impl<T: Into<Error>> From<T> for SetRoomAvatarError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for SetRoomAvatarError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
 impl From<AttachedFileError> for SetRoomAvatarError {
     fn from(err: AttachedFileError) -> Self {
-        Self(err.0)
+        match err {
+            AttachedFileError::Io(err) => Self::Io(err),
+            AttachedFileError::Reqwest(err) => Self::Reqwest(err),
+        }
     }
 }
 
@@ -552,11 +561,20 @@ pub fn set_room_avatar(
 }
 
 #[derive(Debug)]
-pub struct AttachedFileError(Error);
+pub enum AttachedFileError {
+    Io(IoError),
+    Reqwest(ReqwestError),
+}
+
+impl From<ReqwestError> for AttachedFileError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
+    }
+}
 
-impl<T: Into<Error>> From<T> for AttachedFileError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<IoError> for AttachedFileError {
+    fn from(err: IoError) -> Self {
+        Self::Io(err)
     }
 }
 
@@ -598,11 +616,11 @@ pub enum RoomType {
 }
 
 #[derive(Debug)]
-pub struct NewRoomError(Error);
+pub struct NewRoomError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for NewRoomError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for NewRoomError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -650,13 +668,41 @@ pub fn new_room(
     })
 }
 
+#[derive(Debug)]
+pub enum DirectChatError {
+    Reqwest(ReqwestError),
+    EventsDeserialization(IdError),
+}
+
+impl From<ReqwestError> for DirectChatError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
+    }
+}
+
+impl HandleError for DirectChatError {
+    fn handle_error(&self) {
+        error!("Can't set m.direct: {:?}", self);
+        let err_str = format!("{:?}", self);
+        error!(
+            "{}",
+            remove_matrix_access_token_if_present(&err_str).unwrap_or(err_str)
+        );
+
+        let error = i18n("Can’t create the room, try again");
+        let state = AppState::NoRoom;
+        APPOP!(show_error, (error));
+        APPOP!(set_state, (state));
+    }
+}
+
 fn update_direct_chats(
     base: Url,
     access_token: AccessToken,
     user_id: UserId,
     room_id: RoomId,
     user: Member,
-) -> Result<(), Error> {
+) -> Result<(), DirectChatError> {
     let params = GetGlobalAccountDataParameters {
         access_token: access_token.clone(),
     };
@@ -677,7 +723,8 @@ fn update_direct_chats(
                 .collect::<Result<Vec<RoomId>, IdError>>()?;
             Ok((UserId::try_from(uid.as_str())?, roomlist))
         })
-        .collect::<Result<HashMap<UserId, Vec<RoomId>>, IdError>>()?;
+        .collect::<Result<HashMap<UserId, Vec<RoomId>>, IdError>>()
+        .map_err(DirectChatError::EventsDeserialization)?;
 
     if let Some(v) = directs.get_mut(&user.uid) {
         v.push(room_id);
@@ -698,7 +745,7 @@ pub fn direct_chat(
     access_token: AccessToken,
     user_id: UserId,
     user: Member,
-) -> Result<Room, NewRoomError> {
+) -> Result<Room, DirectChatError> {
     let params = CreateRoomParameters {
         access_token: access_token.clone(),
     };
@@ -720,18 +767,13 @@ pub fn direct_chat(
     let request = create_room(base.clone(), &params, &body)?;
     let response: CreateRoomResponse = HTTP_CLIENT.get_client().execute(request)?.json()?;
 
-    let directs = update_direct_chats(
+    update_direct_chats(
         base,
         access_token,
         user_id,
         response.room_id.clone(),
         user.clone(),
-    );
-
-    if let Err(err) = directs {
-        error!("Can't set m.direct: {:?}", err);
-        return Err(NewRoomError(err));
-    }
+    )?;
 
     Ok(Room {
         name: user.alias,
@@ -741,11 +783,11 @@ pub fn direct_chat(
 }
 
 #[derive(Debug)]
-pub struct AddedToFavError(Error);
+pub struct AddedToFavError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for AddedToFavError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for AddedToFavError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -773,11 +815,11 @@ pub fn add_to_fav(
 }
 
 #[derive(Debug)]
-pub struct InviteError(Error);
+pub struct InviteError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for InviteError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for InviteError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -799,11 +841,11 @@ pub fn invite(
 }
 
 #[derive(Debug)]
-pub struct ChangeLanguageError(Error);
+pub struct ChangeLanguageError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for ChangeLanguageError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for ChangeLanguageError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -828,28 +870,16 @@ pub fn set_language(
 
     let body = json!(Language { input_language });
 
-    let response = set_room_account_data(
+    let request = set_room_account_data(
         base,
         &params,
         &body,
         &user_id,
         &room_id,
         "org.gnome.fractal.language",
-    )
-    .map_err(Into::into)
-    .and_then(|request| {
-        let _ = HTTP_CLIENT.get_client().execute(request)?;
+    )?;
 
-        Ok(())
-    });
-
-    // FIXME: Manage errors in the AppOp loop
-    if let Err(ref err) = response {
-        error!(
-            "Matrix failed to set room language with error code: {:?}",
-            err
-        );
-    }
+    HTTP_CLIENT.get_client().execute(request)?;
 
-    response
+    Ok(())
 }
diff --git a/fractal-gtk/src/backend/user.rs b/fractal-gtk/src/backend/user.rs
index 004be50e..32a59799 100644
--- a/fractal-gtk/src/backend/user.rs
+++ b/fractal-gtk/src/backend/user.rs
@@ -1,13 +1,14 @@
 use fractal_api::identifiers::UserId;
-use fractal_api::url::Url;
+use fractal_api::reqwest::Error as ReqwestError;
+use fractal_api::url::{ParseError as UrlError, Url};
 use std::fs;
+use std::io::Error as IoError;
 
 use super::MediaError;
 use crate::actions::global::activate_action;
 use crate::backend::ThreadPool;
 use crate::backend::HTTP_CLIENT;
 use crate::cache::CacheMap;
-use crate::error::Error;
 use crate::util::cache_dir_path;
 use crate::util::ResultExpectLog;
 use log::error;
@@ -80,11 +81,11 @@ use crate::APPOP;
 pub type UserInfo = (String, String);
 
 #[derive(Debug)]
-pub struct NameError(Error);
+pub struct NameError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for NameError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for NameError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -108,13 +109,11 @@ pub fn get_username_async(base: Url, access_token: AccessToken, uid: UserId) ->
     let params = GetDisplayNameParameters { access_token };
 
     get_display_name(base, &params, &uid)
-        .map_err::<Error, _>(Into::into)
         .and_then(|request| {
             HTTP_CLIENT
                 .get_client()
                 .execute(request)?
                 .json::<GetDisplayNameResponse>()
-                .map_err(Into::into)
         })
         .ok()
         .and_then(|response| response.displayname)
@@ -122,11 +121,11 @@ pub fn get_username_async(base: Url, access_token: AccessToken, uid: UserId) ->
 }
 
 #[derive(Debug)]
-pub struct SetUserNameError(Error);
+pub struct SetUserNameError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for SetUserNameError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for SetUserNameError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -152,8 +151,8 @@ pub fn set_username(
 #[derive(Debug)]
 pub struct GetThreePIDError;
 
-impl<T: Into<Error>> From<T> for GetThreePIDError {
-    fn from(_: T) -> Self {
+impl From<ReqwestError> for GetThreePIDError {
+    fn from(_: ReqwestError) -> Self {
         Self
     }
 }
@@ -183,14 +182,15 @@ pub fn get_threepid(
 
 #[derive(Debug)]
 pub enum GetTokenEmailError {
+    IdentityServerUrl(UrlError),
+    Reqwest(ReqwestError),
     TokenUsed,
     Denied,
-    Other(Error),
 }
 
-impl<T: Into<Error>> From<T> for GetTokenEmailError {
-    fn from(err: T) -> Self {
-        Self::Other(err.into())
+impl From<ReqwestError> for GetTokenEmailError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
@@ -205,7 +205,7 @@ impl HandleError for GetTokenEmailError {
                 let error = i18n("Please enter a valid email address.");
                 APPOP!(show_error_dialog_in_settings, (error));
             }
-            Self::Other(err) => {
+            Self::Reqwest(err) => {
                 let error = i18n("Couldn’t add the email address.");
                 let err_str = format!("{:?}", err);
                 error!(
@@ -214,6 +214,11 @@ impl HandleError for GetTokenEmailError {
                 );
                 APPOP!(show_error_dialog_in_settings, (error));
             }
+            Self::IdentityServerUrl(err) => {
+                let error = i18n("The identity server is invalid.");
+                error!("The identity server is invalid: {:?}", err);
+                APPOP!(show_error_dialog_in_settings, (error));
+            }
         }
     }
 }
@@ -229,7 +234,9 @@ pub fn get_email_token(
 
     let params = EmailTokenParameters { access_token };
     let body = EmailTokenBody {
-        id_server: identity.try_into()?,
+        id_server: identity
+            .try_into()
+            .map_err(GetTokenEmailError::IdentityServerUrl)?,
         client_secret: client_secret.clone(),
         email,
         send_attempt: 1,
@@ -251,14 +258,15 @@ pub fn get_email_token(
 
 #[derive(Debug)]
 pub enum GetTokenPhoneError {
+    IdentityServerUrl(UrlError),
+    Reqwest(ReqwestError),
     TokenUsed,
     Denied,
-    Other(Error),
 }
 
-impl<T: Into<Error>> From<T> for GetTokenPhoneError {
-    fn from(err: T) -> Self {
-        Self::Other(err.into())
+impl From<ReqwestError> for GetTokenPhoneError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
@@ -275,7 +283,7 @@ impl HandleError for GetTokenPhoneError {
                 );
                 APPOP!(show_error_dialog_in_settings, (error));
             }
-            Self::Other(err) => {
+            Self::Reqwest(err) => {
                 let error = i18n("Couldn’t add the phone number.");
                 let err_str = format!("{:?}", err);
                 error!(
@@ -284,6 +292,11 @@ impl HandleError for GetTokenPhoneError {
                 );
                 APPOP!(show_error_dialog_in_settings, (error));
             }
+            Self::IdentityServerUrl(err) => {
+                let error = i18n("The identity server is invalid.");
+                error!("The identity server is invalid: {:?}", err);
+                APPOP!(show_error_dialog_in_settings, (error));
+            }
         }
     }
 }
@@ -292,16 +305,18 @@ pub fn get_phone_token(
     base: Url,
     access_token: AccessToken,
     identity: Url,
-    phone: String,
+    phone_number: String,
     client_secret: String,
 ) -> Result<(String, String), GetTokenPhoneError> {
     use PhoneTokenResponse::*;
 
     let params = PhoneTokenParameters { access_token };
     let body = PhoneTokenBody {
-        id_server: identity.try_into()?,
+        id_server: identity
+            .try_into()
+            .map_err(GetTokenPhoneError::IdentityServerUrl)?,
         client_secret: client_secret.clone(),
-        phone_number: phone,
+        phone_number,
         country: String::new(),
         send_attempt: 1,
         next_link: None,
@@ -321,11 +336,14 @@ pub fn get_phone_token(
 }
 
 #[derive(Debug)]
-pub struct AddedToFavError(Error);
+pub enum AddedToFavError {
+    IdentityServerUrl(UrlError),
+    Reqwest(ReqwestError),
+}
 
-impl<T: Into<Error>> From<T> for AddedToFavError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for AddedToFavError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
@@ -341,7 +359,9 @@ pub fn add_threepid(
     let params = AddThreePIDParameters { access_token };
     let body = AddThreePIDBody {
         three_pid_creds: ThreePIDCredentials {
-            id_server: identity.try_into()?,
+            id_server: identity
+                .try_into()
+                .map_err(AddedToFavError::IdentityServerUrl)?,
             sid,
             client_secret,
         },
@@ -355,11 +375,11 @@ pub fn add_threepid(
 }
 
 #[derive(Debug)]
-pub struct SubmitPhoneTokenError(Error);
+pub struct SubmitPhoneTokenError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for SubmitPhoneTokenError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for SubmitPhoneTokenError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -384,11 +404,11 @@ pub fn submit_phone_token(
 }
 
 #[derive(Debug)]
-pub struct DeleteThreePIDError(Error);
+pub struct DeleteThreePIDError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for DeleteThreePIDError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for DeleteThreePIDError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -410,11 +430,11 @@ pub fn delete_three_pid(
 }
 
 #[derive(Debug)]
-pub struct ChangePasswordError(Error);
+pub struct ChangePasswordError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for ChangePasswordError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for ChangePasswordError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -454,11 +474,11 @@ pub fn change_password(
 }
 
 #[derive(Debug)]
-pub struct AccountDestructionError(Error);
+pub struct AccountDestructionError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for AccountDestructionError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for AccountDestructionError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -496,34 +516,20 @@ pub fn account_destruction(
 }
 
 #[derive(Debug)]
-pub struct AvatarError(Error);
-
-impl<T: Into<Error>> From<T> for AvatarError {
-    fn from(err: T) -> Self {
-        Self(err.into())
-    }
+pub enum SetUserAvatarError {
+    Io(IoError),
+    Reqwest(ReqwestError),
 }
 
-impl From<GetUserAvatarError> for AvatarError {
-    fn from(err: GetUserAvatarError) -> Self {
-        Self(err.0)
+impl From<IoError> for SetUserAvatarError {
+    fn from(err: IoError) -> Self {
+        Self::Io(err)
     }
 }
 
-impl HandleError for AvatarError {}
-
-pub fn get_avatar(base: Url, userid: UserId) -> Result<PathBuf, AvatarError> {
-    get_user_avatar(base, &userid)
-        .map(|(_, fname)| fname.into())
-        .map_err(Into::into)
-}
-
-#[derive(Debug)]
-pub struct SetUserAvatarError(Error);
-
-impl<T: Into<Error>> From<T> for SetUserAvatarError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for SetUserAvatarError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
@@ -583,11 +589,11 @@ pub fn get_user_info_async(
 }
 
 #[derive(Debug)]
-pub struct UserSearchError(Error);
+pub struct UserSearchError(ReqwestError);
 
-impl<T: Into<Error>> From<T> for UserSearchError {
-    fn from(err: T) -> Self {
-        Self(err.into())
+impl From<ReqwestError> for UserSearchError {
+    fn from(err: ReqwestError) -> Self {
+        Self(err)
     }
 }
 
@@ -610,33 +616,26 @@ pub fn search(
     Ok(response.results.into_iter().map(Into::into).collect())
 }
 
-pub struct GetUserAvatarError(Error);
-
-impl<T: Into<Error>> From<T> for GetUserAvatarError {
-    fn from(err: T) -> Self {
-        Self(err.into())
-    }
+#[derive(Debug)]
+pub enum GetUserAvatarError {
+    Reqwest(ReqwestError),
+    Download(MediaError),
 }
 
-impl From<MediaError> for GetUserAvatarError {
-    fn from(err: MediaError) -> Self {
-        Self(err.0)
+impl From<ReqwestError> for GetUserAvatarError {
+    fn from(err: ReqwestError) -> Self {
+        Self::Reqwest(err)
     }
 }
 
+impl HandleError for GetUserAvatarError {}
+
 pub fn get_user_avatar(
     base: Url,
     user_id: &UserId,
 ) -> Result<(String, String), GetUserAvatarError> {
-    let response = get_profile(base.clone(), user_id)
-        .map_err::<Error, _>(Into::into)
-        .and_then(|request| {
-            HTTP_CLIENT
-                .get_client()
-                .execute(request)?
-                .json::<GetProfileResponse>()
-                .map_err(Into::into)
-        })?;
+    let request = get_profile(base.clone(), user_id)?;
+    let response: GetProfileResponse = HTTP_CLIENT.get_client().execute(request)?.json()?;
 
     let name = response
         .displayname
@@ -646,7 +645,8 @@ pub fn get_user_avatar(
     let img = response
         .avatar_url
         .map(|url| {
-            let dest = cache_dir_path(None, &user_id.to_string())?;
+            let dest = cache_dir_path(None, &user_id.to_string())
+                .map_err(MediaError::InvalidDownloadPath)?;
             dw_media(
                 base,
                 url.as_str(),
@@ -654,7 +654,8 @@ pub fn get_user_avatar(
                 Some(dest),
             )
         })
-        .unwrap_or_else(|| Ok(Default::default()))?;
+        .unwrap_or_else(|| Ok(Default::default()))
+        .map_err(GetUserAvatarError::Download)?;
 
     Ok((name, img))
 }
diff --git a/fractal-gtk/src/error.rs b/fractal-gtk/src/error.rs
index 15982fe9..6c87ffac 100644
--- a/fractal-gtk/src/error.rs
+++ b/fractal-gtk/src/error.rs
@@ -1,7 +1,5 @@
-use std::io;
-use std::time::SystemTimeError;
-
 use serde::Deserialize;
+use std::io;
 
 #[derive(Clone, Debug, Deserialize)]
 pub struct StandardErrorResponse {
@@ -47,5 +45,4 @@ derror!(fractal_api::url::ParseError, Error::BackendError);
 derror!(io::Error, Error::BackendError);
 derror!(glib::error::Error, Error::BackendError);
 derror!(fractal_api::identifiers::Error, Error::BackendError);
-derror!(SystemTimeError, Error::BackendError);
 derror!(serde_json::Error, Error::CacheError);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]