commit b0186dad8a6b9434b12621779b626aaad435d953
parent bb4a25c3e064e56b780785c7bdd9d8c7edd07955
Author: Marcel <mtrnord1@gmail.com>
Date: Tue, 26 May 2020 14:45:22 +0200
Save access_token after login and use enum as agent response
Took 1 hour 6 minutes
Diffstat:
8 files changed, 152 insertions(+), 69 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -25,6 +25,7 @@ futures = "0.3"
matrix-sdk = { version = "0.1.0", git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false}
url = "2.1.1"
yew_styles = "0.3.1"
+thiserror = "1.0"
[dev-dependencies]
wasm-bindgen-test = "0.3"
diff --git a/src/app.rs b/src/app.rs
@@ -64,23 +64,26 @@ impl Component for App {
}
Msg::NewMessage(response) => {
info!("NewMessage: {:#?}", response);
- if response.message == "client_logged_in"{
- info!("client_logged_in");
- info!("{}", response.content);
- let route: Route = if response.content == "true" {
- //self.state.logged_in = true;
+ match response {
+ Response::Error(_) => {},
+ Response::LoggedIn(logged_in) => {
+ info!("client_logged_in");
+ info!("{}",logged_in);
+ let route: Route = if logged_in {
+ //self.state.logged_in = true;
- // replace with sync routeagent message once its possible
- // https://github.com/yewstack/yew/issues/1127
- //RouteService::new().get_route();
- AppRoute::MainView.into()
- } else {
- AppRoute::Start.into()
- };
+ // replace with sync routeagent message once its possible
+ // https://github.com/yewstack/yew/issues/1127
+ //RouteService::new().get_route();
+ AppRoute::MainView.into()
+ } else {
+ AppRoute::Start.into()
+ };
- info!("{:#?}", route.clone());
- self.route = Some(route.clone());
- self.route_agent.send(ChangeRoute(route));
+ info!("{:#?}", route.clone());
+ self.route = Some(route.clone());
+ self.route_agent.send(ChangeRoute(route));
+ },
}
}
}
diff --git a/src/app/matrix.rs b/src/app/matrix.rs
@@ -1,24 +1,42 @@
+use std::collections::HashSet;
+use std::convert::TryFrom;
+use std::sync::{Arc, Mutex};
+
use log::*;
-use matrix_sdk::{Client, ClientConfig};
+use matrix_sdk::{Client, ClientConfig, Session, Error};
use serde_derive::{Deserialize, Serialize};
-use std::collections::HashSet;
use url::Url;
use wasm_bindgen_futures::spawn_local;
+use yew::format::Json;
+use yew::services::{storage::Area, StorageService};
use yew::worker::*;
-#[derive(Serialize, Deserialize, Default, Clone)]
+use crate::constants::AUTH_KEY;
+use crate::errors::MatrixError;
+
+#[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct MatrixClient {
pub(crate) homeserver: Option<String>,
pub(crate) username: Option<String>,
pub(crate) password: Option<String>,
}
-#[derive(Clone)]
+#[derive(Serialize, Deserialize, Default, Clone, Debug)]
+pub struct SessionStore {
+ access_token: String,
+ user_id: String,
+ device_id: String,
+ homeserver_url: String,
+}
+
+#[derive(Clone, Debug)]
pub struct MatrixAgent {
link: AgentLink<MatrixAgent>,
matrix_state: MatrixClient,
matrix_client: Option<Client>,
subscribers: HashSet<HandlerId>,
+ storage: Arc<Mutex<StorageService>>,
+ session: Option<SessionStore>,
}
#[derive(Serialize, Deserialize, Debug)]
@@ -30,11 +48,10 @@ pub enum Request {
GetLoggedIn,
}
-// TODO make enum
#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct Response {
- pub message: String,
- pub content: String,
+pub enum Response {
+ Error(MatrixError),
+ LoggedIn(bool),
}
impl Agent for MatrixAgent {
@@ -44,16 +61,30 @@ impl Agent for MatrixAgent {
type Output = Response;
fn create(link: AgentLink<Self>) -> Self {
+ let storage = Arc::new(Mutex::new(StorageService::new(Area::Local).expect("storage was disabled by the user")));
+ let session: Option<SessionStore> = {
+ if let Json(Ok(restored_model)) = storage.lock().unwrap().restore(AUTH_KEY) {
+ Some(restored_model)
+ } else {
+ None
+ }
+ };
+ info!("session: {:#?}", session);
MatrixAgent {
link,
matrix_state: Default::default(),
matrix_client: None,
subscribers: HashSet::new(),
+ storage,
+ session,
}
}
fn update(&mut self, _: Self::Message) {}
+ fn connected(&mut self, id: HandlerId) {
+ self.subscribers.insert(id);
+ }
fn handle_input(&mut self, msg: Self::Input, _: HandlerId) {
match msg {
Request::SetHomeserver(homeserver) => {
@@ -68,10 +99,7 @@ impl Agent for MatrixAgent {
Request::Login() => {
let login_client = self.login();
if login_client.is_none() {
- let resp = Response {
- message: "login_missing_client".to_string(),
- content: "".to_string(),
- };
+ let resp = Response::Error(MatrixError::MissingClient);
for sub in self.subscribers.iter() {
self.link.respond(*sub, resp.clone());
}
@@ -84,21 +112,38 @@ impl Agent for MatrixAgent {
let password = password.clone();
let client = client.clone();
let subscribers = self.subscribers.clone();
- let agent = self.clone();
+ let mut agent = self.clone();
spawn_local(async move {
- client
- .login(
- username.clone(),
- password.clone(),
- None,
- Some("Daydream".to_string()),
- )
- .await;
+ // TODO handle login error
+ if agent.session.is_some() {
+ let stored_session = agent.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,
+ };
+ client.restore_login(session).await;
+ } else {
+ let login_response: matrix_sdk::api::r0::session::login::Response = client
+ .login(
+ username.clone(),
+ password.clone(),
+ None,
+ Some("Daydream".to_string()),
+ )
+ .await.unwrap();
+ 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().clone().into_string(),
+ };
+ let mut storage = agent.storage.lock().unwrap();
+ storage.store(AUTH_KEY, Json(&session_store));
+ }
+
info!("did login");
- let resp = Response {
- message: "client_logged_in".to_string(),
- content: "true".to_string(),
- };
+ let resp = Response::LoggedIn(true);
info!("prepared login response");
for sub in subscribers.iter() {
agent.link.respond(*sub, resp.clone());
@@ -108,23 +153,33 @@ impl Agent for MatrixAgent {
}
Request::GetLoggedIn => {
let subscribers = self.subscribers.clone();
+ let login_client = self.login();
+ if login_client.is_none() {
+ let resp = Response::Error(MatrixError::MissingClient);
+ for sub in self.subscribers.iter() {
+ self.link.respond(*sub, resp.clone());
+ }
+ 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;
- let resp = Response {
- message: "client_logged_in".to_string(),
- content: logged_in,
- };
- for sub in subscribers.iter() {
- agent.link.respond(*sub, resp.clone());
+
+ if !logged_in && agent.session.is_some() {
+ error!("Not logged in but got session");
+ } else {
+ let resp = Response::LoggedIn(logged_in.clone());
+ for sub in subscribers.iter() {
+ agent.link.respond(*sub, resp.clone());
+ }
}
});
}
}
}
- fn connected(&mut self, id: HandlerId) {
- self.subscribers.insert(id);
- }
fn disconnected(&mut self, id: HandlerId) {
self.subscribers.remove(&id);
@@ -132,32 +187,49 @@ impl Agent for MatrixAgent {
}
impl MatrixAgent {
- async fn get_logged_in(&self) -> String {
+ async fn get_logged_in(&self) -> bool {
if self.matrix_client.is_none() {
- return "false".to_string();
+ return false;
}
self.matrix_client
.clone()
.unwrap()
.logged_in()
.await
- .to_string()
}
fn login(&mut self) -> Option<Client> {
- return if self.matrix_state.homeserver.is_none()
+ return if (self.matrix_state.homeserver.is_none()
|| self.matrix_state.username.is_none()
|| self.matrix_state.password.is_none()
- || self.matrix_client.is_some()
+ || self.matrix_client.is_some()) && self.session.is_none()
{
- let resp = Response {
- message: "login_fields_missing".to_string(),
- content: "".to_string(),
- };
+ let resp = Response::Error(MatrixError::MissingFields);
for sub in self.subscribers.iter() {
self.link.respond(*sub, resp.clone());
}
None
+ } else if self.session.is_some() {
+ let homeserver = self.session.clone().unwrap().homeserver_url;
+
+ let client_config = ClientConfig::new();
+ let homeserver_url = Url::parse(&homeserver.clone()).unwrap();
+ let client = Client::new_with_config(homeserver_url, client_config).unwrap();
+ self.matrix_client = Some(client.clone());
+
+ // 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();
+ spawn_local(async move {
+ client_clone.restore_login(session).await;
+ });
+
+ Some(client.clone())
} else {
let homeserver = self.matrix_state.homeserver.clone().unwrap();
diff --git a/src/app/views/login.rs b/src/app/views/login.rs
@@ -1,7 +1,6 @@
use log::*;
use yew::agent::{Dispatched, Dispatcher};
use yew::prelude::*;
-use yew::services::storage::{Area, StorageService};
use crate::app::matrix::{MatrixAgent, Request};
@@ -10,7 +9,6 @@ pub struct Login {
homeserver: String,
username: String,
password: String,
- storage: StorageService,
matrix_agent: Dispatcher<MatrixAgent>,
}
@@ -28,7 +26,6 @@ impl Component for Login {
type Properties = ();
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
- let storage = StorageService::new(Area::Local).unwrap();
let matrix_agent = MatrixAgent::dispatcher();
Login {
link,
@@ -36,7 +33,6 @@ impl Component for Login {
homeserver: "".to_string(),
username: "".to_string(),
password: "".to_string(),
- storage,
matrix_agent,
}
}
diff --git a/src/app/views/main_view.rs b/src/app/views/main_view.rs
@@ -1,15 +1,12 @@
use log::*;
use serde_derive::{Deserialize, Serialize};
use yew::prelude::*;
-use yew::services::storage::Area;
-use yew::services::StorageService;
use yew::ComponentLink;
use crate::app::matrix::{MatrixAgent, Response};
pub struct MainView {
link: ComponentLink<Self>,
- storage: StorageService,
state: State,
matrix_agent: Box<dyn Bridge<MatrixAgent>>,
}
@@ -26,14 +23,12 @@ impl Component for MainView {
type Properties = ();
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
- let storage = StorageService::new(Area::Local).unwrap();
let matrix_callback = link.callback(Msg::NewMessage);
let matrix_agent = MatrixAgent::bridge(matrix_callback);
let state = State {};
MainView {
link,
- storage,
matrix_agent,
state,
}
@@ -43,8 +38,11 @@ impl Component for MainView {
match msg {
Msg::NewMessage(response) => {
info!("NewMessage: {:#?}", response);
- if response.message == "client_logged_in" {
- info!("client_logged_in: {}", response.content);
+ match response {
+ Response::LoggedIn(v) => {
+ info!("client_logged_in: {}", v);
+ },
+ _ => {}
}
}
}
diff --git a/src/constants.rs b/src/constants.rs
@@ -0,0 +1 @@
+pub const AUTH_KEY: &str = "nordgedanken.daydream.auth_data";
diff --git a/src/errors.rs b/src/errors.rs
@@ -0,0 +1,10 @@
+use serde_derive::{Deserialize, Serialize};use thiserror::Error;
+
+
+#[derive(Error, Debug, Clone, Serialize, Deserialize)]
+pub enum MatrixError {
+ #[error("No Matrix Client is available yet")]
+ MissingClient,
+ #[error("Missing required Data")]
+ MissingFields,
+}
diff --git a/src/lib.rs b/src/lib.rs
@@ -4,6 +4,8 @@
extern crate cfg_if;
mod app;
+mod errors;
+mod constants;
use wasm_bindgen::prelude::*;