daydream

A small matrix web client written in rust
git clone git://archive.git.mtrnord.blog/daydream-mx/daydream.git
Log | Files | Refs | README | LICENSE

commit 09c82b01c23c8f36a0d7fb247ee76b63a7911477
parent 94108195cdffce537bc2180563a9c6a530b7829b
Author: Marcel <mtrnord1@gmail.com>
Date:   Sat,  4 Jul 2020 12:30:27 +0200

Move login logic to a seperate file

Took 2 hours 42 minutes

Diffstat:
Asrc/app/matrix/login.rs | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/app/matrix/mod.rs | 269+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/app/mod.rs | 2+-
Msrc/errors.rs | 5+++++
4 files changed, 185 insertions(+), 166 deletions(-)

diff --git a/src/app/matrix/login.rs b/src/app/matrix/login.rs @@ -0,0 +1,75 @@ +use crate::errors::{Field, MatrixError}; +use log::*; +use matrix_sdk::{Client, ClientConfig, Session}; +use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; +use url::Url; +use wasm_bindgen_futures::spawn_local; + +#[derive(Serialize, Deserialize, Default, Clone, Debug)] +pub struct SessionStore { + pub(crate) access_token: String, + pub(crate) user_id: String, + pub(crate) device_id: String, + pub(crate) homeserver_url: String, +} + +pub fn login( + session: Option<&SessionStore>, + homeserver: Option<&String>, +) -> Result<Client, MatrixError> { + info!("preparing client"); + match session { + Some(session) => restore_client(session), + None => match homeserver { + Some(homeserver) => { + let homeserver = Url::parse(&homeserver); + match homeserver { + Ok(homeserver) => { + let client_config = ClientConfig::new(); + let client = Client::new_with_config(homeserver, client_config).unwrap(); + Ok(client) + } + Err(e) => Err(MatrixError::UrlParseError(e.to_string())), + } + } + None => Err(MatrixError::MissingFields(Field::Homeserver)), + }, + } +} + +fn restore_client(session: &SessionStore) -> Result<Client, MatrixError> { + let homeserver = Url::parse(&session.homeserver_url); + match homeserver { + Ok(homeserver) => { + let client_config = ClientConfig::new(); + let client = Client::new_with_config(homeserver, client_config); + match client { + Ok(client) => { + info!("got client"); + // Also directly restore Login data + let session = Session { + access_token: session.access_token.clone(), + user_id: matrix_sdk::identifiers::UserId::try_from( + session.user_id.as_str(), + ) + .unwrap(), + device_id: session.device_id.clone(), + }; + info!("before restore"); + let cloned_client = client.clone(); + spawn_local(async move { + if let Err(e) = cloned_client.restore_login(session).await { + error!("{}", e); + // TODO find a way to get this back up in the function tree + } + }); + info!("after restore"); + Ok(client) + } + Err(e) => Err(MatrixError::SDKError(e.to_string())), + } + } + Err(e) => Err(MatrixError::UrlParseError(e.to_string())), + } +} diff --git a/src/app/matrix/mod.rs b/src/app/matrix/mod.rs @@ -1,5 +1,4 @@ use std::collections::HashSet; -use std::convert::TryFrom; use std::sync::Arc; use log::*; @@ -16,17 +15,18 @@ use matrix_sdk::{ identifiers::RoomId, js_int::UInt, locks::RwLock, - Client, ClientConfig, MessagesRequestBuilder, Room, Session, + Client, MessagesRequestBuilder, Room, }; use pulldown_cmark::{html, Options, Parser}; use serde::{Deserialize, Serialize}; -use url::Url; use wasm_bindgen_futures::spawn_local; use yew::worker::*; use crate::app::matrix::types::{get_media_download_url, get_video_media_download_url}; -use crate::errors::{Field, MatrixError}; +use crate::errors::MatrixError; +use login::{login, SessionStore}; +pub mod login; mod sync; pub mod types; @@ -37,14 +37,6 @@ pub struct MatrixClient { pub(crate) password: Option<String>, } -#[derive(Serialize, Deserialize, Default, Clone, Debug)] -pub struct SessionStore { - pub(crate) access_token: String, - pub(crate) user_id: String, - pub(crate) device_id: String, - pub(crate) homeserver_url: String, -} - #[derive(Clone, Debug)] pub struct MatrixAgent { link: AgentLink<MatrixAgent>, @@ -134,117 +126,124 @@ impl Agent for MatrixAgent { } Request::Login => { info!("Starting Login"); - let login_client = self.login(); - if login_client.is_none() { - for sub in self.subscribers.iter() { - let resp = Response::Error(MatrixError::MissingClient); - self.link.respond(*sub, resp); - } - return; - } - let client = login_client.unwrap(); - let username = self.matrix_state.username.clone().unwrap(); - let password = self.matrix_state.password.clone().unwrap(); - let subscribers = self.subscribers.clone(); - let agent = self.clone(); - spawn_local(async move { - // TODO handle login error - if agent.session.is_some() { - let stored_session = agent.session.unwrap(); - let session = Session { - access_token: stored_session.access_token, - user_id: matrix_sdk::identifiers::UserId::try_from( - stored_session.user_id.as_str(), - ) - .unwrap(), - device_id: stored_session.device_id, - }; - client.restore_login(session).await; - } else { - // FIXME gracefully handle login errors - let login_response = client - .login(username, password, None, Some("Daydream".to_string())) - .await; - match login_response { - Ok(login_response) => { - let session_store = SessionStore { - access_token: login_response.access_token, - user_id: login_response.user_id.to_string(), - device_id: login_response.device_id, - homeserver_url: client.homeserver().to_string(), - }; - for sub in subscribers.iter() { - let resp = Response::SaveSession(session_store.clone()); - agent.link.respond(*sub, resp); - let resp = Response::LoggedIn(true); - agent.link.respond(*sub, resp); - } + let homeserver = self.matrix_state.homeserver.as_ref(); + let session = self.session.as_ref(); + let client = login(session, homeserver); + match client { + Ok(client) => { + if let Some(_session) = session { + for sub in self.subscribers.iter() { + let resp = Response::LoggedIn(true); + self.link.respond(*sub, resp); } - Err(e) => { - if let matrix_sdk::Error::Reqwest(e) = e { - match e.status() { - None => { - for sub in subscribers.iter() { - let resp = Response::Error(MatrixError::SDKError( - e.to_string(), - )); - agent.link.respond(*sub, resp); - } - } - Some(v) => { - if v.is_server_error() { - for sub in subscribers.iter() { - let resp = - Response::Error(MatrixError::LoginTimeout); - agent.link.respond(*sub, resp); - } - } else { - for sub in subscribers.iter() { + } + self.matrix_client = Some(client.clone()); + let username = self.matrix_state.username.clone().unwrap(); + let password = self.matrix_state.password.clone().unwrap(); + let agent = self.clone(); + spawn_local(async move { + // FIXME gracefully handle login errors + let login_response = agent + .matrix_client + .as_ref() + .unwrap() + .login(username, password, None, Some("Daydream".to_string())) + .await; + match login_response { + Ok(login_response) => { + let session_store = SessionStore { + access_token: login_response.access_token, + user_id: login_response.user_id.to_string(), + device_id: login_response.device_id, + homeserver_url: client.homeserver().to_string(), + }; + for sub in agent.subscribers.iter() { + let resp = Response::SaveSession(session_store.clone()); + agent.link.respond(*sub, resp); + let resp = Response::LoggedIn(true); + agent.link.respond(*sub, resp); + } + } + Err(e) => { + if let matrix_sdk::Error::Reqwest(e) = e { + match e.status() { + None => { + for sub in agent.subscribers.iter() { let resp = Response::Error( MatrixError::SDKError(e.to_string()), ); agent.link.respond(*sub, resp); } } + Some(v) => { + if v.is_server_error() { + for sub in agent.subscribers.iter() { + let resp = Response::Error( + MatrixError::LoginTimeout, + ); + agent.link.respond(*sub, resp); + } + } else { + for sub in agent.subscribers.iter() { + let resp = Response::Error( + MatrixError::SDKError(e.to_string()), + ); + agent.link.respond(*sub, resp); + } + } + } + } + } else { + for sub in agent.subscribers.iter() { + let resp = Response::Error(MatrixError::SDKError( + e.to_string(), + )); + agent.link.respond(*sub, resp); } - } - } else { - for sub in subscribers.iter() { - let resp = - Response::Error(MatrixError::SDKError(e.to_string())); - agent.link.respond(*sub, resp); } } } + }); + } + Err(e) => { + for sub in self.subscribers.iter() { + let resp = Response::Error(e.clone()); + self.link.respond(*sub, resp); } } - }); + } } Request::GetLoggedIn => { - let login_client = self.login(); - if login_client.is_none() { - for sub in self.subscribers.iter() { - let resp = Response::Error(MatrixError::MissingClient); - self.link.respond(*sub, resp); + let homeserver = self.matrix_state.homeserver.as_ref(); + let session = self.session.clone(); + let client = login(session.as_ref(), homeserver); + match client { + Ok(client) => { + info!("Got client"); + self.matrix_client = Some(client); + info!("Client set"); + let agent = self.clone(); + spawn_local(async move { + let logged_in = agent.get_logged_in().await; + + if !logged_in && session.is_some() { + error!("Not logged in but got session"); + } else { + for sub in agent.subscribers.iter() { + let resp = Response::LoggedIn(logged_in); + agent.link.respond(*sub, resp); + } + } + }); } - return; - } - - // Always clone agent after having tried to login! - let agent = self.clone(); - - spawn_local(async move { - let logged_in = agent.get_logged_in().await; - - if !logged_in && agent.session.is_some() { - error!("Not logged in but got session"); - } else { - for sub in agent.subscribers.iter() { - let resp = Response::LoggedIn(logged_in); - agent.link.respond(*sub, resp); + Err(e) => { + error!("Got no client: {:?}", e); + for sub in self.subscribers.iter() { + let resp = Response::Error(e.clone()); + self.link.respond(*sub, resp); } } - }); + } } Request::StartSync => { // Always clone agent after having tried to login! @@ -436,64 +435,4 @@ impl MatrixAgent { } self.matrix_client.as_ref().unwrap().logged_in().await } - - fn login(&mut self) -> Option<Client> { - info!("preparing client"); - if self.session.is_some() { - info!("restoring login"); - let homeserver = &self.session.as_ref().unwrap().homeserver_url; - - let client_config = ClientConfig::new(); - let homeserver_url = Url::parse(homeserver).unwrap(); - let client = Client::new_with_config(homeserver_url, client_config).unwrap(); - self.matrix_client = Some(client.clone()); - - info!("got client"); - // Also directly restore Login data - let stored_session = self.session.clone().unwrap(); - let session = Session { - access_token: stored_session.access_token, - user_id: matrix_sdk::identifiers::UserId::try_from(stored_session.user_id.as_str()) - .unwrap(), - device_id: stored_session.device_id, - }; - let client_clone = client.clone(); - info!("before restore"); - spawn_local(async move { - info!("before inner restore"); - client_clone.restore_login(session).await; - info!("after restore"); - }); - - Some(client) - } else if self.matrix_state.homeserver.is_none() { - for sub in self.subscribers.iter() { - let resp = Response::Error(MatrixError::MissingFields(Field::Homeserver)); - self.link.respond(*sub, resp); - } - None - } else if self.matrix_state.username.is_none() { - for sub in self.subscribers.iter() { - let resp = Response::Error(MatrixError::MissingFields(Field::MXID)); - self.link.respond(*sub, resp); - } - None - } else if self.matrix_state.password.is_none() { - for sub in self.subscribers.iter() { - let resp = Response::Error(MatrixError::MissingFields(Field::Password)); - self.link.respond(*sub, resp); - } - None - } else { - info!("new login"); - let homeserver = self.matrix_state.homeserver.clone().unwrap(); - - let client_config = ClientConfig::new(); - let homeserver_url = Url::parse(&homeserver).unwrap(); - let client = Client::new_with_config(homeserver_url, client_config).unwrap(); - self.matrix_client = Some(client.clone()); - - Some(client) - } - } } diff --git a/src/app/mod.rs b/src/app/mod.rs @@ -2,7 +2,7 @@ use yew::{prelude::*, virtual_dom::VNode}; use yew_router::agent::RouteRequest::ChangeRoute; use yew_router::{prelude::*, Switch}; -use crate::app::matrix::{MatrixAgent, Response, SessionStore}; +use crate::app::matrix::{login::SessionStore, MatrixAgent, Response}; use crate::app::views::{login::Login, main_view::MainView}; use crate::constants::AUTH_KEY; use log::*; diff --git a/src/errors.rs b/src/errors.rs @@ -36,4 +36,9 @@ pub enum MatrixError { /// This can't use transparent as we need Clone #[error("An error occurred in the Matrix client library: `{0}`")] SDKError(String), + + /// An error occurred in the URL parse library. + /// This can't use transparent as we need Serialize, Deserialize + #[error("An error occurred in the URL parse library: `{0}`")] + UrlParseError(String), }