matrix-sdk: Don't require the the session at client creation time.

The client objects in the sdk accepted an optional session argument at
creation time. If provided this would restore the client into a logged
in state.

Since we need to restore the client state and encryption state at some
point it makes sense to do it when the client transitions into a logged
in state. At the same time we would like to avoid the client creation to
be async.

This introduces a restore_login() method which can be called instead of
the login() method to restore a session.
master
Damir Jelić 2020-05-22 15:23:58 +02:00
parent cffa2990b6
commit ea5f7f1d19
13 changed files with 147 additions and 115 deletions

View File

@ -20,7 +20,7 @@ sqlite-cryptostore = ["matrix-sdk-base/sqlite-cryptostore"]
http = "0.2.1" http = "0.2.1"
reqwest = "0.10.4" reqwest = "0.10.4"
serde_json = "1.0.53" serde_json = "1.0.53"
thiserror = "1.0.17" thiserror = "1.0.18"
tracing = "0.1.14" tracing = "0.1.14"
url = "2.1.1" url = "2.1.1"
futures-timer = "3.0.2" futures-timer = "3.0.2"

View File

@ -75,7 +75,7 @@ async fn login_and_sync(
let homeserver_url = Url::parse(&homeserver_url).expect("Couldn't parse the homeserver URL"); let homeserver_url = Url::parse(&homeserver_url).expect("Couldn't parse the homeserver URL");
// create a new Client with the given homeserver url and config // create a new Client with the given homeserver url and config
let mut client = Client::new_with_config(homeserver_url, None, client_config).unwrap(); let mut client = Client::new_with_config(homeserver_url, client_config).unwrap();
client client
.login( .login(

View File

@ -45,7 +45,7 @@ async fn login(
.proxy("http://localhost:8080")? .proxy("http://localhost:8080")?
.disable_ssl_verification(); .disable_ssl_verification();
let homeserver_url = Url::parse(&homeserver_url).expect("Couldn't parse the homeserver URL"); let homeserver_url = Url::parse(&homeserver_url).expect("Couldn't parse the homeserver URL");
let mut client = Client::new_with_config(homeserver_url, None, client_config).unwrap(); let mut client = Client::new_with_config(homeserver_url, client_config).unwrap();
client.add_event_emitter(Box::new(EventCallback)).await; client.add_event_emitter(Box::new(EventCallback)).await;

View File

@ -74,7 +74,6 @@ impl std::fmt::Debug for Client {
} }
} }
#[derive(Default)]
/// Configuration for the creation of the `Client`. /// Configuration for the creation of the `Client`.
/// ///
/// When setting the `StateStore` it is up to the user to open/connect /// When setting the `StateStore` it is up to the user to open/connect
@ -99,6 +98,7 @@ impl std::fmt::Debug for Client {
/// let client_config = ClientConfig::new() /// let client_config = ClientConfig::new()
/// .state_store(Box::new(store)); /// .state_store(Box::new(store));
/// ``` /// ```
#[derive(Default)]
pub struct ClientConfig { pub struct ClientConfig {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
proxy: Option<reqwest::Proxy>, proxy: Option<reqwest::Proxy>,
@ -242,11 +242,9 @@ impl Client {
/// # Arguments /// # Arguments
/// ///
/// * `homeserver_url` - The homeserver that the client should connect to. /// * `homeserver_url` - The homeserver that the client should connect to.
/// * `session` - If a previous login exists, the access token can be pub fn new<U: TryInto<Url>>(homeserver_url: U) -> Result<Self> {
/// reused by giving a session object here.
pub fn new<U: TryInto<Url>>(homeserver_url: U, session: Option<Session>) -> Result<Self> {
let config = ClientConfig::new(); let config = ClientConfig::new();
Client::new_with_config(homeserver_url, session, config) Client::new_with_config(homeserver_url, config)
} }
/// Create a new client with the given configuration. /// Create a new client with the given configuration.
@ -254,12 +252,10 @@ impl Client {
/// # Arguments /// # Arguments
/// ///
/// * `homeserver_url` - The homeserver that the client should connect to. /// * `homeserver_url` - The homeserver that the client should connect to.
/// * `session` - If a previous login exists, the access token can be ///
/// reused by giving a session object here.
/// * `config` - Configuration for the client. /// * `config` - Configuration for the client.
pub fn new_with_config<U: TryInto<Url>>( pub fn new_with_config<U: TryInto<Url>>(
homeserver_url: U, homeserver_url: U,
session: Option<Session>,
config: ClientConfig, config: ClientConfig,
) -> Result<Self> { ) -> Result<Self> {
#[allow(clippy::match_wild_err_arm)] #[allow(clippy::match_wild_err_arm)]
@ -298,9 +294,9 @@ impl Client {
let http_client = http_client.build()?; let http_client = http_client.build()?;
let base_client = if let Some(store) = config.state_store { let base_client = if let Some(store) = config.state_store {
BaseClient::new_with_state_store(session, store)? BaseClient::new_with_state_store(store)?
} else { } else {
BaseClient::new(session)? BaseClient::new()?
}; };
Ok(Self { Ok(Self {
@ -389,7 +385,7 @@ impl Client {
/// # let homeserver = Url::parse("http://example.com").unwrap(); /// # let homeserver = Url::parse("http://example.com").unwrap();
/// let store = JsonStore::open("path/to/store").unwrap(); /// let store = JsonStore::open("path/to/store").unwrap();
/// let config = ClientConfig::new().state_store(Box::new(store)); /// let config = ClientConfig::new().state_store(Box::new(store));
/// let mut client = Client::new(homeserver, None).unwrap(); /// let mut client = Client::new(homeserver).unwrap();
/// # use futures::executor::block_on; /// # use futures::executor::block_on;
/// # block_on(async { /// # block_on(async {
/// let _ = client.login("name", "password", None, None).await.unwrap(); /// let _ = client.login("name", "password", None, None).await.unwrap();
@ -455,6 +451,16 @@ impl Client {
Ok(response) Ok(response)
} }
/// Restore a previously logged in session.
///
/// # Arguments
///
/// * `session` - An session that the user already has from a
/// previous login call.
pub async fn restore_login(&self, session: Session) -> Result<()> {
Ok(self.base_client.restore_login(session).await?)
}
/// Join a room by `RoomId`. /// Join a room by `RoomId`.
/// ///
/// Returns a `join_room_by_id::Response` consisting of the /// Returns a `join_room_by_id::Response` consisting of the
@ -566,7 +572,6 @@ impl Client {
/// # Arguments /// # Arguments
/// ///
/// * `room_id` - The `RoomId` of the room to leave. /// * `room_id` - The `RoomId` of the room to leave.
///
pub async fn leave_room(&self, room_id: &RoomId) -> Result<leave_room::Response> { pub async fn leave_room(&self, room_id: &RoomId) -> Result<leave_room::Response> {
let request = leave_room::Request { let request = leave_room::Request {
room_id: room_id.clone(), room_id: room_id.clone(),
@ -641,7 +646,7 @@ impl Client {
/// .name("name") /// .name("name")
/// .room_version("v1.0"); /// .room_version("v1.0");
/// ///
/// let mut cli = Client::new(homeserver, None).unwrap(); /// let mut cli = Client::new(homeserver).unwrap();
/// # use futures::executor::block_on; /// # use futures::executor::block_on;
/// # block_on(async { /// # block_on(async {
/// assert!(cli.create_room(builder).await.is_ok()); /// assert!(cli.create_room(builder).await.is_ok());
@ -685,10 +690,10 @@ impl Client {
/// .direction(Direction::Backward) /// .direction(Direction::Backward)
/// .limit(UInt::new(10).unwrap()); /// .limit(UInt::new(10).unwrap());
/// ///
/// let mut cli = Client::new(homeserver, None).unwrap(); /// let mut client = Client::new(homeserver).unwrap();
/// # use futures::executor::block_on; /// # use futures::executor::block_on;
/// # block_on(async { /// # block_on(async {
/// assert!(cli.room_messages(builder).await.is_ok()); /// assert!(client.room_messages(builder).await.is_ok());
/// # }); /// # });
/// ``` /// ```
pub async fn room_messages<R: Into<get_message_events::Request>>( pub async fn room_messages<R: Into<get_message_events::Request>>(
@ -759,21 +764,7 @@ impl Client {
/// ///
/// * `sync_settings` - Settings for the sync call. /// * `sync_settings` - Settings for the sync call.
#[instrument] #[instrument]
#[allow(clippy::useless_let_if_seq)] pub async fn sync(&self, sync_settings: SyncSettings) -> Result<sync_events::Response> {
pub async fn sync(&self, mut sync_settings: SyncSettings) -> Result<sync_events::Response> {
{
// if the client has been synced from the state store don't sync again
if !self.base_client.is_state_store_synced() {
// this will bail out returning false if the store has not been set up
if let Ok(synced) = self.sync_with_state_store().await {
if synced {
// once synced, update the sync token to the last known state from `StateStore`.
sync_settings.token = self.sync_token().await;
}
}
}
}
let request = sync_events::Request { let request = sync_events::Request {
filter: None, filter: None,
since: sync_settings.token, since: sync_settings.token,
@ -857,6 +848,10 @@ impl Client {
let mut sync_settings = sync_settings; let mut sync_settings = sync_settings;
let mut last_sync_time: Option<Instant> = None; let mut last_sync_time: Option<Instant> = None;
if sync_settings.token.is_none() {
sync_settings.token = self.sync_token().await;
}
loop { loop {
let response = self.sync(sync_settings.clone()).await; let response = self.sync(sync_settings.clone()).await;
@ -1010,7 +1005,7 @@ impl Client {
/// use matrix_sdk::events::room::message::{MessageEventContent, TextMessageEventContent}; /// use matrix_sdk::events::room::message::{MessageEventContent, TextMessageEventContent};
/// # block_on(async { /// # block_on(async {
/// # let homeserver = Url::parse("http://localhost:8080").unwrap(); /// # let homeserver = Url::parse("http://localhost:8080").unwrap();
/// # let mut client = Client::new(homeserver, None).unwrap(); /// # let mut client = Client::new(homeserver).unwrap();
/// # let room_id = RoomId::try_from("!test:localhost").unwrap(); /// # let room_id = RoomId::try_from("!test:localhost").unwrap();
/// use matrix_sdk_common::uuid::Uuid; /// use matrix_sdk_common::uuid::Uuid;
/// ///
@ -1277,8 +1272,8 @@ mod test {
let store = Box::new(JsonStore::open(path).unwrap()); let store = Box::new(JsonStore::open(path).unwrap());
let config = ClientConfig::default().state_store(store); let config = ClientConfig::default().state_store(store);
let client = let client = Client::new_with_config(homeserver.clone(), config).unwrap();
Client::new_with_config(homeserver.clone(), Some(session.clone()), config).unwrap(); client.restore_login(session.clone()).await.unwrap();
let room = client.get_joined_room(&room_id).await; let room = client.get_joined_room(&room_id).await;
assert!(room.is_none()); assert!(room.is_none());
@ -1294,7 +1289,8 @@ mod test {
// test store reloads with correct room state from JsonStore // test store reloads with correct room state from JsonStore
let store = Box::new(JsonStore::open(path).unwrap()); let store = Box::new(JsonStore::open(path).unwrap());
let config = ClientConfig::default().state_store(store); let config = ClientConfig::default().state_store(store);
let joined_client = Client::new_with_config(homeserver, Some(session), config).unwrap(); let joined_client = Client::new_with_config(homeserver, config).unwrap();
joined_client.restore_login(session).await.unwrap();
// joined room reloaded from state store // joined room reloaded from state store
joined_client.sync(SyncSettings::default()).await.unwrap(); joined_client.sync(SyncSettings::default()).await.unwrap();
@ -1336,7 +1332,8 @@ mod test {
.with_body_from_file("../test_data/sync.json") .with_body_from_file("../test_data/sync.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
@ -1355,7 +1352,8 @@ mod test {
device_id: "DEVICEID".to_owned(), device_id: "DEVICEID".to_owned(),
}; };
let homeserver = url::Url::parse(&mockito::server_url()).unwrap(); let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let mut response = EventBuilder::default() let mut response = EventBuilder::default()
.add_room_event(EventsFile::Member, RoomEvent::RoomMember) .add_room_event(EventsFile::Member, RoomEvent::RoomMember)
@ -1387,7 +1385,7 @@ mod test {
.with_body_from_file("../test_data/login_response_error.json") .with_body_from_file("../test_data/login_response_error.json")
.create(); .create();
let client = Client::new(homeserver, None).unwrap(); let client = Client::new(homeserver).unwrap();
if let Err(err) = client.login("example", "wordpass", None, None).await { if let Err(err) = client.login("example", "wordpass", None, None).await {
if let crate::Error::RumaResponse(crate::FromHttpResponseError::Http( if let crate::Error::RumaResponse(crate::FromHttpResponseError::Http(
@ -1436,7 +1434,8 @@ mod test {
.with_body_from_file("../test_data/room_id.json") .with_body_from_file("../test_data/room_id.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let room_id = RoomId::try_from("!testroom:example.org").unwrap(); let room_id = RoomId::try_from("!testroom:example.org").unwrap();
assert_eq!( assert_eq!(
@ -1466,7 +1465,8 @@ mod test {
.with_body_from_file("../test_data/room_id.json") .with_body_from_file("../test_data/room_id.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let room_id = RoomIdOrAliasId::try_from("!testroom:example.org").unwrap(); let room_id = RoomIdOrAliasId::try_from("!testroom:example.org").unwrap();
assert_eq!( assert_eq!(
@ -1501,7 +1501,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
if let invite_user::Response = client.invite_user_by_id(&room_id, &user).await.unwrap() {} if let invite_user::Response = client.invite_user_by_id(&room_id, &user).await.unwrap() {}
} }
@ -1527,7 +1528,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
if let invite_user::Response = client if let invite_user::Response = client
.invite_user_by_3pid( .invite_user_by_3pid(
@ -1564,7 +1566,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let room_id = RoomId::try_from("!testroom:example.org").unwrap(); let room_id = RoomId::try_from("!testroom:example.org").unwrap();
let response = client.leave_room(&room_id).await.unwrap(); let response = client.leave_room(&room_id).await.unwrap();
@ -1599,7 +1602,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let response = client.ban_user(&room_id, &user, None).await.unwrap(); let response = client.ban_user(&room_id, &user, None).await.unwrap();
if let ban_user::Response = response { if let ban_user::Response = response {
@ -1633,7 +1637,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let response = client.kick_user(&room_id, &user, None).await.unwrap(); let response = client.kick_user(&room_id, &user, None).await.unwrap();
if let kick_user::Response = response { if let kick_user::Response = response {
@ -1667,7 +1672,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let response = client.forget_room_by_id(&room_id).await.unwrap(); let response = client.forget_room_by_id(&room_id).await.unwrap();
if let forget_room::Response = response { if let forget_room::Response = response {
@ -1702,7 +1708,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let response = client.read_receipt(&room_id, &event_id).await.unwrap(); let response = client.read_receipt(&room_id, &event_id).await.unwrap();
if let create_receipt::Response = response { if let create_receipt::Response = response {
@ -1736,7 +1743,8 @@ mod test {
.with_body_from_file("../test_data/logout_response.json") .with_body_from_file("../test_data/logout_response.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let response = client let response = client
.typing_notice( .typing_notice(
@ -1778,7 +1786,8 @@ mod test {
.with_body_from_file("../test_data/event_id.json") .with_body_from_file("../test_data/event_id.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let content = MessageEventContent::Text(TextMessageEventContent { let content = MessageEventContent::Text(TextMessageEventContent {
body: "Hello world".to_owned(), body: "Hello world".to_owned(),
@ -1816,7 +1825,8 @@ mod test {
.with_body_from_file("../test_data/sync.json") .with_body_from_file("../test_data/sync.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
@ -1856,7 +1866,8 @@ mod test {
.with_body_from_file("../test_data/sync_with_summary.json") .with_body_from_file("../test_data/sync_with_summary.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
let _response = client.sync(sync_settings).await.unwrap(); let _response = client.sync(sync_settings).await.unwrap();
@ -1880,7 +1891,8 @@ mod test {
}; };
let homeserver = url::Url::parse(&mockito::server_url()).unwrap(); let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let _m = mock( let _m = mock(
"GET", "GET",
@ -1913,7 +1925,8 @@ mod test {
}; };
let homeserver = url::Url::parse(&mockito::server_url()).unwrap(); let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let _m = mock( let _m = mock(
"GET", "GET",
@ -1962,8 +1975,8 @@ mod test {
// a sync response to populate our JSON store // a sync response to populate our JSON store
let config = let config =
ClientConfig::default().state_store(Box::new(JsonStore::open(dir.path()).unwrap())); ClientConfig::default().state_store(Box::new(JsonStore::open(dir.path()).unwrap()));
let client = let client = Client::new_with_config(homeserver.clone(), config).unwrap();
Client::new_with_config(homeserver.clone(), Some(session.clone()), config).unwrap(); client.restore_login(session.clone()).await.unwrap();
let sync_settings = SyncSettings::new().timeout(std::time::Duration::from_millis(3000)); let sync_settings = SyncSettings::new().timeout(std::time::Duration::from_millis(3000));
// gather state to save to the db, the first time through loading will be skipped // gather state to save to the db, the first time through loading will be skipped
@ -1972,7 +1985,8 @@ mod test {
// now syncing the client will update from the state store // now syncing the client will update from the state store
let config = let config =
ClientConfig::default().state_store(Box::new(JsonStore::open(dir.path()).unwrap())); ClientConfig::default().state_store(Box::new(JsonStore::open(dir.path()).unwrap()));
let client = Client::new_with_config(homeserver, Some(session.clone()), config).unwrap(); let client = Client::new_with_config(homeserver, config).unwrap();
client.restore_login(session.clone()).await.unwrap();
client.sync(sync_settings).await.unwrap(); client.sync(sync_settings).await.unwrap();
let base_client = &client.base_client; let base_client = &client.base_client;
@ -1998,7 +2012,7 @@ mod test {
.with_body_from_file("../test_data/login_response.json") .with_body_from_file("../test_data/login_response.json")
.create(); .create();
let client = Client::new(homeserver, None).unwrap(); let client = Client::new(homeserver).unwrap();
client client
.login("example", "wordpass", None, None) .login("example", "wordpass", None, None)
@ -2027,7 +2041,8 @@ mod test {
.with_body_from_file("../test_data/sync.json") .with_body_from_file("../test_data/sync.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
@ -2056,7 +2071,8 @@ mod test {
.with_body_from_file("../test_data/sync.json") .with_body_from_file("../test_data/sync.json")
.create(); .create();
let client = Client::new(homeserver, Some(session)).unwrap(); let client = Client::new(homeserver).unwrap();
client.restore_login(session).await.unwrap();
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));

View File

@ -30,8 +30,8 @@ use crate::js_int::UInt;
/// .visibility(Visibility::Public) /// .visibility(Visibility::Public)
/// .name("name") /// .name("name")
/// .room_version("v1.0"); /// .room_version("v1.0");
/// let mut cli = Client::new(homeserver, None).unwrap(); /// let mut client = Client::new(homeserver).unwrap();
/// cli.create_room(builder).await; /// client.create_room(builder).await;
/// # }) /// # })
/// ``` /// ```
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -188,14 +188,14 @@ impl Into<create_room::Request> for RoomBuilder {
/// # rt.block_on(async { /// # rt.block_on(async {
/// # let room_id = RoomId::try_from("!test:localhost").unwrap(); /// # let room_id = RoomId::try_from("!test:localhost").unwrap();
/// # let last_sync_token = "".to_string(); /// # let last_sync_token = "".to_string();
/// let mut cli = Client::new(homeserver, None).unwrap(); /// let mut client = Client::new(homeserver).unwrap();
/// ///
/// let mut builder = MessagesRequestBuilder::new(); /// let mut builder = MessagesRequestBuilder::new();
/// builder.room_id(room_id) /// builder.room_id(room_id)
/// .from(last_sync_token) /// .from(last_sync_token)
/// .direction(Direction::Forward); /// .direction(Direction::Forward);
/// ///
/// cli.room_messages(builder).await.is_err(); /// client.room_messages(builder).await.is_err();
/// # }) /// # })
/// ``` /// ```
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -342,7 +342,8 @@ mod test {
.room_alias_name("room_alias") .room_alias_name("room_alias")
.topic("room topic") .topic("room topic")
.visibility(Visibility::Private); .visibility(Visibility::Private);
let cli = Client::new(homeserver, Some(session)).unwrap(); let cli = Client::new(homeserver).unwrap();
cli.restore_login(session).await.unwrap();
assert!(cli.create_room(builder).await.is_ok()); assert!(cli.create_room(builder).await.is_ok());
} }
@ -378,7 +379,8 @@ mod test {
..Default::default() ..Default::default()
}); });
let cli = Client::new(homeserver, Some(session)).unwrap(); let cli = Client::new(homeserver).unwrap();
cli.restore_login(session).await.unwrap();
assert!(cli.room_messages(builder).await.is_ok()); assert!(cli.room_messages(builder).await.is_ok());
} }
} }

View File

@ -25,7 +25,7 @@ matrix-sdk-common = { version = "0.1.0", path = "../matrix_sdk_common" }
matrix-sdk-crypto = { version = "0.1.0", path = "../matrix_sdk_crypto", optional = true } matrix-sdk-crypto = { version = "0.1.0", path = "../matrix_sdk_crypto", optional = true }
# Misc dependencies # Misc dependencies
thiserror = "1.0.17" thiserror = "1.0.18"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio] [target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio]
version = "0.2.21" version = "0.2.21"

View File

@ -143,8 +143,8 @@ impl BaseClient {
/// ///
/// * `session` - An optional session if the user already has one from a /// * `session` - An optional session if the user already has one from a
/// previous login call. /// previous login call.
pub fn new(session: Option<Session>) -> Result<Self> { pub fn new() -> Result<Self> {
BaseClient::new_helper(session, None) BaseClient::new_helper(None)
} }
/// Create a new client. /// Create a new client.
@ -156,22 +156,13 @@ impl BaseClient {
/// ///
/// * `store` - An open state store implementation that will be used through /// * `store` - An open state store implementation that will be used through
/// the lifetime of the client. /// the lifetime of the client.
pub fn new_with_state_store( pub fn new_with_state_store(store: Box<dyn StateStore>) -> Result<Self> {
session: Option<Session>, BaseClient::new_helper(Some(store))
store: Box<dyn StateStore>,
) -> Result<Self> {
BaseClient::new_helper(session, Some(store))
} }
fn new_helper(session: Option<Session>, store: Option<Box<dyn StateStore>>) -> Result<Self> { fn new_helper(store: Option<Box<dyn StateStore>>) -> Result<Self> {
#[cfg(feature = "encryption")]
let olm = match &session {
Some(s) => Some(OlmMachine::new(&s.user_id, &s.device_id)),
None => None,
};
Ok(BaseClient { Ok(BaseClient {
session: Arc::new(RwLock::new(session)), session: Arc::new(RwLock::new(None)),
sync_token: Arc::new(RwLock::new(None)), sync_token: Arc::new(RwLock::new(None)),
joined_rooms: Arc::new(RwLock::new(HashMap::new())), joined_rooms: Arc::new(RwLock::new(HashMap::new())),
invited_rooms: Arc::new(RwLock::new(HashMap::new())), invited_rooms: Arc::new(RwLock::new(HashMap::new())),
@ -182,7 +173,7 @@ impl BaseClient {
state_store: Arc::new(RwLock::new(store)), state_store: Arc::new(RwLock::new(store)),
needs_state_store_sync: Arc::new(AtomicBool::from(true)), needs_state_store_sync: Arc::new(AtomicBool::from(true)),
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
olm: Arc::new(Mutex::new(olm)), olm: Arc::new(Mutex::new(None)),
}) })
} }
@ -299,13 +290,24 @@ impl BaseClient {
device_id: response.device_id.clone(), device_id: response.device_id.clone(),
user_id: response.user_id.clone(), user_id: response.user_id.clone(),
}; };
*self.session.write().await = Some(session); self.restore_login(session).await
}
/// Restore a previously logged in session.
///
/// # Arguments
///
/// * `session` - An session that the user already has from a
/// previous login call.
pub async fn restore_login(&self, session: Session) -> Result<()> {
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
{ {
let mut olm = self.olm.lock().await; let mut olm = self.olm.lock().await;
*olm = Some(OlmMachine::new(&response.user_id, &response.device_id)); *olm = Some(OlmMachine::new(&session.user_id, &session.device_id));
} }
self.sync_with_state_store().await?;
*self.session.write().await = Some(session);
Ok(()) Ok(())
} }
@ -1518,13 +1520,15 @@ mod test {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*; use wasm_bindgen_test::*;
fn get_client() -> BaseClient { async fn get_client() -> BaseClient {
let session = Session { let session = Session {
access_token: "1234".to_owned(), access_token: "1234".to_owned(),
user_id: UserId::try_from("@example:localhost").unwrap(), user_id: UserId::try_from("@example:localhost").unwrap(),
device_id: "DEVICEID".to_owned(), device_id: "DEVICEID".to_owned(),
}; };
BaseClient::new(Some(session)).unwrap() let client = BaseClient::new().unwrap();
client.restore_login(session).await.unwrap();
client
} }
fn get_room_id() -> RoomId { fn get_room_id() -> RoomId {
@ -1551,7 +1555,7 @@ mod test {
let mut sync_response = EventBuilder::default() let mut sync_response = EventBuilder::default()
.add_room_event(EventsFile::Member, RoomEvent::RoomMember) .add_room_event(EventsFile::Member, RoomEvent::RoomMember)
.build_sync_response(); .build_sync_response();
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();
let room = client.get_joined_room(&room_id).await; let room = client.get_joined_room(&room_id).await;
@ -1593,7 +1597,7 @@ mod test {
.add_custom_left_event(&room_id, member_event(), RoomEvent::RoomMember) .add_custom_left_event(&room_id, member_event(), RoomEvent::RoomMember)
.build_sync_response(); .build_sync_response();
let client = get_client(); let client = get_client().await;
let room = client.get_left_room(&room_id).await; let room = client.get_left_room(&room_id).await;
assert!(room.is_none()); assert!(room.is_none());
@ -1631,7 +1635,7 @@ mod test {
.add_custom_invited_event(&room_id, member_event(), AnyStrippedStateEvent::RoomMember) .add_custom_invited_event(&room_id, member_event(), AnyStrippedStateEvent::RoomMember)
.build_sync_response(); .build_sync_response();
let client = get_client(); let client = get_client().await;
let room = client.get_invited_room(&room_id).await; let room = client.get_invited_room(&room_id).await;
assert!(room.is_none()); assert!(room.is_none());
@ -1665,7 +1669,7 @@ mod test {
#[async_test] #[async_test]
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
async fn test_group_session_invalidation() { async fn test_group_session_invalidation() {
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();
let mut sync_response = EventBuilder::default() let mut sync_response = EventBuilder::default()

View File

@ -295,13 +295,15 @@ mod test {
use std::convert::TryFrom; use std::convert::TryFrom;
fn get_client() -> BaseClient { async fn get_client() -> BaseClient {
let session = Session { let session = Session {
access_token: "1234".to_owned(), access_token: "1234".to_owned(),
user_id: UserId::try_from("@example:example.com").unwrap(), user_id: UserId::try_from("@example:example.com").unwrap(),
device_id: "DEVICEID".to_owned(), device_id: "DEVICEID".to_owned(),
}; };
BaseClient::new(Some(session)).unwrap() let client = BaseClient::new().unwrap();
client.restore_login(session).await.unwrap();
client
} }
#[async_test] #[async_test]
@ -310,7 +312,7 @@ mod test {
let test_vec = Arc::clone(&vec); let test_vec = Arc::clone(&vec);
let emitter = Box::new(EvEmitterTest(vec)); let emitter = Box::new(EvEmitterTest(vec));
let client = get_client(); let client = get_client().await;
client.add_event_emitter(emitter).await; client.add_event_emitter(emitter).await;
let mut response = sync_response(SyncResponseFile::Default); let mut response = sync_response(SyncResponseFile::Default);
@ -341,7 +343,7 @@ mod test {
let test_vec = Arc::clone(&vec); let test_vec = Arc::clone(&vec);
let emitter = Box::new(EvEmitterTest(vec)); let emitter = Box::new(EvEmitterTest(vec));
let client = get_client(); let client = get_client().await;
client.add_event_emitter(emitter).await; client.add_event_emitter(emitter).await;
let mut response = sync_response(SyncResponseFile::Invite); let mut response = sync_response(SyncResponseFile::Invite);
@ -360,7 +362,7 @@ mod test {
let test_vec = Arc::clone(&vec); let test_vec = Arc::clone(&vec);
let emitter = Box::new(EvEmitterTest(vec)); let emitter = Box::new(EvEmitterTest(vec));
let client = get_client(); let client = get_client().await;
client.add_event_emitter(emitter).await; client.add_event_emitter(emitter).await;
let mut response = sync_response(SyncResponseFile::Leave); let mut response = sync_response(SyncResponseFile::Leave);

View File

@ -589,13 +589,15 @@ mod test {
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ops::Deref; use std::ops::Deref;
fn get_client() -> BaseClient { async fn get_client() -> BaseClient {
let session = Session { let session = Session {
access_token: "1234".to_owned(), access_token: "1234".to_owned(),
user_id: UserId::try_from("@example:localhost").unwrap(), user_id: UserId::try_from("@example:localhost").unwrap(),
device_id: "DEVICEID".to_owned(), device_id: "DEVICEID".to_owned(),
}; };
BaseClient::new(Some(session)).unwrap() let client = BaseClient::new().unwrap();
client.restore_login(session).await.unwrap();
client
} }
fn get_room_id() -> RoomId { fn get_room_id() -> RoomId {
@ -604,7 +606,7 @@ mod test {
#[async_test] #[async_test]
async fn user_presence() { async fn user_presence() {
let client = get_client(); let client = get_client().await;
let mut response = sync_response(SyncResponseFile::Default); let mut response = sync_response(SyncResponseFile::Default);
@ -628,7 +630,7 @@ mod test {
#[async_test] #[async_test]
async fn room_events() { async fn room_events() {
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();
let user_id = UserId::try_from("@example:localhost").unwrap(); let user_id = UserId::try_from("@example:localhost").unwrap();
@ -657,7 +659,7 @@ mod test {
#[async_test] #[async_test]
async fn calculate_aliases() { async fn calculate_aliases() {
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();
@ -675,7 +677,7 @@ mod test {
#[async_test] #[async_test]
async fn calculate_alias() { async fn calculate_alias() {
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();
@ -693,7 +695,7 @@ mod test {
#[async_test] #[async_test]
async fn calculate_name() { async fn calculate_name() {
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();
@ -718,7 +720,8 @@ mod test {
user_id: UserId::try_from("@example:localhost").unwrap(), user_id: UserId::try_from("@example:localhost").unwrap(),
device_id: "DEVICEID".to_owned(), device_id: "DEVICEID".to_owned(),
}; };
let client = BaseClient::new(Some(session)).unwrap(); let client = BaseClient::new().unwrap();
client.restore_login(session).await.unwrap();
client.receive_sync_response(&mut response).await.unwrap(); client.receive_sync_response(&mut response).await.unwrap();
let mut room_names = vec![]; let mut room_names = vec![];
@ -740,7 +743,8 @@ mod test {
user_id: user_id.clone(), user_id: user_id.clone(),
device_id: "DEVICEID".to_owned(), device_id: "DEVICEID".to_owned(),
}; };
let client = BaseClient::new(Some(session)).unwrap(); let client = BaseClient::new().unwrap();
client.restore_login(session).await.unwrap();
client.receive_sync_response(&mut response).await.unwrap(); client.receive_sync_response(&mut response).await.unwrap();
let event = EncryptionEvent { let event = EncryptionEvent {

View File

@ -213,13 +213,15 @@ mod test {
use std::convert::TryFrom; use std::convert::TryFrom;
fn get_client() -> BaseClient { async fn get_client() -> BaseClient {
let session = Session { let session = Session {
access_token: "1234".to_owned(), access_token: "1234".to_owned(),
user_id: UserId::try_from("@example:localhost").unwrap(), user_id: UserId::try_from("@example:localhost").unwrap(),
device_id: "DEVICEID".to_owned(), device_id: "DEVICEID".to_owned(),
}; };
BaseClient::new(Some(session)).unwrap() let client = BaseClient::new().unwrap();
client.restore_login(session).await.unwrap();
client
} }
fn get_room_id() -> RoomId { fn get_room_id() -> RoomId {
@ -228,7 +230,7 @@ mod test {
#[async_test] #[async_test]
async fn room_member_events() { async fn room_member_events() {
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();
@ -252,7 +254,7 @@ mod test {
#[async_test] #[async_test]
async fn member_presence_events() { async fn member_presence_events() {
let client = get_client(); let client = get_client().await;
let room_id = get_room_id(); let room_id = get_room_id();

View File

@ -360,7 +360,8 @@ mod test {
// a sync response to populate our JSON store // a sync response to populate our JSON store
let store = Box::new(JsonStore::open(path).unwrap()); let store = Box::new(JsonStore::open(path).unwrap());
let client = BaseClient::new_with_state_store(Some(session.clone()), store).unwrap(); let client = BaseClient::new_with_state_store(store).unwrap();
client.restore_login(session.clone()).await.unwrap();
let mut response = sync_response("../test_data/sync.json"); let mut response = sync_response("../test_data/sync.json");
@ -369,7 +370,8 @@ mod test {
// now syncing the client will update from the state store // now syncing the client will update from the state store
let store = Box::new(JsonStore::open(path).unwrap()); let store = Box::new(JsonStore::open(path).unwrap());
let client = BaseClient::new_with_state_store(Some(session.clone()), store).unwrap(); let client = BaseClient::new_with_state_store(store).unwrap();
client.restore_login(session.clone()).await.unwrap();
client.sync_with_state_store().await.unwrap(); client.sync_with_state_store().await.unwrap();
// assert the synced client and the logged in client are equal // assert the synced client and the logged in client are equal

View File

@ -14,9 +14,9 @@ version = "0.1.0"
js_int = "0.1.5" js_int = "0.1.5"
ruma-api = "0.16.1" ruma-api = "0.16.1"
ruma-client-api = "0.8.0" ruma-client-api = "0.8.0"
ruma-events = "0.21.1" ruma-events = "0.21.2"
ruma-identifiers = "0.16.1" ruma-identifiers = "0.16.1"
instant = { version = "0.1.3", features = ["wasm-bindgen", "now"] } instant = { version = "0.1.4", features = ["wasm-bindgen", "now"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
uuid = { version = "0.8.1", features = ["v4"] } uuid = { version = "0.8.1", features = ["v4"] }

View File

@ -27,7 +27,7 @@ zeroize = { version = "1.1.0", features = ["zeroize_derive"] }
url = "2.1.1" url = "2.1.1"
# Misc dependencies # Misc dependencies
thiserror = "1.0.17" thiserror = "1.0.18"
tracing = "0.1.14" tracing = "0.1.14"
atomic = "0.4.5" atomic = "0.4.5"
dashmap = "3.11.1" dashmap = "3.11.1"