|
|
|
|
@ -11,6 +11,7 @@ use self::user::User;
|
|
|
|
|
|
|
|
|
|
use crate::event_from_sync_event; |
|
|
|
|
use crate::secret; |
|
|
|
|
use crate::utils::do_async; |
|
|
|
|
use crate::RUNTIME; |
|
|
|
|
|
|
|
|
|
use adw; |
|
|
|
|
@ -20,15 +21,12 @@ use gtk::{self, prelude::*};
|
|
|
|
|
use gtk::{glib, glib::clone, glib::SyncSender, CompositeTemplate}; |
|
|
|
|
use gtk_macros::send; |
|
|
|
|
use log::error; |
|
|
|
|
use matrix_sdk::api::r0::{ |
|
|
|
|
filter::{FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter}, |
|
|
|
|
session::login, |
|
|
|
|
}; |
|
|
|
|
use matrix_sdk::api::r0::filter::{FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter}; |
|
|
|
|
use matrix_sdk::{ |
|
|
|
|
self, assign, |
|
|
|
|
deserialized_responses::SyncResponse, |
|
|
|
|
events::{AnyRoomEvent, AnySyncRoomEvent}, |
|
|
|
|
identifiers::{RoomId, UserId}, |
|
|
|
|
identifiers::RoomId, |
|
|
|
|
Client, ClientConfig, RequestConfig, SyncSettings, |
|
|
|
|
}; |
|
|
|
|
use std::time::Duration; |
|
|
|
|
@ -114,10 +112,8 @@ mod imp {
|
|
|
|
|
) { |
|
|
|
|
match pspec.name() { |
|
|
|
|
"homeserver" => { |
|
|
|
|
let homeserver = value |
|
|
|
|
.get() |
|
|
|
|
.expect("type conformity checked by `Object::set_property`"); |
|
|
|
|
let _ = self.homeserver.set(homeserver); |
|
|
|
|
let homeserver = value.get().unwrap(); |
|
|
|
|
let _ = obj.set_homeserver(homeserver); |
|
|
|
|
} |
|
|
|
|
"selected-room" => { |
|
|
|
|
let selected_room = value.get().unwrap(); |
|
|
|
|
@ -151,15 +147,6 @@ mod imp {
|
|
|
|
|
impl BinImpl for Session {} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Enum containing the supported methods to create a `Session`.
|
|
|
|
|
#[derive(Clone, Debug)] |
|
|
|
|
enum CreationMethod { |
|
|
|
|
/// Restore a previous session: `matrix_sdk::Session`
|
|
|
|
|
SessionRestore(matrix_sdk::Session), |
|
|
|
|
/// Password Login: `username`, 'password`
|
|
|
|
|
Password(String, String), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
glib::wrapper! { |
|
|
|
|
pub struct Session(ObjectSubclass<imp::Session>) |
|
|
|
|
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible; |
|
|
|
|
@ -187,123 +174,106 @@ impl Session {
|
|
|
|
|
self.notify("selected-room"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn login_with_password(&self, username: String, password: String) { |
|
|
|
|
let method = CreationMethod::Password(username, password); |
|
|
|
|
self.login(method); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn login_with_previous_session(&self, session: matrix_sdk::Session) { |
|
|
|
|
let method = CreationMethod::SessionRestore(session); |
|
|
|
|
self.login(method); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn login(&self, method: CreationMethod) { |
|
|
|
|
fn set_homeserver(&self, homeserver: String) { |
|
|
|
|
let priv_ = imp::Session::from_instance(self); |
|
|
|
|
let homeserver = priv_.homeserver.get().unwrap(); |
|
|
|
|
|
|
|
|
|
let sender = self.setup(); |
|
|
|
|
|
|
|
|
|
let config = ClientConfig::new().request_config(RequestConfig::new().retry_limit(2)); |
|
|
|
|
// Please note the homeserver needs to be a valid url or the client will panic!
|
|
|
|
|
let client = Client::new_with_config(homeserver.as_str(), config); |
|
|
|
|
let client = Client::new_with_config(homeserver.as_str(), config).unwrap(); |
|
|
|
|
|
|
|
|
|
if let Err(error) = client { |
|
|
|
|
send!(sender, Err(error)); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
priv_.homeserver.set(homeserver).unwrap(); |
|
|
|
|
priv_.client.set(client).unwrap(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let client = client.unwrap(); |
|
|
|
|
fn client(&self) -> Client { |
|
|
|
|
let priv_ = imp::Session::from_instance(self); |
|
|
|
|
priv_.client.get().unwrap().clone() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
priv_.client.set(client.clone()).unwrap(); |
|
|
|
|
let room_sender = self.create_new_sync_response_sender(); |
|
|
|
|
pub fn login_with_password(&self, username: String, password: String) { |
|
|
|
|
let client = self.client(); |
|
|
|
|
|
|
|
|
|
RUNTIME.spawn(async move { |
|
|
|
|
let success = match method { |
|
|
|
|
CreationMethod::SessionRestore(session) => { |
|
|
|
|
let res = client.restore_login(session).await; |
|
|
|
|
let success = res.is_ok(); |
|
|
|
|
let user_id = client.user_id().await.unwrap(); |
|
|
|
|
send!(sender, res.map(|_| (user_id, None))); |
|
|
|
|
success |
|
|
|
|
} |
|
|
|
|
CreationMethod::Password(username, password) => { |
|
|
|
|
let response = client |
|
|
|
|
.login(&username, &password, None, Some("Fractal Next")) |
|
|
|
|
.await; |
|
|
|
|
let success = response.is_ok(); |
|
|
|
|
let user_id = client.user_id().await.unwrap(); |
|
|
|
|
send!(sender, response.map(|r| (user_id, Some(r)))); |
|
|
|
|
success |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if success { |
|
|
|
|
// TODO: only create the filter once and reuse it in the future
|
|
|
|
|
let room_event_filter = assign!(RoomEventFilter::default(), { |
|
|
|
|
lazy_load_options: LazyLoadOptions::Enabled {include_redundant_members: false}, |
|
|
|
|
}); |
|
|
|
|
let filter = assign!(FilterDefinition::default(), { |
|
|
|
|
room: assign!(RoomFilter::empty(), { |
|
|
|
|
include_leave: true, |
|
|
|
|
state: room_event_filter, |
|
|
|
|
}), |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
let sync_settings = SyncSettings::new() |
|
|
|
|
.timeout(Duration::from_secs(30)) |
|
|
|
|
.filter(filter.into()); |
|
|
|
|
do_async( |
|
|
|
|
async move { |
|
|
|
|
client |
|
|
|
|
.sync_with_callback(sync_settings, |response| { |
|
|
|
|
let room_sender = room_sender.clone(); |
|
|
|
|
async move { |
|
|
|
|
// Using the event hanlder doesn't make a lot of sense for us since we want every room event
|
|
|
|
|
// Eventually we should contribute a better EventHandler interface so that it makes sense to use it.
|
|
|
|
|
room_sender.send(response).unwrap(); |
|
|
|
|
|
|
|
|
|
matrix_sdk::LoopCtrl::Continue |
|
|
|
|
} |
|
|
|
|
.login(&username, &password, None, Some("Fractal Next")) |
|
|
|
|
.await |
|
|
|
|
.map(|response| matrix_sdk::Session { |
|
|
|
|
access_token: response.access_token, |
|
|
|
|
user_id: response.user_id, |
|
|
|
|
device_id: response.device_id, |
|
|
|
|
}) |
|
|
|
|
.await; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
clone!(@weak self as obj => move |result| async move { |
|
|
|
|
obj.handle_login_result(result, true); |
|
|
|
|
}), |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn setup(&self) -> glib::SyncSender<matrix_sdk::Result<(UserId, Option<login::Response>)>> { |
|
|
|
|
let (sender, receiver) = glib::MainContext::sync_channel::< |
|
|
|
|
matrix_sdk::Result<(UserId, Option<login::Response>)>, |
|
|
|
|
>(Default::default(), 100); |
|
|
|
|
receiver.attach( |
|
|
|
|
None, |
|
|
|
|
clone!(@weak self as obj => @default-return glib::Continue(false), move |result| { |
|
|
|
|
match result { |
|
|
|
|
Err(error) => { |
|
|
|
|
let priv_ = &imp::Session::from_instance(&obj); |
|
|
|
|
priv_.error.replace(Some(error)); |
|
|
|
|
} |
|
|
|
|
Ok((user_id, Some(response))) => { |
|
|
|
|
let session = matrix_sdk::Session { |
|
|
|
|
access_token: response.access_token, |
|
|
|
|
user_id: response.user_id, |
|
|
|
|
device_id: response.device_id, |
|
|
|
|
}; |
|
|
|
|
obj.set_user(User::new(&user_id)); |
|
|
|
|
|
|
|
|
|
//TODO: set error to this error
|
|
|
|
|
obj.store_session(session).unwrap(); |
|
|
|
|
} |
|
|
|
|
Ok((user_id, None)) => { |
|
|
|
|
obj.set_user(User::new(&user_id)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
obj.load(); |
|
|
|
|
|
|
|
|
|
obj.emit_by_name("ready", &[]).unwrap(); |
|
|
|
|
pub fn login_with_previous_session(&self, session: matrix_sdk::Session) { |
|
|
|
|
let client = self.client(); |
|
|
|
|
|
|
|
|
|
glib::Continue(false) |
|
|
|
|
do_async( |
|
|
|
|
async move { client.restore_login(session.clone()).await.map(|_| session) }, |
|
|
|
|
clone!(@weak self as obj => move |result| async move { |
|
|
|
|
obj.handle_login_result(result, false); |
|
|
|
|
}), |
|
|
|
|
); |
|
|
|
|
sender |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn handle_login_result( |
|
|
|
|
&self, |
|
|
|
|
result: Result<matrix_sdk::Session, matrix_sdk::Error>, |
|
|
|
|
store_session: bool, |
|
|
|
|
) { |
|
|
|
|
let priv_ = &imp::Session::from_instance(self); |
|
|
|
|
match result { |
|
|
|
|
Ok(session) => { |
|
|
|
|
self.set_user(User::new(&session.user_id)); |
|
|
|
|
if store_session { |
|
|
|
|
self.store_session(session).unwrap(); |
|
|
|
|
} |
|
|
|
|
self.load(); |
|
|
|
|
self.sync(); |
|
|
|
|
} |
|
|
|
|
Err(error) => { |
|
|
|
|
priv_.error.replace(Some(error)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
self.emit_by_name("ready", &[]).unwrap(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn sync(&self) { |
|
|
|
|
let sender = self.create_new_sync_response_sender(); |
|
|
|
|
let client = self.client(); |
|
|
|
|
RUNTIME.spawn(async move { |
|
|
|
|
// TODO: only create the filter once and reuse it in the future
|
|
|
|
|
let room_event_filter = assign!(RoomEventFilter::default(), { |
|
|
|
|
lazy_load_options: LazyLoadOptions::Enabled {include_redundant_members: false}, |
|
|
|
|
}); |
|
|
|
|
let filter = assign!(FilterDefinition::default(), { |
|
|
|
|
room: assign!(RoomFilter::empty(), { |
|
|
|
|
include_leave: true, |
|
|
|
|
state: room_event_filter, |
|
|
|
|
}), |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
let sync_settings = SyncSettings::new() |
|
|
|
|
.timeout(Duration::from_secs(30)) |
|
|
|
|
.filter(filter.into()); |
|
|
|
|
client |
|
|
|
|
.sync_with_callback(sync_settings, |response| { |
|
|
|
|
let sender = sender.clone(); |
|
|
|
|
async move { |
|
|
|
|
// Using the event hanlder doesn't make a lot of sense for us since we want every room event
|
|
|
|
|
// Eventually we should contribute a better EventHandler interface so that it makes sense to use it.
|
|
|
|
|
send!(sender, response); |
|
|
|
|
|
|
|
|
|
matrix_sdk::LoopCtrl::Continue |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.await; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn set_user(&self, user: User) { |
|
|
|
|
|