diff --git a/matrix_sdk/Cargo.toml b/matrix_sdk/Cargo.toml index 46372aa4..cc1ba580 100644 --- a/matrix_sdk/Cargo.toml +++ b/matrix_sdk/Cargo.toml @@ -28,14 +28,15 @@ socks = ["reqwest/socks"] docs = ["encryption", "sqlite_cryptostore", "messages"] [dependencies] -async-trait = "0.1.40" +async-trait = "0.1.41" dashmap = { version = "3.11.10", optional = true } http = "0.2.1" -serde_json = "1.0.57" -thiserror = "1.0.20" -tracing = "0.1.19" +serde_json = "1.0.58" +thiserror = "1.0.21" +tracing = "0.1.21" url = "2.1.1" -zeroize = "1.1.0" +zeroize = "1.1.1" +mime = "0.3.16" matrix-sdk-common-macros = { version = "0.1.0", path = "../matrix_sdk_common_macros" } matrix-sdk-common = { version = "0.1.0", path = "../matrix_sdk_common" } @@ -67,17 +68,17 @@ version = "3.0.2" features = ["wasm-bindgen"] [dev-dependencies] -async-trait = "0.1.40" +async-trait = "0.1.41" async-std = { version = "1.6.5", features = ["unstable"] } dirs = "3.0.1" matrix-sdk-test = { version = "0.1.0", path = "../matrix_sdk_test" } tokio = { version = "0.2.22", features = ["rt-threaded", "macros"] } -serde_json = "1.0.57" -tracing-subscriber = "0.2.11" +serde_json = "1.0.58" +tracing-subscriber = "0.2.13" tempfile = "3.1.0" mockito = "0.27.0" lazy_static = "1.4.0" -futures = "0.3.5" +futures = "0.3.6" [[example]] name = "emoji_verification" diff --git a/matrix_sdk/examples/autojoin.rs b/matrix_sdk/examples/autojoin.rs index 2af9a61b..a5edc34b 100644 --- a/matrix_sdk/examples/autojoin.rs +++ b/matrix_sdk/examples/autojoin.rs @@ -1,4 +1,5 @@ use std::{env, process::exit}; +use tokio::time::{delay_for, Duration}; use matrix_sdk::{ self, @@ -32,11 +33,27 @@ impl EventEmitter for AutoJoinBot { if let SyncRoom::Invited(room) = room { let room = room.read().await; - println!("Autojoining room {}", room.display_name()); - self.client - .join_room_by_id(&room.room_id) - .await - .expect("Can't join room"); + println!("Autojoining room {}", room.room_id); + let mut delay = 2; + + while let Err(err) = self.client.join_room_by_id(&room.room_id).await { + // retry autojoin due to synapse sending invites, before the + // invited user can join for more information see + // https://github.com/matrix-org/synapse/issues/4345 + eprintln!( + "Failed to join room {} ({:?}), retrying in {}s", + room.room_id, err, delay + ); + + delay_for(Duration::from_secs(delay)).await; + delay *= 2; + + if delay > 3600 { + eprintln!("Can't join room {} ({:?})", room.room_id, err); + break; + } + } + println!("Successfully joined room {}", room.room_id); } } } diff --git a/matrix_sdk/examples/image_bot.rs b/matrix_sdk/examples/image_bot.rs index 68099d89..141d0d56 100644 --- a/matrix_sdk/examples/image_bot.rs +++ b/matrix_sdk/examples/image_bot.rs @@ -52,7 +52,7 @@ impl EventEmitter for ImageBot { let mut image = self.image.lock().await; self.client - .room_send_attachment(&room_id, "cat", "image/jpg", &mut *image, None) + .room_send_attachment(&room_id, "cat", &mime::IMAGE_JPEG, &mut *image, None) .await .unwrap(); diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index 6fcd4835..5b6fc4b5 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -30,6 +30,7 @@ use std::{ use dashmap::DashMap; use futures_timer::Delay as sleep; use http::HeaderValue; +use mime::{self, Mime}; use reqwest::header::InvalidHeaderValue; use url::Url; #[cfg(feature = "encryption")] @@ -871,12 +872,9 @@ impl Client { self.send(request).await } - /// Get messages starting at a specific sync point using the - /// `MessagesRequestBuilder`s `from` field as a starting point. - /// - /// Sends a request to `/_matrix/client/r0/rooms/{room_id}/messages` and - /// returns a `get_message_events::Response` that contains chunks - /// of `RoomEvents`. + /// Sends a request to `/_matrix/client/r0/rooms/{room_id}/messages` and returns + /// a `get_message_events::Response` that contains a chunk of room and state events + /// (`AnyRoomEvent` and `AnyStateEvent`). /// /// # Arguments /// @@ -1162,6 +1160,7 @@ impl Client { /// # use std::{path::PathBuf, fs::File, io::Read}; /// # use matrix_sdk::{Client, identifiers::room_id}; /// # use url::Url; + /// # use mime; /// # use futures::executor::block_on; /// # block_on(async { /// # let homeserver = Url::parse("http://localhost:8080").unwrap(); @@ -1171,7 +1170,7 @@ impl Client { /// let mut image = File::open(path).unwrap(); /// /// let response = client - /// .room_send_attachment(&room_id, "My favorite cat", "image/jpg", &mut image, None) + /// .room_send_attachment(&room_id, "My favorite cat", &mime::IMAGE_JPEG, &mut image, None) /// .await /// .expect("Can't upload my cat."); /// # }); @@ -1180,7 +1179,7 @@ impl Client { &self, room_id: &RoomId, body: &str, - content_type: &str, + content_type: &Mime, mut reader: &mut R, txn_id: Option, ) -> Result { @@ -1188,9 +1187,9 @@ impl Client { #[cfg(feature = "encryption")] let mut reader = AttachmentEncryptor::new(reader); #[cfg(feature = "encryption")] - let content_type = "application/octet-stream"; + let content_type = mime::APPLICATION_OCTET_STREAM; - let response = self.upload(content_type, &mut reader).await?; + let response = self.upload(&content_type, &mut reader).await?; #[cfg(feature = "encryption")] let keys = { @@ -1208,42 +1207,41 @@ impl Client { (response, keys) } else { - let response = self.upload(content_type, &mut reader).await?; + let response = self.upload(&content_type, &mut reader).await?; (response, None) }; let url = response.content_uri; - let content = if content_type.starts_with("image") { - // TODO create a thumbnail using the image crate?. - MessageEventContent::Image(ImageMessageEventContent { + let content = match content_type.type_() { + mime::IMAGE => { + // TODO create a thumbnail using the image crate?. + MessageEventContent::Image(ImageMessageEventContent { + body: body.to_owned(), + info: None, + url: Some(url), + file: encrypted_file, + }) + } + mime::AUDIO => MessageEventContent::Audio(AudioMessageEventContent { body: body.to_owned(), info: None, url: Some(url), file: encrypted_file, - }) - } else if content_type.starts_with("audio") { - MessageEventContent::Audio(AudioMessageEventContent { + }), + mime::VIDEO => MessageEventContent::Video(VideoMessageEventContent { body: body.to_owned(), info: None, url: Some(url), file: encrypted_file, - }) - } else if content_type.starts_with("video") { - MessageEventContent::Video(VideoMessageEventContent { - body: body.to_owned(), - info: None, - url: Some(url), - file: encrypted_file, - }) - } else { - MessageEventContent::File(FileMessageEventContent { + }), + _ => MessageEventContent::File(FileMessageEventContent { filename: None, body: body.to_owned(), info: None, url: Some(url), file: encrypted_file, - }) + }), }; self.room_send( @@ -1271,6 +1269,7 @@ impl Client { /// # use matrix_sdk::{Client, identifiers::room_id}; /// # use url::Url; /// # use futures::executor::block_on; + /// # use mime; /// # block_on(async { /// # let homeserver = Url::parse("http://localhost:8080").unwrap(); /// # let mut client = Client::new(homeserver).unwrap(); @@ -1278,7 +1277,7 @@ impl Client { /// let mut image = File::open(path).unwrap(); /// /// let response = client - /// .upload("image/jpg", &mut image) + /// .upload(&mime::IMAGE_JPEG, &mut image) /// .await /// .expect("Can't upload my cat."); /// @@ -1287,13 +1286,13 @@ impl Client { /// ``` pub async fn upload( &self, - content_type: &str, + content_type: &Mime, reader: &mut impl Read, ) -> Result { let mut data = Vec::new(); reader.read_to_end(&mut data)?; - let request = create_content::Request::new(content_type, data); + let request = create_content::Request::new(content_type.essence_str(), data); self.http_client.upload(request).await } @@ -2524,7 +2523,7 @@ mod test { Matcher::Regex(r"^/_matrix/media/r0/upload".to_string()), ) .with_status(200) - .match_header("content-type", "image/jpg") + .match_header("content-type", "image/jpeg") .with_body( json!({ "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" @@ -2538,7 +2537,7 @@ mod test { let mut media = Cursor::new("Hello world"); let response = client - .room_send_attachment(&room_id, "image", "image/jpg", &mut media, None) + .room_send_attachment(&room_id, "image", &mime::IMAGE_JPEG, &mut media, None) .await .unwrap(); diff --git a/matrix_sdk/src/lib.rs b/matrix_sdk/src/lib.rs index 0b97e007..3cb65f27 100644 --- a/matrix_sdk/src/lib.rs +++ b/matrix_sdk/src/lib.rs @@ -15,7 +15,24 @@ //! This crate implements a [Matrix](https://matrix.org/) client library. //! -//! ## Crate Feature Flags +//! # Enabling logging +//! +//! Users of the matrix-sdk crate can enable log output by depending on the `tracing-subscriber` +//! crate and including the following line in their application (e.g. at the start of `main`): +//! +//! ```rust +//! tracing_subscriber::fmt::init(); +//! ``` +//! +//! The log output is controlled via the `RUST_LOG` environment variable by setting it to one of +//! the `error`, `warn`, `info`, `debug` or `trace` levels. The output is printed to stdout. +//! +//! The `RUST_LOG` variable also supports a more advanced syntax for filtering log output more +//! precisely, for instance with crate-level granularity. For more information on this, check out +//! the [tracing_subscriber +//! documentation](https://tracing.rs/tracing_subscriber/filter/struct.envfilter). +//! +//! # Crate Feature Flags //! //! The following crate feature flags are available: //! diff --git a/matrix_sdk_base/Cargo.toml b/matrix_sdk_base/Cargo.toml index 25c868d7..7d8de457 100644 --- a/matrix_sdk_base/Cargo.toml +++ b/matrix_sdk_base/Cargo.toml @@ -24,18 +24,18 @@ unstable-synapse-quirks = ["matrix-sdk-common/unstable-synapse-quirks"] docs = ["encryption", "sqlite_cryptostore", "messages"] [dependencies] -async-trait = "0.1.40" -serde = "1.0.115" -serde_json = "1.0.57" -zeroize = "1.1.0" -tracing = "0.1.19" +async-trait = "0.1.41" +serde = "1.0.116" +serde_json = "1.0.58" +zeroize = "1.1.1" +tracing = "0.1.21" matrix-sdk-common-macros = { version = "0.1.0", path = "../matrix_sdk_common_macros" } matrix-sdk-common = { version = "0.1.0", path = "../matrix_sdk_common" } matrix-sdk-crypto = { version = "0.1.0", path = "../matrix_sdk_crypto", optional = true } # Misc dependencies -thiserror = "1.0.20" +thiserror = "1.0.21" [target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio] version = "0.2.22" @@ -43,10 +43,10 @@ default-features = false features = ["sync", "fs"] [dev-dependencies] -futures = "0.3.5" +futures = "0.3.6" matrix-sdk-test = { version = "0.1.0", path = "../matrix_sdk_test" } http = "0.2.1" -tracing-subscriber = "0.2.11" +tracing-subscriber = "0.2.13" tempfile = "3.1.0" mockito = "0.27.0" @@ -54,4 +54,4 @@ mockito = "0.27.0" tokio = { version = "0.2.22", features = ["rt-threaded", "macros"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test = "0.3.17" +wasm-bindgen-test = "0.3.18" diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index 9ac9a6e8..6557a69b 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -1886,6 +1886,16 @@ impl BaseClient { } } + /// Get the user login session. + /// + /// If the client is currently logged in, this will return a `matrix_sdk::Session` object which + /// can later be given to `restore_login`. + /// + /// Returns a session object if the client is logged in. Otherwise returns `None`. + pub async fn get_session(&self) -> Option { + self.session.read().await.clone() + } + /// Get a map holding all the devices of an user. /// /// This will always return an empty map if the client hasn't been logged diff --git a/matrix_sdk_base/src/models/room.rs b/matrix_sdk_base/src/models/room.rs index aa333c57..6892c50a 100644 --- a/matrix_sdk_base/src/models/room.rs +++ b/matrix_sdk_base/src/models/room.rs @@ -647,7 +647,7 @@ impl Room { if state_event && !self.member_is_tracked(&target_user) { debug!( - "handle_membership: User {user_id} is {state} the room {room_id} ({room_name})", + "handle_membership: User {user_id} {state} the room {room_id} ({room_name})", user_id = target_user, state = event.content.membership.describe(), room_id = self.room_id, @@ -1089,8 +1089,8 @@ impl Describe for MembershipState { Self::Ban => "is banned in", Self::Invite => "is invited to", Self::Join => "is a member of", - Self::Knock => "is requesting access", - Self::Leave => "left", + Self::Knock => "is requesting access to", + Self::Leave => "has left", } .to_string() } @@ -1112,12 +1112,12 @@ impl Describe for MembershipChange { displayname_changed, avatar_url_changed, } => match (*displayname_changed, *avatar_url_changed) { - (true, true) => "changed their displayname and avatar", - (true, false) => "changed their displayname", - (false, true) => "changed their avatar", + (true, true) => "changed their displayname and avatar in", + (true, false) => "changed their displayname in", + (false, true) => "changed their avatar in", _ => { error!("Got ProfileChanged but nothing changed"); - "impossible: changed nothing in their profile" + "impossible: changed nothing in their profile in" } }, Self::None => "did nothing in", diff --git a/matrix_sdk_base/src/session.rs b/matrix_sdk_base/src/session.rs index b240b5d0..bae61166 100644 --- a/matrix_sdk_base/src/session.rs +++ b/matrix_sdk_base/src/session.rs @@ -15,11 +15,13 @@ //! User sessions. +use serde::{Deserialize, Serialize}; + use matrix_sdk_common::identifiers::{DeviceId, UserId}; /// A user session, containing an access token and information about the /// associated user account. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct Session { /// The access token used for this session. pub access_token: String, diff --git a/matrix_sdk_common/Cargo.toml b/matrix_sdk_common/Cargo.toml index 6eb38e5d..05aded63 100644 --- a/matrix_sdk_common/Cargo.toml +++ b/matrix_sdk_common/Cargo.toml @@ -15,7 +15,7 @@ unstable-synapse-quirks = ["ruma/unstable-synapse-quirks"] [dependencies] assign = "1.1.0" -instant = { version = "0.1.6", features = ["wasm-bindgen", "now"] } +instant = { version = "0.1.7", features = ["wasm-bindgen", "now"] } js_int = "0.1.9" [dependencies.ruma] diff --git a/matrix_sdk_common_macros/Cargo.toml b/matrix_sdk_common_macros/Cargo.toml index b48aa9b1..fab5eea7 100644 --- a/matrix_sdk_common_macros/Cargo.toml +++ b/matrix_sdk_common_macros/Cargo.toml @@ -14,5 +14,5 @@ version = "0.1.0" proc-macro = true [dependencies] -syn = "1.0.40" +syn = "1.0.44" quote = "1.0.7" diff --git a/matrix_sdk_crypto/Cargo.toml b/matrix_sdk_crypto/Cargo.toml index aa3bbb3a..023c9cb3 100644 --- a/matrix_sdk_crypto/Cargo.toml +++ b/matrix_sdk_crypto/Cargo.toml @@ -20,29 +20,29 @@ sqlite_cryptostore = ["sqlx"] docs = ["sqlite_cryptostore"] [dependencies] -async-trait = "0.1.40" +async-trait = "0.1.41" matrix-sdk-common-macros = { version = "0.1.0", path = "../matrix_sdk_common_macros" } matrix-sdk-common = { version = "0.1.0", path = "../matrix_sdk_common" } -olm-rs = { version = "0.6.0", features = ["serde"] } +olm-rs = { version = "1.0.0", features = ["serde"] } getrandom = "0.2.0" -serde = { version = "1.0.115", features = ["derive", "rc"] } -serde_json = "1.0.57" +serde = { version = "1.0.116", features = ["derive", "rc"] } +serde_json = "1.0.58" cjson = "0.1.1" -zeroize = { version = "1.1.0", features = ["zeroize_derive"] } +zeroize = { version = "1.1.1", features = ["zeroize_derive"] } url = "2.1.1" # Misc dependencies -thiserror = "1.0.20" -tracing = "0.1.19" +thiserror = "1.0.21" +tracing = "0.1.21" atomic = "0.5.0" dashmap = "3.11.10" sha2 = "0.9.1" -aes-ctr = "0.4.0" +aes-ctr = "0.5.0" pbkdf2 = { version = "0.5.0", default-features = false } hmac = "0.9.0" -base64 = "0.12.3" +base64 = "0.13.0" byteorder = "1.3.4" [dependencies.tracing-futures] @@ -58,10 +58,10 @@ features = ["runtime-tokio", "sqlite", "macros"] [dev-dependencies] tokio = { version = "0.2.22", features = ["rt-threaded", "macros"] } -futures = "0.3.5" +futures = "0.3.6" proptest = "0.10.1" -serde_json = "1.0.57" +serde_json = "1.0.58" tempfile = "3.1.0" http = "0.2.1" matrix-sdk-test = { version = "0.1.0", path = "../matrix_sdk_test" } -indoc = "1.0.2" +indoc = "1.0.3" diff --git a/matrix_sdk_crypto/src/store/sqlite.rs b/matrix_sdk_crypto/src/store/sqlite.rs index 17c525c2..fe67e2d6 100644 --- a/matrix_sdk_crypto/src/store/sqlite.rs +++ b/matrix_sdk_crypto/src/store/sqlite.rs @@ -1219,7 +1219,8 @@ impl CryptoStore for SqliteStore { ) VALUES (?1, ?2, ?3, ?4, ?5) ON CONFLICT(user_id, device_id) DO UPDATE SET pickle = excluded.pickle, - shared = excluded.shared + shared = excluded.shared, + uploaded_key_count = excluded.uploaded_key_count ", ) .bind(pickle.user_id.as_str()) @@ -1612,6 +1613,7 @@ mod test { .expect("Can't save account"); account.mark_as_shared(); + account.update_uploaded_key_count(50); store .save_account(account.clone()) @@ -1622,6 +1624,10 @@ mod test { let loaded_account = loaded_account.unwrap(); assert_eq!(account, loaded_account); + assert_eq!( + account.uploaded_key_count(), + loaded_account.uploaded_key_count() + ); } #[tokio::test] diff --git a/matrix_sdk_test/Cargo.toml b/matrix_sdk_test/Cargo.toml index 4c58f638..108ad599 100644 --- a/matrix_sdk_test/Cargo.toml +++ b/matrix_sdk_test/Cargo.toml @@ -11,9 +11,9 @@ repository = "https://github.com/matrix-org/matrix-rust-sdk" version = "0.1.0" [dependencies] -serde_json = "1.0.57" +serde_json = "1.0.58" http = "0.2.1" matrix-sdk-common = { version = "0.1.0", path = "../matrix_sdk_common" } matrix-sdk-test-macros = { version = "0.1.0", path = "../matrix_sdk_test_macros" } lazy_static = "1.4.0" -serde = "1.0.115" +serde = "1.0.116"