Merge remote-tracking branch 'origin/main' into gnunicorn/issue756
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# Conventional Commits
|
||||
|
||||
This project uses [Conventional
|
||||
Commits](https://www.conventionalcommits.org/). Read the
|
||||
[Summary](https://www.conventionalcommits.org/en/v1.0.0/#summary) or
|
||||
the [Full
|
||||
Specification](https://www.conventionalcommits.org/en/v1.0.0/#specification)
|
||||
to learn more.
|
||||
|
||||
## Types
|
||||
|
||||
Conventional Commits defines _type_ (as in `type(scope):
|
||||
message`). This section aims at listing the types used inside this
|
||||
project:
|
||||
|
||||
| Type | Definition |
|
||||
|-|-|
|
||||
| `feat` | About a new feature. |
|
||||
| `fix` | About a bug fix. |
|
||||
| `test` | About a test (suite, case, runner…). |
|
||||
| `doc` | About a documentation modification. |
|
||||
| `refactor` | About a refactoring. |
|
||||
| `ci` | About a Continuous Integration modification. |
|
||||
| `chore` | About some cleanup, or regular tasks. |
|
||||
|
||||
## Scopes
|
||||
|
||||
Conventional Commits defines _scope_ (as in `type(scope): message`). This
|
||||
section aims at listing all the scopes used inside this project:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Group</th>
|
||||
<th>Scope</th>
|
||||
<th>Definition</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td rowspan="10">Crates</td>
|
||||
<td><code>sdk</code></td>
|
||||
<td>About the <code>matrix-sdk</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>appservice</code></td>
|
||||
<td>About the <code>matrix-sdk-appservice</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>base</code></td>
|
||||
<td>About the <code>matrix-sdk-base</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>common</code></td>
|
||||
<td>About the <code>matrix-sdk-common</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>crypto</code></td>
|
||||
<td>About the <code>matrix-sdk-crypto</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>indexeddb</code></td>
|
||||
<td>About the <code>matrix-sdk-indexeddb</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>qrcode</code></td>
|
||||
<td>About the <code>matrix-sdk-qrcode</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sled</code></td>
|
||||
<td>About the <code>matrix-sdk-sled</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>store-encryption</code></td>
|
||||
<td>About the <code>matrix-sdk-store-encryption</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>test</code></td>
|
||||
<td>About the <code>matrix-sdk-test</code> and <code>matrix-sdk-test-macros</code> crate.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="4">Bindings</td>
|
||||
<td><code>apple</code></td>
|
||||
<td>About the <code>matrix-rust-components-swift</code> binding.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>crypto-nodejs</code></td>
|
||||
<td>About the <code>matrix-sdk-crypto-nodejs</code> binding.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>crypto-js</code></td>
|
||||
<td>About the <code>matrix-sdk-crypto-js</code> binding.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>crypto-ffi</code></td>
|
||||
<td>About the <code>matrix-sdk-crypto-ffi</code> binding.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Labs</td>
|
||||
<td><code>sled-state-inspector</code></td>
|
||||
<td>About the <code>sled-state-inspector</code> project.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Continuous Integration</td>
|
||||
<td><code>xtask</code></td>
|
||||
<td>About the <code>xtask</code> project.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Generating `CHANGELOG.md`
|
||||
|
||||
The [`git-cliff`](https://github.com/orhun/git-cliff) project is used
|
||||
to generate `CHANGELOG.md` automatically. Hence the various
|
||||
`cliff.toml` files that are present in this project, or the
|
||||
`package.metadata.git-cliff` sections in various `Cargo.toml` files.
|
||||
|
||||
Its companion,
|
||||
[`git-cliff-action`](https://github.com/orhun/git-cliff-action)
|
||||
project, is used inside Github Action workflows.
|
||||
@@ -63,7 +63,7 @@ pub fn keys_query(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("Keys querying");
|
||||
group.throughput(Throughput::Elements(count as u64));
|
||||
|
||||
let name = format!("{} device and cross signing keys", count);
|
||||
let name = format!("{count} device and cross signing keys");
|
||||
|
||||
group.bench_with_input(BenchmarkId::new("memory store", &name), &response, |b, response| {
|
||||
b.to_async(&runtime)
|
||||
@@ -96,7 +96,7 @@ pub fn keys_claiming(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("Olm session creation");
|
||||
group.throughput(Throughput::Elements(count as u64));
|
||||
|
||||
let name = format!("{} one-time keys", count);
|
||||
let name = format!("{count} one-time keys");
|
||||
|
||||
group.bench_with_input(BenchmarkId::new("memory store", &name), &response, |b, response| {
|
||||
b.iter_batched(
|
||||
@@ -158,7 +158,7 @@ pub fn room_key_sharing(c: &mut Criterion) {
|
||||
|
||||
let mut group = c.benchmark_group("Room key sharing");
|
||||
group.throughput(Throughput::Elements(count as u64));
|
||||
let name = format!("{} devices", count);
|
||||
let name = format!("{count} devices");
|
||||
|
||||
group.bench_function(BenchmarkId::new("memory store", &name), |b| {
|
||||
b.to_async(&runtime).iter(|| async {
|
||||
@@ -225,7 +225,7 @@ pub fn devices_missing_sessions_collecting(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("Devices missing sessions collecting");
|
||||
group.throughput(Throughput::Elements(count as u64));
|
||||
|
||||
let name = format!("{} devices", count);
|
||||
let name = format!("{count} devices");
|
||||
|
||||
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "matrix-sdk-crypto-ffi"
|
||||
version = "0.1.0"
|
||||
authors = ["Damir Jelić <poljar@termina.org.uk>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
description = "Uniffi based bindings for the Rust SDK crypto crate"
|
||||
repository = "https://github.com/matrix-org/matrix-rust-sdk"
|
||||
|
||||
@@ -14,7 +14,7 @@ mod responses;
|
||||
mod users;
|
||||
mod verification;
|
||||
|
||||
use std::{borrow::Borrow, collections::HashMap, convert::TryFrom, str::FromStr, sync::Arc};
|
||||
use std::{borrow::Borrow, collections::HashMap, str::FromStr, sync::Arc};
|
||||
|
||||
pub use backup_recovery_key::{
|
||||
BackupRecoveryKey, DecodeError, MegolmV1BackupKey, PassphraseInfo, PkDecryptionError,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
convert::TryInto,
|
||||
io::Cursor,
|
||||
ops::Deref,
|
||||
sync::Arc,
|
||||
|
||||
@@ -62,8 +62,7 @@ where
|
||||
Ok(unsafe { T::ref_from_abi(pointer) })
|
||||
} else {
|
||||
Err(JsError::new(&format!(
|
||||
"Expect an `{}` instance, received `{}` instead",
|
||||
classname, constructor_name,
|
||||
"Expect an `{classname}` instance, received `{constructor_name}` instead",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ mod inner {
|
||||
|
||||
let origin = metadata
|
||||
.file()
|
||||
.and_then(|file| metadata.line().map(|ln| format!("{}:{}", file, ln)))
|
||||
.and_then(|file| metadata.line().map(|ln| format!("{file}:{ln}")))
|
||||
.unwrap_or_default();
|
||||
|
||||
let message = format!("{level} {origin}{recorder}");
|
||||
@@ -240,11 +240,11 @@ mod inner {
|
||||
self.string.push('\n');
|
||||
}
|
||||
|
||||
let _ = write!(self.string, "{:?}", value);
|
||||
let _ = write!(self.string, "{value:?}");
|
||||
}
|
||||
|
||||
field_name => {
|
||||
let _ = write!(self.string, "\n{} = {:?}", field_name, value);
|
||||
let _ = write!(self.string, "\n{field_name} = {value:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ interface MediaSource {
|
||||
[Error]
|
||||
enum AuthenticationError {
|
||||
"ClientMissing",
|
||||
"SessionMissing",
|
||||
"Generic",
|
||||
};
|
||||
|
||||
@@ -178,6 +179,9 @@ interface AuthenticationService {
|
||||
|
||||
[Throws=AuthenticationError]
|
||||
Client login(string username, string password);
|
||||
|
||||
[Throws=AuthenticationError]
|
||||
Client restore_with_access_token(string token, string device_id);
|
||||
};
|
||||
|
||||
interface SessionVerificationEmoji {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures_util::future::join3;
|
||||
use matrix_sdk::{
|
||||
ruma::{OwnedDeviceId, UserId},
|
||||
Session,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use super::{client::Client, client_builder::ClientBuilder, RUNTIME};
|
||||
@@ -15,6 +19,8 @@ pub struct AuthenticationService {
|
||||
pub enum AuthenticationError {
|
||||
#[error("A successful call to use_server must be made first.")]
|
||||
ClientMissing,
|
||||
#[error("Login was successful but is missing a valid Session to configure the file store.")]
|
||||
SessionMissing,
|
||||
#[error("An error occurred: {message}")]
|
||||
Generic { message: String },
|
||||
}
|
||||
@@ -66,14 +72,12 @@ impl AuthenticationService {
|
||||
/// Updates the service to authenticate with the homeserver for the
|
||||
/// specified address.
|
||||
pub fn configure_homeserver(&self, server_name: String) -> Result<(), AuthenticationError> {
|
||||
// Construct a username as the builder currently requires one.
|
||||
let username = format!("@auth:{}", server_name);
|
||||
|
||||
let mut builder =
|
||||
Arc::new(ClientBuilder::new()).base_path(self.base_path.clone()).username(username);
|
||||
let mut builder = Arc::new(ClientBuilder::new()).base_path(self.base_path.clone());
|
||||
|
||||
if server_name.starts_with("http://") || server_name.starts_with("https://") {
|
||||
builder = builder.homeserver_url(server_name)
|
||||
} else {
|
||||
builder = builder.server_name(server_name);
|
||||
}
|
||||
|
||||
let client = builder.build().map_err(AuthenticationError::from)?;
|
||||
@@ -96,18 +100,74 @@ impl AuthenticationService {
|
||||
) -> Result<Arc<Client>, AuthenticationError> {
|
||||
match self.client.read().as_ref() {
|
||||
Some(client) => {
|
||||
let homeserver_url = client.homeserver();
|
||||
// Login and ask the server for the full user ID as this could be different from
|
||||
// the username that was entered.
|
||||
client.login(username, password).map_err(AuthenticationError::from)?;
|
||||
let whoami = client.whoami()?;
|
||||
|
||||
// Create a new client to setup the store path for the username
|
||||
// Create a new client to setup the store path now the user ID is known.
|
||||
let homeserver_url = client.homeserver();
|
||||
let session = client.session().ok_or(AuthenticationError::SessionMissing)?;
|
||||
let client = Arc::new(ClientBuilder::new())
|
||||
.base_path(self.base_path.clone())
|
||||
.homeserver_url(homeserver_url)
|
||||
.username(username.clone())
|
||||
.username(whoami.user_id.to_string())
|
||||
.build()
|
||||
.map_err(AuthenticationError::from)?;
|
||||
|
||||
// Restore the client using the session from the login request.
|
||||
client
|
||||
.login(username, password)
|
||||
.restore_session(session.clone())
|
||||
.map(|_| client.clone())
|
||||
.map_err(AuthenticationError::from)
|
||||
}
|
||||
None => Err(AuthenticationError::ClientMissing),
|
||||
}
|
||||
}
|
||||
|
||||
/// Restore an existing session on the current homeserver using an access
|
||||
/// token issued by an authentication server.
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `token` - The access token issued by the authentication server.
|
||||
///
|
||||
/// * `device_id` - The device ID that the access token was scoped for.
|
||||
pub fn restore_with_access_token(
|
||||
&self,
|
||||
token: String,
|
||||
device_id: String,
|
||||
) -> Result<Arc<Client>, AuthenticationError> {
|
||||
match self.client.read().as_ref() {
|
||||
Some(client) => {
|
||||
// Restore the client and ask the server for the full user ID as this
|
||||
// could be different from the username that was entered.
|
||||
let discovery_user_id = UserId::parse("@unknown:unknown")
|
||||
.map_err(|e| AuthenticationError::Generic { message: e.to_string() })?;
|
||||
let device_id: OwnedDeviceId = device_id.as_str().into();
|
||||
|
||||
let discovery_session = Session {
|
||||
access_token: token.clone(),
|
||||
user_id: discovery_user_id,
|
||||
device_id: device_id.clone(),
|
||||
};
|
||||
|
||||
client.restore_session(discovery_session).map_err(AuthenticationError::from)?;
|
||||
let whoami = client.whoami()?;
|
||||
|
||||
// Create the actual client with a store path from the user ID.
|
||||
let homeserver_url = client.homeserver();
|
||||
let session =
|
||||
Session { access_token: token, user_id: whoami.user_id.clone(), device_id };
|
||||
let client = Arc::new(ClientBuilder::new())
|
||||
.base_path(self.base_path.clone())
|
||||
.homeserver_url(homeserver_url)
|
||||
.username(whoami.user_id.to_string())
|
||||
.build()
|
||||
.map_err(AuthenticationError::from)?;
|
||||
|
||||
// Restore the client using the session.
|
||||
client
|
||||
.restore_session(session)
|
||||
.map(|_| client.clone())
|
||||
.map_err(AuthenticationError::from)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
media::{MediaFormat, MediaRequest},
|
||||
ruma::{
|
||||
api::client::{
|
||||
account::whoami,
|
||||
filter::{FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter},
|
||||
session::get_login_types,
|
||||
sync::sync_events::v3::Filter,
|
||||
@@ -12,7 +14,7 @@ use matrix_sdk::{
|
||||
events::room::MediaSource,
|
||||
TransactionId,
|
||||
},
|
||||
Client as MatrixClient, LoopCtrl,
|
||||
Client as MatrixClient, LoopCtrl, Session,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
@@ -51,6 +53,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/// Login using a username and password.
|
||||
pub fn login(&self, username: String, password: String) -> anyhow::Result<()> {
|
||||
RUNTIME.block_on(async move {
|
||||
self.client.login_username(&username, &password).send().await?;
|
||||
@@ -58,10 +61,16 @@ impl Client {
|
||||
})
|
||||
}
|
||||
|
||||
/// Restores the client from a `RestoreToken`.
|
||||
pub fn restore_login(&self, restore_token: String) -> anyhow::Result<()> {
|
||||
let RestoreToken { session, homeurl: _, is_guest: _ } =
|
||||
serde_json::from_str(&restore_token)?;
|
||||
|
||||
self.restore_session(session)
|
||||
}
|
||||
|
||||
/// Restores the client from a `Session`.
|
||||
pub fn restore_session(&self, session: Session) -> anyhow::Result<()> {
|
||||
RUNTIME.block_on(async move {
|
||||
self.client.restore_login(session).await?;
|
||||
Ok(())
|
||||
@@ -97,6 +106,12 @@ impl Client {
|
||||
Ok(supports_password)
|
||||
}
|
||||
|
||||
/// Gets information about the owner of a given access token.
|
||||
pub fn whoami(&self) -> anyhow::Result<whoami::v3::Response> {
|
||||
RUNTIME
|
||||
.block_on(async move { self.client.whoami().await.map_err(|e| anyhow!(e.to_string())) })
|
||||
}
|
||||
|
||||
pub fn start_sync(&self) {
|
||||
let client = self.client.clone();
|
||||
let state = self.state.clone();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use std::{fs, path::PathBuf, sync::Arc};
|
||||
|
||||
use anyhow::Context;
|
||||
use anyhow::anyhow;
|
||||
use matrix_sdk::{
|
||||
ruma::UserId, store::make_store_config, Client as MatrixClient,
|
||||
ClientBuilder as MatrixClientBuilder,
|
||||
ruma::{ServerName, UserId},
|
||||
store::make_store_config,
|
||||
Client as MatrixClient, ClientBuilder as MatrixClientBuilder,
|
||||
};
|
||||
use sanitize_filename_reader_friendly::sanitize;
|
||||
|
||||
@@ -13,6 +14,7 @@ use super::{client::Client, ClientState, RUNTIME};
|
||||
pub struct ClientBuilder {
|
||||
base_path: Option<String>,
|
||||
username: Option<String>,
|
||||
server_name: Option<String>,
|
||||
homeserver_url: Option<String>,
|
||||
inner: MatrixClientBuilder,
|
||||
}
|
||||
@@ -22,6 +24,7 @@ impl ClientBuilder {
|
||||
Self {
|
||||
base_path: None,
|
||||
username: None,
|
||||
server_name: None,
|
||||
homeserver_url: None,
|
||||
inner: MatrixClient::builder().user_agent("rust-sdk-ios"),
|
||||
}
|
||||
@@ -39,6 +42,12 @@ impl ClientBuilder {
|
||||
Arc::new(builder)
|
||||
}
|
||||
|
||||
pub fn server_name(self: Arc<Self>, server_name: String) -> Arc<Self> {
|
||||
let mut builder = unwrap_or_clone_arc(self);
|
||||
builder.server_name = Some(server_name);
|
||||
Arc::new(builder)
|
||||
}
|
||||
|
||||
pub fn homeserver_url(self: Arc<Self>, url: String) -> Arc<Self> {
|
||||
let mut builder = unwrap_or_clone_arc(self);
|
||||
builder.homeserver_url = Some(url);
|
||||
@@ -47,25 +56,30 @@ impl ClientBuilder {
|
||||
|
||||
pub fn build(self: Arc<Self>) -> anyhow::Result<Arc<Client>> {
|
||||
let builder = unwrap_or_clone_arc(self);
|
||||
let mut inner_builder = builder.inner;
|
||||
|
||||
let base_path = builder.base_path.context("Base path was not set")?;
|
||||
let username = builder
|
||||
.username
|
||||
.context("Username to determine homeserver and home path was not set")?;
|
||||
if let (Some(base_path), Some(username)) = (builder.base_path, &builder.username) {
|
||||
// Determine store path
|
||||
let data_path = PathBuf::from(base_path).join(sanitize(username));
|
||||
fs::create_dir_all(&data_path)?;
|
||||
let store_config = make_store_config(&data_path, None)?;
|
||||
|
||||
// Determine store path
|
||||
let data_path = PathBuf::from(base_path).join(sanitize(&username));
|
||||
fs::create_dir_all(&data_path)?;
|
||||
let store_config = make_store_config(&data_path, None)?;
|
||||
inner_builder = inner_builder.store_config(store_config);
|
||||
}
|
||||
|
||||
let mut inner_builder = builder.inner.store_config(store_config);
|
||||
|
||||
// Determine server either from explicitly set homeserver or from userId
|
||||
// Determine server either from URL, server name or user ID.
|
||||
if let Some(homeserver_url) = builder.homeserver_url {
|
||||
inner_builder = inner_builder.homeserver_url(homeserver_url);
|
||||
} else {
|
||||
} else if let Some(server_name) = builder.server_name {
|
||||
let server_name = ServerName::parse(server_name)?;
|
||||
inner_builder = inner_builder.server_name(&server_name);
|
||||
} else if let Some(username) = builder.username {
|
||||
let user = UserId::parse(username)?;
|
||||
inner_builder = inner_builder.server_name(user.server_name());
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"Failed to build: One of homeserver_url, server_name or username must be called."
|
||||
));
|
||||
}
|
||||
|
||||
RUNTIME.block_on(async move {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
authors = ["Johannes Becker <j.becker@famedly.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/matrix-org/matrix-rust-sdk"
|
||||
repository = "https://github.com/matrix-org/matrix-rust-sdk"
|
||||
description = "Appservice SDK based on the matrix-sdk"
|
||||
|
||||
@@ -60,10 +60,11 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let appservice = AppService::new(homeserver_url, server_name, registration).await?;
|
||||
appservice.register_user_query(Box::new(|_, _| Box::pin(async { true }))).await;
|
||||
appservice
|
||||
.virtual_user(None)
|
||||
.await?
|
||||
.register_event_handler_context(appservice.clone())
|
||||
|
||||
let virtual_user = appservice.virtual_user(None).await?;
|
||||
|
||||
virtual_user.register_event_handler_context(appservice.clone());
|
||||
virtual_user
|
||||
.register_event_handler(
|
||||
move |event: OriginalSyncRoomMemberEvent,
|
||||
room: Room,
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
//! [matrix-org/matrix-rust-sdk#228]: https://github.com/matrix-org/matrix-rust-sdk/issues/228
|
||||
//! [examples directory]: https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk-appservice/examples
|
||||
|
||||
use std::{convert::TryInto, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use dashmap::DashMap;
|
||||
pub use error::Error;
|
||||
@@ -122,7 +122,7 @@ pub use virtual_user::VirtualUserBuilder;
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
const USER_KEY: &[u8] = b"appservice.users.";
|
||||
pub const USER_MEMBER: &[u8] = b"appservice.users.membership.";
|
||||
const USER_MEMBER: &[u8] = b"appservice.users.membership.";
|
||||
|
||||
type Localpart = String;
|
||||
|
||||
@@ -492,7 +492,7 @@ impl AppService {
|
||||
}
|
||||
for task in tasks {
|
||||
if let Err(e) = task.await {
|
||||
warn!("Joining sync task failed: {}", e);
|
||||
warn!("Joining sync task failed: {e}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -505,7 +505,7 @@ impl AppService {
|
||||
pub async fn run(&self, host: impl Into<String>, port: impl Into<u16>) -> Result<()> {
|
||||
let host = host.into();
|
||||
let port = port.into();
|
||||
info!("Starting AppService on {}:{}", &host, &port);
|
||||
info!("Starting AppService on {host}:{port}");
|
||||
|
||||
webserver::run_server(self.clone(), host, port).await?;
|
||||
Ok(())
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
//! AppService Registration.
|
||||
|
||||
use std::{convert::TryFrom, fs::File, ops::Deref, path::PathBuf};
|
||||
use std::{fs::File, ops::Deref, path::PathBuf};
|
||||
|
||||
use http::Uri;
|
||||
use regex::Regex;
|
||||
|
||||
@@ -145,7 +145,7 @@ mod filters {
|
||||
.and(warp::body::bytes())
|
||||
.and_then(|method, path: FullPath, query, headers, bytes| async move {
|
||||
let uri = http::uri::Builder::new()
|
||||
.path_and_query(format!("{}?{}", path.as_str(), query))
|
||||
.path_and_query(format!("{}?{query}", path.as_str()))
|
||||
.build()
|
||||
.map_err(Error::from)?;
|
||||
|
||||
@@ -164,9 +164,13 @@ mod filters {
|
||||
|
||||
mod handlers {
|
||||
use percent_encoding::percent_decode_str;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct EmptyObject {}
|
||||
|
||||
pub async fn user(
|
||||
user_id: String,
|
||||
appservice: AppService,
|
||||
@@ -177,12 +181,12 @@ mod handlers {
|
||||
let request = query_user::IncomingRequest::try_from_http_request(request, &[user_id])
|
||||
.map_err(Error::from)?;
|
||||
return if user_exists(appservice.clone(), request).await {
|
||||
Ok(warp::reply::json(&String::from("{}")))
|
||||
Ok(warp::reply::json(&EmptyObject {}))
|
||||
} else {
|
||||
Err(warp::reject::not_found())
|
||||
};
|
||||
}
|
||||
Ok(warp::reply::json(&String::from("{}")))
|
||||
Ok(warp::reply::json(&EmptyObject {}))
|
||||
}
|
||||
|
||||
pub async fn room(
|
||||
@@ -195,12 +199,12 @@ mod handlers {
|
||||
let request = query_room::IncomingRequest::try_from_http_request(request, &[room_id])
|
||||
.map_err(Error::from)?;
|
||||
return if room_exists(appservice.clone(), request).await {
|
||||
Ok(warp::reply::json(&String::from("{}")))
|
||||
Ok(warp::reply::json(&EmptyObject {}))
|
||||
} else {
|
||||
Err(warp::reject::not_found())
|
||||
};
|
||||
}
|
||||
Ok(warp::reply::json(&String::from("{}")))
|
||||
Ok(warp::reply::json(&EmptyObject {}))
|
||||
}
|
||||
|
||||
pub async fn transaction(
|
||||
@@ -213,7 +217,7 @@ mod handlers {
|
||||
.map_err(Error::from)?;
|
||||
|
||||
appservice.receive_transaction(incoming_transaction).await?;
|
||||
Ok(warp::reply::json(&String::from("{}")))
|
||||
Ok(warp::reply::json(&EmptyObject {}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -400,8 +400,8 @@ impl BaseClient {
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Couldn't deserialize stripped state event for room {}: {:?}",
|
||||
room_info.room_id, err
|
||||
"Couldn't deserialize stripped state event for room {}: {err:?}",
|
||||
room_info.room_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -430,8 +430,8 @@ impl BaseClient {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Couldn't deserialize state event for room {}: {:?} {:#?}",
|
||||
room_id, e, raw_event
|
||||
"Couldn't deserialize state event for room {room_id}: \
|
||||
{e:?} {raw_event:#?}",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -831,7 +831,7 @@ impl BaseClient {
|
||||
.filter_map(|event| match event.deserialize() {
|
||||
Ok(ev) => Some(ev),
|
||||
Err(e) => {
|
||||
debug!(?event, "Failed to deserialize m.room.member event: {}", e);
|
||||
debug!(?event, "Failed to deserialize m.room.member event: {e}");
|
||||
None
|
||||
}
|
||||
})
|
||||
|
||||
@@ -47,9 +47,9 @@ impl fmt::Display for DisplayName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
DisplayName::Named(s) | DisplayName::Calculated(s) | DisplayName::Aliased(s) => {
|
||||
write!(f, "{}", s)
|
||||
write!(f, "{s}")
|
||||
}
|
||||
DisplayName::EmptyWas(s) => write!(f, "Empty Room (was {})", s),
|
||||
DisplayName::EmptyWas(s) => write!(f, "Empty Room (was {s})"),
|
||||
DisplayName::Empty => write!(f, "Empty Room"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ use ruma::{
|
||||
RoomVersionId, UserId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::debug;
|
||||
|
||||
use super::{BaseRoomInfo, DisplayName, RoomMember};
|
||||
use crate::{
|
||||
@@ -396,7 +397,7 @@ impl Room {
|
||||
_ => (summary.joined_member_count, summary.invited_member_count),
|
||||
};
|
||||
|
||||
tracing::debug!(
|
||||
debug!(
|
||||
room_id = self.room_id().as_str(),
|
||||
own_user = self.own_user_id.as_str(),
|
||||
joined, invited,
|
||||
@@ -589,6 +590,8 @@ impl Room {
|
||||
/// Add a new timeline slice to the timeline streams.
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
pub async fn add_timeline_slice(&self, timeline: &TimelineSlice) {
|
||||
use tracing::warn;
|
||||
|
||||
if timeline.sync {
|
||||
let mut streams = self.forward_timeline_streams.lock().await;
|
||||
let mut remaining_streams = Vec::with_capacity(streams.len());
|
||||
@@ -596,7 +599,7 @@ impl Room {
|
||||
if !forward.is_closed() {
|
||||
if let Err(error) = forward.try_send(timeline.clone()) {
|
||||
if error.is_full() {
|
||||
tracing::warn!("Drop timeline slice because the limit of the buffer for the forward stream is reached");
|
||||
warn!("Drop timeline slice because the limit of the buffer for the forward stream is reached");
|
||||
}
|
||||
} else {
|
||||
remaining_streams.push(forward);
|
||||
@@ -611,7 +614,7 @@ impl Room {
|
||||
if !backward.is_closed() {
|
||||
if let Err(error) = backward.try_send(timeline.clone()) {
|
||||
if error.is_full() {
|
||||
tracing::warn!("Drop timeline slice because the limit of the buffer for the backward stream is reached");
|
||||
warn!("Drop timeline slice because the limit of the buffer for the backward stream is reached");
|
||||
}
|
||||
} else {
|
||||
remaining_streams.push(backward);
|
||||
|
||||
@@ -123,7 +123,7 @@ impl AmbiguityCache {
|
||||
member_ambiguous: ambiguous,
|
||||
};
|
||||
|
||||
trace!("Handling display name ambiguity for {}: {:#?}", member_event.state_key(), change);
|
||||
trace!("Handling display name ambiguity for {}: {change:#?}", member_event.state_key());
|
||||
|
||||
self.add_change(room_id, member_event.event_id().to_owned(), change);
|
||||
|
||||
|
||||
@@ -775,13 +775,14 @@ macro_rules! statestore_integration_tests {
|
||||
.zip(stored_events.iter())
|
||||
.enumerate()
|
||||
{
|
||||
assert_eq!(a.expect("not a value").event_id(), b.event_id(), "pos {} not equal - expected: {:#?}, but found {:#?}", idx, expected, found);
|
||||
|
||||
assert_eq!(
|
||||
a.expect("not a value").event_id(),
|
||||
b.event_id(),
|
||||
"pos {idx} not equal - expected: {expected:#?}, but found {found:#?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ use ruma::{
|
||||
serde::Raw,
|
||||
EventId, MxcUri, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId,
|
||||
};
|
||||
use tracing::info;
|
||||
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
use super::BoxStream;
|
||||
@@ -343,25 +344,24 @@ impl MemoryStore {
|
||||
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
for (room, timeline) in &changes.timeline {
|
||||
use tracing::warn;
|
||||
|
||||
if timeline.sync {
|
||||
tracing::info!("Save new timeline batch from sync response for {}", room);
|
||||
info!("Save new timeline batch from sync response for {room}");
|
||||
} else {
|
||||
tracing::info!("Save new timeline batch from messages response for {}", room);
|
||||
info!("Save new timeline batch from messages response for {room}");
|
||||
}
|
||||
|
||||
let mut delete_timeline = false;
|
||||
if timeline.limited {
|
||||
tracing::info!(
|
||||
"Delete stored timeline for {} because the sync response was limited",
|
||||
room
|
||||
);
|
||||
info!("Delete stored timeline for {room} because the sync response was limited");
|
||||
delete_timeline = true;
|
||||
} else if let Some(mut data) = self.room_timeline.get_mut(room) {
|
||||
if !timeline.sync && Some(&timeline.start) != data.end.as_ref() {
|
||||
// This should only happen when a developer adds a wrong timeline
|
||||
// batch to the `StateChanges` or the server returns a wrong response
|
||||
// to our request.
|
||||
tracing::warn!("Drop unexpected timeline batch for {}", room);
|
||||
warn!("Drop unexpected timeline batch for {room}");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ impl MemoryStore {
|
||||
}
|
||||
|
||||
if delete_timeline {
|
||||
tracing::info!("Delete stored timeline for {} because of duplicated events", room);
|
||||
info!("Delete stored timeline for {room} because of duplicated events");
|
||||
self.room_timeline.remove(room);
|
||||
}
|
||||
|
||||
@@ -401,10 +401,7 @@ impl MemoryStore {
|
||||
.get(room)
|
||||
.and_then(|info| info.room_version().cloned())
|
||||
.unwrap_or_else(|| {
|
||||
tracing::warn!(
|
||||
"Unable to find the room version for {}, assume version 9",
|
||||
room
|
||||
);
|
||||
warn!("Unable to find the room version for {room}, assume version 9");
|
||||
RoomVersionId::V9
|
||||
})
|
||||
};
|
||||
@@ -455,7 +452,7 @@ impl MemoryStore {
|
||||
}
|
||||
}
|
||||
|
||||
tracing::info!("Saved changes in {:?}", now.elapsed());
|
||||
info!("Saved changes in {:?}", now.elapsed());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -676,7 +673,7 @@ impl MemoryStore {
|
||||
let (events, end_token) = if let Some(data) = self.room_timeline.get(room_id) {
|
||||
(data.events.clone(), data.end.clone())
|
||||
} else {
|
||||
tracing::info!("No timeline for {} was previously stored", room_id);
|
||||
info!("No timeline for {room_id} was previously stored");
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
@@ -686,11 +683,7 @@ impl MemoryStore {
|
||||
}
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
"Found previously stored timeline for {}, with end token {:?}",
|
||||
room_id,
|
||||
end_token
|
||||
);
|
||||
info!("Found previously stored timeline for {room_id}, with end token {end_token:?}");
|
||||
|
||||
Ok(Some((Box::pin(stream), end_token)))
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ The state machine works in a push/pull manner:
|
||||
state machine
|
||||
|
||||
```rust,no_run
|
||||
use std::{collections::BTreeMap, convert::TryFrom};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use matrix_sdk_crypto::{OlmMachine, OlmError};
|
||||
use ruma::{
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
io::{Cursor, Read},
|
||||
ops::DerefMut,
|
||||
};
|
||||
|
||||
@@ -369,7 +369,7 @@ mod tests {
|
||||
)]),
|
||||
);
|
||||
|
||||
assert_eq!(machine.import_keys(export, false, |_, _| {}).await?, keys,);
|
||||
assert_eq!(machine.import_keys(export, false, |_, _| {}).await?, keys);
|
||||
|
||||
let export = vec![session.export_at_index(10).await];
|
||||
assert_eq!(
|
||||
@@ -379,7 +379,7 @@ mod tests {
|
||||
|
||||
let better_export = vec![session.export().await];
|
||||
|
||||
assert_eq!(machine.import_keys(better_export, false, |_, _| {}).await?, keys,);
|
||||
assert_eq!(machine.import_keys(better_export, false, |_, _| {}).await?, keys);
|
||||
|
||||
let another_session = machine.create_inbound_session(room_id).await?;
|
||||
let export = vec![another_session.export_at_index(10).await];
|
||||
@@ -396,7 +396,7 @@ mod tests {
|
||||
)]),
|
||||
);
|
||||
|
||||
assert_eq!(machine.import_keys(export, false, |_, _| {}).await?, keys,);
|
||||
assert_eq!(machine.import_keys(export, false, |_, _| {}).await?, keys);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet, HashSet},
|
||||
convert::TryFrom,
|
||||
ops::Deref,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
@@ -623,7 +622,7 @@ impl IdentityManager {
|
||||
}
|
||||
|
||||
if let Err(e) = self.store.update_tracked_user(user, true).await {
|
||||
warn!("Error storing users for tracking {}", e);
|
||||
warn!("Error storing users for tracking: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1211,7 +1211,6 @@ impl OlmMachine {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk_crypto::OlmMachine;
|
||||
/// # use ruma::{device_id, user_id};
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -1269,7 +1268,6 @@ impl OlmMachine {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk_crypto::OlmMachine;
|
||||
/// # use ruma::{device_id, user_id};
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -1554,7 +1552,7 @@ pub(crate) mod testing {
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use std::{collections::BTreeMap, convert::TryInto, iter, sync::Arc};
|
||||
use std::{collections::BTreeMap, iter, sync::Arc};
|
||||
|
||||
use matrix_sdk_test::{async_test, test_json};
|
||||
use ruma::{
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
convert::TryInto,
|
||||
fmt,
|
||||
ops::Deref,
|
||||
sync::{
|
||||
@@ -577,9 +576,8 @@ impl ReadOnlyAccount {
|
||||
// so.
|
||||
if count != old_count {
|
||||
debug!(
|
||||
"Updated uploaded one-time key count {} -> {}.",
|
||||
"Updated uploaded one-time key count {} -> {count}.",
|
||||
self.uploaded_key_count(),
|
||||
count
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{collections::BTreeMap, convert::TryInto};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ruma::{
|
||||
events::forwarded_room_key::{
|
||||
|
||||
@@ -717,12 +717,12 @@ mod tests {
|
||||
|
||||
assert!(master_key
|
||||
.public_key
|
||||
.verify_subkey(&identity.self_signing_key.lock().await.as_ref().unwrap().public_key,)
|
||||
.verify_subkey(&identity.self_signing_key.lock().await.as_ref().unwrap().public_key)
|
||||
.is_ok());
|
||||
|
||||
assert!(master_key
|
||||
.public_key
|
||||
.verify_subkey(&identity.user_signing_key.lock().await.as_ref().unwrap().public_key,)
|
||||
.verify_subkey(&identity.user_signing_key.lock().await.as_ref().unwrap().public_key)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
use ruma::{CanonicalJsonValue, DeviceKeyAlgorithm, DeviceKeyId, UserId};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -445,7 +445,7 @@ impl GroupSessionManager {
|
||||
users: impl Iterator<Item = &UserId>,
|
||||
encryption_settings: impl Into<EncryptionSettings>,
|
||||
) -> OlmResult<Vec<Arc<ToDeviceRequest>>> {
|
||||
trace!(room_id = room_id.as_str(), "Checking if a room key needs to be shared",);
|
||||
trace!(room_id = room_id.as_str(), "Checking if a room key needs to be shared");
|
||||
|
||||
let encryption_settings = encryption_settings.into();
|
||||
let history_visibility = encryption_settings.history_visibility.clone();
|
||||
|
||||
@@ -338,10 +338,7 @@ impl SessionManager {
|
||||
self.key_request_machine.retry_keyshare(user_id, device_id);
|
||||
|
||||
if let Err(e) = self.check_if_unwedged(user_id, device_id).await {
|
||||
error!(
|
||||
"Error while treating an unwedged device {} {} {:?}",
|
||||
user_id, device_id, e
|
||||
);
|
||||
error!("Error while treating an unwedged device {user_id} {device_id} {e:?}");
|
||||
}
|
||||
|
||||
changes.sessions.push(session);
|
||||
|
||||
@@ -753,7 +753,7 @@ impl TryFrom<ToDeviceRequest> for OutgoingContent {
|
||||
serde_json::from_value(json).map_err(|e| e.to_string())?,
|
||||
)
|
||||
}
|
||||
e => return Err(format!("Unsupported event type {}", e)),
|
||||
e => return Err(format!("Unsupported event type {e}")),
|
||||
};
|
||||
|
||||
Ok(content.into())
|
||||
|
||||
@@ -506,7 +506,7 @@ impl VerificationMachine {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{convert::TryFrom, sync::Arc, time::Duration};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use matrix_sdk_common::{instant::Instant, locks::Mutex};
|
||||
use matrix_sdk_test::async_test;
|
||||
|
||||
@@ -501,10 +501,9 @@ impl IdentitiesBeingVerified {
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Error signing device keys for {} {} {:?}",
|
||||
"Error signing device keys for {} {}: {e:?}",
|
||||
device.user_id(),
|
||||
device.device_id(),
|
||||
e
|
||||
);
|
||||
None
|
||||
}
|
||||
@@ -535,9 +534,8 @@ impl IdentitiesBeingVerified {
|
||||
}
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Error signing the public cross signing keys for {} {:?}",
|
||||
"Error signing the public cross signing keys for {} {e:?}",
|
||||
i.user_id(),
|
||||
e
|
||||
);
|
||||
None
|
||||
}
|
||||
@@ -707,7 +705,6 @@ impl IdentitiesBeingVerified {
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use std::convert::TryInto;
|
||||
|
||||
use ruma::{
|
||||
events::{AnyToDeviceEventContent, ToDeviceEvent},
|
||||
|
||||
@@ -787,7 +787,7 @@ impl QrState<Reciprocated> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use matrix_sdk_common::locks::Mutex;
|
||||
use matrix_sdk_qrcode::QrVerificationData;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{collections::BTreeMap, convert::TryInto};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ruma::{
|
||||
events::{
|
||||
@@ -196,19 +196,14 @@ pub fn receive_mac_event(
|
||||
|
||||
let info = extra_mac_info_receive(ids, flow_id);
|
||||
|
||||
trace!(
|
||||
"Received a key.verification.mac event from {} {}",
|
||||
sender,
|
||||
ids.other_device.device_id()
|
||||
);
|
||||
trace!("Received a key.verification.mac event from {sender} {}", ids.other_device.device_id());
|
||||
|
||||
let mut keys = content.mac().keys().map(|k| k.as_str()).collect::<Vec<_>>();
|
||||
keys.sort_unstable();
|
||||
|
||||
let keys = Base64::parse(
|
||||
sas.calculate_mac_invalid_base64(&keys.join(","), &format!("{}KEY_IDS", &info)),
|
||||
)
|
||||
.expect("Can't base64-decode SAS MAC");
|
||||
let keys =
|
||||
Base64::parse(sas.calculate_mac_invalid_base64(&keys.join(","), &format!("{info}KEY_IDS")))
|
||||
.expect("Can't base64-decode SAS MAC");
|
||||
|
||||
if keys != *content.keys() {
|
||||
return Err(CancelCode::KeyMismatch);
|
||||
@@ -216,9 +211,7 @@ pub fn receive_mac_event(
|
||||
|
||||
for (key_id, key_mac) in content.mac() {
|
||||
trace!(
|
||||
"Checking MAC for the key id {} from {} {}",
|
||||
key_id,
|
||||
sender,
|
||||
"Checking MAC for the key id {key_id} from {sender} {}",
|
||||
ids.other_device.device_id()
|
||||
);
|
||||
|
||||
@@ -234,7 +227,7 @@ pub fn receive_mac_event(
|
||||
.expect("Can't base64-decode SAS MAC");
|
||||
|
||||
if *key_mac == calculated_mac {
|
||||
trace!("Successfully verified the device key {} from {}", key_id, sender);
|
||||
trace!("Successfully verified the device key {key_id} from {sender}");
|
||||
verified_devices.push(ids.other_device.clone());
|
||||
} else {
|
||||
return Err(CancelCode::KeyMismatch);
|
||||
@@ -243,14 +236,13 @@ pub fn receive_mac_event(
|
||||
if let Some(key) = identity.master_key().get_key(&key_id) {
|
||||
// TODO we should check that the master key signs the device,
|
||||
// this way we know the master key also trusts the device
|
||||
let calculated_mac = Base64::parse(sas.calculate_mac_invalid_base64(
|
||||
&key.to_base64(),
|
||||
&format!("{}{}", info, key_id),
|
||||
))
|
||||
let calculated_mac = Base64::parse(
|
||||
sas.calculate_mac_invalid_base64(&key.to_base64(), &format!("{info}{key_id}")),
|
||||
)
|
||||
.expect("Can't base64-decode SAS MAC");
|
||||
|
||||
if *key_mac == calculated_mac {
|
||||
trace!("Successfully verified the master key {} from {}", key_id, sender);
|
||||
trace!("Successfully verified the master key {key_id} from {sender}");
|
||||
verified_identities.push(identity.clone())
|
||||
} else {
|
||||
return Err(CancelCode::KeyMismatch);
|
||||
@@ -258,10 +250,8 @@ pub fn receive_mac_event(
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Key ID {} in MAC event from {} {} doesn't belong to any device \
|
||||
"Key ID {key_id} in MAC event from {sender} {} doesn't belong to any device \
|
||||
or user identity",
|
||||
key_id,
|
||||
sender,
|
||||
ids.other_device.device_id()
|
||||
);
|
||||
}
|
||||
@@ -312,7 +302,7 @@ pub fn get_mac_content(sas: &EstablishedSas, ids: &SasIds, flow_id: &FlowId) ->
|
||||
|
||||
mac.insert(
|
||||
key_id.to_string(),
|
||||
Base64::parse(sas.calculate_mac_invalid_base64(&key, &format!("{}{}", info, key_id)))
|
||||
Base64::parse(sas.calculate_mac_invalid_base64(&key, &format!("{info}{key_id}")))
|
||||
.expect("Can't base64-decode SAS MAC"),
|
||||
);
|
||||
|
||||
@@ -321,10 +311,9 @@ pub fn get_mac_content(sas: &EstablishedSas, ids: &SasIds, flow_id: &FlowId) ->
|
||||
if let Some(key) = own_identity.master_key().get_first_key() {
|
||||
let key_id = format!("{}:{}", DeviceKeyAlgorithm::Ed25519, key.to_base64());
|
||||
|
||||
let calculated_mac = Base64::parse(sas.calculate_mac_invalid_base64(
|
||||
&key.to_base64(),
|
||||
&format!("{}{}", info, &key_id),
|
||||
))
|
||||
let calculated_mac = Base64::parse(
|
||||
sas.calculate_mac_invalid_base64(&key.to_base64(), &format!("{info}{key_id}")),
|
||||
)
|
||||
.expect("Can't base64-decode SAS Master key MAC");
|
||||
|
||||
mac.insert(key_id, calculated_mac);
|
||||
|
||||
@@ -508,7 +508,7 @@ impl AcceptSettings {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use matrix_sdk_common::locks::Mutex;
|
||||
use matrix_sdk_test::async_test;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
matches,
|
||||
sync::{Arc, Mutex},
|
||||
time::Duration,
|
||||
@@ -546,10 +545,8 @@ impl SasState<Started> {
|
||||
let commitment = calculate_commitment(our_public_key, content);
|
||||
|
||||
info!(
|
||||
"Calculated commitment for pubkey {} and content {:?} {}",
|
||||
"Calculated commitment for pubkey {} and content {content:?} {commitment}",
|
||||
our_public_key.to_base64(),
|
||||
content,
|
||||
commitment
|
||||
);
|
||||
|
||||
if let Ok(accepted_protocols) = AcceptedProtocols::try_from(method_content) {
|
||||
@@ -1224,8 +1221,6 @@ impl SasState<Cancelled> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use matrix_sdk_test::async_test;
|
||||
use ruma::{
|
||||
device_id,
|
||||
|
||||
@@ -72,8 +72,7 @@ pub trait SafeEncode {
|
||||
store_cipher: &StoreCipher,
|
||||
i: usize,
|
||||
) -> JsValue {
|
||||
format!("{}{}{:016x}", self.as_secure_string(table_name, store_cipher), KEY_SEPARATOR, i,)
|
||||
.into()
|
||||
format!("{}{KEY_SEPARATOR}{i:016x}", self.as_secure_string(table_name, store_cipher)).into()
|
||||
}
|
||||
|
||||
/// Encode self into a IdbKeyRange for searching all keys that are
|
||||
|
||||
@@ -54,6 +54,8 @@ use ruma::{
|
||||
RoomVersionId,
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
use tracing::{info, warn};
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::IdbKeyRange;
|
||||
|
||||
@@ -111,12 +113,10 @@ impl From<IndexeddbStoreError> for StoreError {
|
||||
EncryptionError::Serialization(e) => StoreError::Json(e),
|
||||
EncryptionError::Encryption(e) => StoreError::Encryption(e.to_string()),
|
||||
EncryptionError::Version(found, expected) => StoreError::Encryption(format!(
|
||||
"Bad Database Encryption Version: expected {} found {}",
|
||||
expected, found
|
||||
"Bad Database Encryption Version: expected {expected}, found {found}",
|
||||
)),
|
||||
EncryptionError::Length(found, expected) => StoreError::Encryption(format!(
|
||||
"The database key an invalid length: expected {} found {}",
|
||||
expected, found
|
||||
"The database key an invalid length: expected {expected}, found {found}",
|
||||
)),
|
||||
},
|
||||
_ => StoreError::backend(e),
|
||||
@@ -274,9 +274,11 @@ async fn backup(source: &IdbDatabase, meta: &IdbDatabase) -> Result<()> {
|
||||
pub struct IndexeddbStoreBuilderConfig {
|
||||
/// The name for the indexeddb store to use, `state` is none given
|
||||
name: String,
|
||||
/// The password the indexeddb should be encrypted with. If not given, the DB is not encrypted
|
||||
/// The password the indexeddb should be encrypted with. If not given, the
|
||||
/// DB is not encrypted
|
||||
passphrase: String,
|
||||
/// The strategy to use when a merge conflict is found, see [`MigrationConflictStrategy`] for details
|
||||
/// The strategy to use when a merge conflict is found, see
|
||||
/// [`MigrationConflictStrategy`] for details
|
||||
#[builder(default = "MigrationConflictStrategy::BackupAndDrop")]
|
||||
migration_conflict_strategy: MigrationConflictStrategy,
|
||||
}
|
||||
@@ -851,17 +853,14 @@ impl IndexeddbStore {
|
||||
|
||||
for (room_id, timeline) in &changes.timeline {
|
||||
if timeline.sync {
|
||||
tracing::info!("Save new timeline batch from sync response for {}", room_id);
|
||||
info!("Save new timeline batch from sync response for {room_id}");
|
||||
} else {
|
||||
tracing::info!(
|
||||
"Save new timeline batch from messages response for {}",
|
||||
room_id
|
||||
);
|
||||
info!("Save new timeline batch from messages response for {room_id}");
|
||||
}
|
||||
let metadata: Option<TimelineMetadata> = if timeline.limited {
|
||||
tracing::info!(
|
||||
"Delete stored timeline for {} because the sync response was limited",
|
||||
room_id
|
||||
info!(
|
||||
"Delete stored timeline for {room_id} because the sync response was \
|
||||
limited",
|
||||
);
|
||||
|
||||
let stores = &[
|
||||
@@ -888,7 +887,7 @@ impl IndexeddbStore {
|
||||
// This should only happen when a developer adds a wrong timeline
|
||||
// batch to the `StateChanges` or the server returns a wrong response
|
||||
// to our request.
|
||||
tracing::warn!("Drop unexpected timeline batch for {}", room_id);
|
||||
warn!("Drop unexpected timeline batch for {room_id}");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -912,9 +911,8 @@ impl IndexeddbStore {
|
||||
}
|
||||
|
||||
if delete_timeline {
|
||||
tracing::info!(
|
||||
"Delete stored timeline for {} because of duplicated events",
|
||||
room_id
|
||||
info!(
|
||||
"Delete stored timeline for {room_id} because of duplicated events",
|
||||
);
|
||||
|
||||
let stores = &[
|
||||
@@ -961,9 +959,8 @@ impl IndexeddbStore {
|
||||
.transpose()?
|
||||
.and_then(|info| info.room_version().cloned())
|
||||
.unwrap_or_else(|| {
|
||||
tracing::warn!(
|
||||
"Unable to find the room version for {}, assume version 9",
|
||||
room_id
|
||||
warn!(
|
||||
"Unable to find the room version for {room_id}, assume version 9",
|
||||
);
|
||||
RoomVersionId::V9
|
||||
});
|
||||
@@ -1466,7 +1463,7 @@ impl IndexeddbStore {
|
||||
{
|
||||
Some(tl) => tl,
|
||||
_ => {
|
||||
tracing::info!("No timeline for {} was previously stored", room_id);
|
||||
info!("No timeline for {room_id} was previously stored");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
@@ -1482,11 +1479,7 @@ impl IndexeddbStore {
|
||||
|
||||
let stream = Box::pin(stream::iter(timeline.into_iter()));
|
||||
|
||||
tracing::info!(
|
||||
"Found previously stored timeline for {}, with end token {:?}",
|
||||
room_id,
|
||||
end_token
|
||||
);
|
||||
info!("Found previously stored timeline for {room_id}, with end token {end_token:?}");
|
||||
|
||||
Ok(Some((stream, end_token)))
|
||||
}
|
||||
@@ -1682,7 +1675,7 @@ mod tests {
|
||||
use super::{IndexeddbStore, IndexeddbStoreBuilder, Result};
|
||||
|
||||
async fn get_store() -> Result<IndexeddbStore> {
|
||||
let db_name = format!("test-state-plain-{}", Uuid::new_v4().as_hyphenated().to_string());
|
||||
let db_name = format!("test-state-plain-{}", Uuid::new_v4().as_hyphenated());
|
||||
Ok(IndexeddbStoreBuilder::default().name(db_name).build().await?)
|
||||
}
|
||||
|
||||
@@ -1700,9 +1693,8 @@ mod encrypted_tests {
|
||||
use super::{IndexeddbStore, IndexeddbStoreBuilder, Result};
|
||||
|
||||
async fn get_store() -> Result<IndexeddbStore> {
|
||||
let db_name =
|
||||
format!("test-state-encrypted-{}", Uuid::new_v4().as_hyphenated().to_string());
|
||||
let passphrase = format!("some_passphrase-{}", Uuid::new_v4().as_hyphenated().to_string());
|
||||
let db_name = format!("test-state-encrypted-{}", Uuid::new_v4().as_hyphenated());
|
||||
let passphrase = format!("some_passphrase-{}", Uuid::new_v4().as_hyphenated());
|
||||
Ok(IndexeddbStoreBuilder::default().name(db_name).passphrase(passphrase).build().await?)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ pub use types::{
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(feature = "decode_image")]
|
||||
use std::{convert::TryFrom, io::Cursor};
|
||||
use std::io::Cursor;
|
||||
|
||||
#[cfg(feature = "decode_image")]
|
||||
use image::{ImageFormat, Luma};
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[cfg(feature = "decode_image")]
|
||||
use image::{GenericImage, GenericImageView, Luma};
|
||||
use qrcode::{bits::Bits, EcLevel, QrCode, Version};
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
convert::TryInto,
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
@@ -59,6 +59,7 @@ use sled::{
|
||||
Config, Db, Transactional, Tree,
|
||||
};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tracing::{debug, info};
|
||||
|
||||
#[cfg(feature = "crypto-store")]
|
||||
use super::OpenStoreError;
|
||||
@@ -126,12 +127,10 @@ impl Into<StoreError> for SledStoreError {
|
||||
KeyEncryptionError::Serialization(e) => StoreError::Json(e),
|
||||
KeyEncryptionError::Encryption(e) => StoreError::Encryption(e.to_string()),
|
||||
KeyEncryptionError::Version(found, expected) => StoreError::Encryption(format!(
|
||||
"Bad Database Encryption Version: expected {} found {}",
|
||||
expected, found
|
||||
"Bad Database Encryption Version: expected {expected}, found {found}",
|
||||
)),
|
||||
KeyEncryptionError::Length(found, expected) => StoreError::Encryption(format!(
|
||||
"The database key an invalid length: expected {} found {}",
|
||||
expected, found
|
||||
"The database key an invalid length: expected {expected}, found {found}",
|
||||
)),
|
||||
},
|
||||
SledStoreError::StoreError(e) => e,
|
||||
@@ -215,7 +214,8 @@ pub struct SledStoreBuilderConfig {
|
||||
path: PathBuf,
|
||||
/// Set the password the sled store is encrypted with (if any)
|
||||
passphrase: String,
|
||||
/// The strategy to use when a merge conflict is found, see [`MigrationConflictStrategy`] for details
|
||||
/// The strategy to use when a merge conflict is found, see
|
||||
/// [`MigrationConflictStrategy`] for details
|
||||
#[builder(default = "MigrationConflictStrategy::BackupAndDrop")]
|
||||
migration_conflict_strategy: MigrationConflictStrategy,
|
||||
}
|
||||
@@ -476,11 +476,7 @@ impl SledStore {
|
||||
Some(version) => version,
|
||||
};
|
||||
|
||||
tracing::debug!(
|
||||
old_version,
|
||||
new_version = DATABASE_VERSION,
|
||||
"Upgrading the Sled state store"
|
||||
);
|
||||
debug!(old_version, new_version = DATABASE_VERSION, "Upgrading the Sled state store");
|
||||
|
||||
if old_version == 1 {
|
||||
if self.store_cipher.is_some() {
|
||||
@@ -839,7 +835,7 @@ impl SledStore {
|
||||
|
||||
self.inner.flush_async().await?;
|
||||
|
||||
tracing::info!("Saved changes in {:?}", now.elapsed());
|
||||
info!("Saved changes in {:?}", now.elapsed());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1308,7 +1304,7 @@ impl SledStore {
|
||||
let metadata = match metadata {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
tracing::info!("No timeline for {} was previously stored", r_id);
|
||||
info!("No timeline for {r_id} was previously stored");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
@@ -1316,16 +1312,14 @@ impl SledStore {
|
||||
let mut position = metadata.start_position;
|
||||
let end_token = metadata.end;
|
||||
|
||||
tracing::info!(
|
||||
"Found previously stored timeline for {}, with end token {:?}",
|
||||
r_id,
|
||||
end_token
|
||||
);
|
||||
info!("Found previously stored timeline for {r_id}, with end token {end_token:?}");
|
||||
|
||||
let stream = stream! {
|
||||
while let Ok(Some(item)) = db.room_timeline.get(&db.encode_key_with_counter(TIMELINE, &r_id, position)) {
|
||||
while let Ok(Some(item)) =
|
||||
db.room_timeline.get(&db.encode_key_with_counter(TIMELINE, &r_id, position))
|
||||
{
|
||||
position += 1;
|
||||
yield db.deserialize_value(&item).map_err(SledStoreError::from).map_err(|e| e.into());
|
||||
yield db.deserialize_value(&item).map_err(|e| SledStoreError::from(e).into());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1334,7 +1328,7 @@ impl SledStore {
|
||||
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
async fn remove_room_timeline(&self, room_id: &RoomId) -> Result<()> {
|
||||
tracing::info!("Remove stored timeline for {}", room_id);
|
||||
info!("Remove stored timeline for {room_id}");
|
||||
|
||||
let mut timeline_batch = sled::Batch::default();
|
||||
for key in self.room_timeline.scan_prefix(self.encode_key(TIMELINE, &room_id)).keys() {
|
||||
@@ -1371,22 +1365,21 @@ impl SledStore {
|
||||
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
async fn save_room_timeline(&self, changes: &StateChanges) -> Result<()> {
|
||||
use tracing::warn;
|
||||
|
||||
let mut timeline_batch = sled::Batch::default();
|
||||
let mut event_id_to_position_batch = sled::Batch::default();
|
||||
let mut timeline_metadata_batch = sled::Batch::default();
|
||||
|
||||
for (room_id, timeline) in &changes.timeline {
|
||||
if timeline.sync {
|
||||
tracing::info!("Save new timeline batch from sync response for {}", room_id);
|
||||
info!("Save new timeline batch from sync response for {room_id}");
|
||||
} else {
|
||||
tracing::info!("Save new timeline batch from messages response for {}", room_id);
|
||||
info!("Save new timeline batch from messages response for {room_id}");
|
||||
}
|
||||
|
||||
let metadata: Option<TimelineMetadata> = if timeline.limited {
|
||||
tracing::info!(
|
||||
"Delete stored timeline for {} because the sync response was limited",
|
||||
room_id
|
||||
);
|
||||
info!("Delete stored timeline for {room_id} because the sync response was limited");
|
||||
self.remove_room_timeline(room_id).await?;
|
||||
None
|
||||
} else {
|
||||
@@ -1400,7 +1393,7 @@ impl SledStore {
|
||||
// This should only happen when a developer adds a wrong timeline
|
||||
// batch to the `StateChanges` or the server returns a wrong response
|
||||
// to our request.
|
||||
tracing::warn!("Drop unexpected timeline batch for {}", room_id);
|
||||
warn!("Drop unexpected timeline batch for {room_id}");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1418,10 +1411,7 @@ impl SledStore {
|
||||
}
|
||||
|
||||
if delete_timeline {
|
||||
tracing::info!(
|
||||
"Delete stored timeline for {} because of duplicated events",
|
||||
room_id
|
||||
);
|
||||
info!("Delete stored timeline for {room_id} because of duplicated events");
|
||||
self.remove_room_timeline(room_id).await?;
|
||||
None
|
||||
} else if timeline.sync {
|
||||
@@ -1453,10 +1443,7 @@ impl SledStore {
|
||||
.transpose()?
|
||||
.and_then(|info| info.room_version().cloned())
|
||||
.unwrap_or_else(|| {
|
||||
tracing::warn!(
|
||||
"Unable to find the room version for {}, assume version 9",
|
||||
room_id
|
||||
);
|
||||
warn!("Unable to find the room version for {room_id}, assume version 9");
|
||||
RoomVersionId::V9
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use ruma::{events::AnyRoomEvent, serde::Raw};
|
||||
use serde_json::Value;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
default = [
|
||||
"e2e-encryption",
|
||||
"sled",
|
||||
"native-tls"
|
||||
"native-tls",
|
||||
]
|
||||
|
||||
e2e-encryption = [
|
||||
|
||||
@@ -25,7 +25,6 @@ some event handlers and then syncing.
|
||||
This is demonstrated in the example below.
|
||||
|
||||
```rust,no_run
|
||||
use std::convert::TryFrom;
|
||||
use matrix_sdk::{
|
||||
Client, config::SyncSettings,
|
||||
ruma::{user_id, events::room::message::SyncRoomMessageEvent},
|
||||
|
||||
@@ -22,13 +22,13 @@ async fn on_stripped_state_member(
|
||||
// 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);
|
||||
eprintln!("Failed to join room {} ({err:?}), retrying in {delay}s", room.room_id());
|
||||
|
||||
sleep(Duration::from_secs(delay)).await;
|
||||
delay *= 2;
|
||||
|
||||
if delay > 3600 {
|
||||
eprintln!("Can't join room {} ({:?})", room.room_id(), err);
|
||||
eprintln!("Can't join room {} ({err:?})", room.room_id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ async fn login_and_sync(
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
println!("logged in as {}", username);
|
||||
println!("logged in as {username}");
|
||||
|
||||
client.register_event_handler(on_stripped_state_member).await;
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ async fn login_and_sync(
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
println!("logged in as {}", username);
|
||||
println!("logged in as {username}");
|
||||
|
||||
// An initial sync to set up state and so our bot doesn't respond to old
|
||||
// messages. If the `StateStore` finds saved state in the location given the
|
||||
|
||||
@@ -92,7 +92,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
};
|
||||
|
||||
println!("helloooo {} {} {} {:#?}", homeserver_url, username, password, image_path);
|
||||
println!("helloooo {homeserver_url} {username} {password} {image_path:#?}");
|
||||
let path = PathBuf::from(image_path);
|
||||
let image = File::open(path).expect("Can't open image file.");
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
|
||||
{
|
||||
let member = room.get_member(&sender).await.unwrap().unwrap();
|
||||
let name = member.display_name().unwrap_or_else(|| member.user_id().as_str());
|
||||
println!("{}: {}", name, msg_body);
|
||||
println!("{name}: {msg_body}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ async fn print_timeline(room: Room) {
|
||||
while let Some(event) = backward_stream.next().await {
|
||||
let event = event.unwrap();
|
||||
if let Some(content) = event_content(event.event.deserialize().unwrap()) {
|
||||
println!("{}", content);
|
||||
println!("{content}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ impl Account {
|
||||
/// client.login(user, "password", None, None).await?;
|
||||
///
|
||||
/// if let Some(name) = client.account().get_display_name().await? {
|
||||
/// println!("Logged in as user '{}' with display name '{}'", user, name);
|
||||
/// println!("Logged in as user '{user}' with display name '{name}'");
|
||||
/// }
|
||||
/// # anyhow::Ok(()) });
|
||||
/// ```
|
||||
@@ -113,7 +113,7 @@ impl Account {
|
||||
/// client.login(user, "password", None, None).await?;
|
||||
///
|
||||
/// if let Some(url) = client.account().get_avatar_url().await? {
|
||||
/// println!("Your avatar's mxc url is {}", url);
|
||||
/// println!("Your avatar's mxc url is {url}");
|
||||
/// }
|
||||
/// # anyhow::Ok(()) });
|
||||
/// ```
|
||||
@@ -258,7 +258,6 @@ impl Account {
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::Client;
|
||||
/// # use matrix_sdk::ruma::{
|
||||
/// # api::client::{
|
||||
@@ -307,7 +306,6 @@ impl Account {
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::Client;
|
||||
/// # use matrix_sdk::ruma::{
|
||||
/// # api::client::{
|
||||
|
||||
@@ -342,6 +342,7 @@ impl ClientBuilder {
|
||||
typing_notice_times: Default::default(),
|
||||
event_handlers: Default::default(),
|
||||
event_handler_data: Default::default(),
|
||||
event_handler_counter: Default::default(),
|
||||
notification_handlers: Default::default(),
|
||||
appservice_mode: self.appservice_mode,
|
||||
respect_login_well_known: self.respect_login_well_known,
|
||||
@@ -354,12 +355,12 @@ impl ClientBuilder {
|
||||
|
||||
fn homeserver_from_name(server_name: &ServerName) -> String {
|
||||
#[cfg(not(test))]
|
||||
return format!("https://{}", server_name);
|
||||
return format!("https://{server_name}");
|
||||
|
||||
// Wiremock only knows how to test http endpoints:
|
||||
// https://github.com/LukeMathWalker/wiremock-rs/issues/58
|
||||
#[cfg(test)]
|
||||
return format!("http://{}", server_name);
|
||||
return format!("http://{server_name}");
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -224,7 +224,7 @@ where
|
||||
const SSO_SERVER_BIND_TRIES: u8 = 10;
|
||||
|
||||
let homeserver = self.client.homeserver().await;
|
||||
info!("Logging in to {}", homeserver);
|
||||
info!("Logging in to {homeserver}");
|
||||
|
||||
let (signal_tx, signal_rx) = oneshot::channel();
|
||||
let (data_tx, data_rx) = oneshot::channel();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright 2020 Damir Jelić
|
||||
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
// Copyright 2022 Famedly GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +20,10 @@ use std::{
|
||||
future::Future,
|
||||
io::Read,
|
||||
pin::Pin,
|
||||
sync::{Arc, RwLock as StdRwLock},
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering::SeqCst},
|
||||
Arc, RwLock as StdRwLock,
|
||||
},
|
||||
};
|
||||
|
||||
use anymap2::any::CloneAnySendSync;
|
||||
@@ -80,7 +84,10 @@ use crate::{
|
||||
attachment::{AttachmentInfo, Thumbnail},
|
||||
config::RequestConfig,
|
||||
error::{HttpError, HttpResult},
|
||||
event_handler::{EventHandler, EventHandlerData, EventHandlerResult, EventKind, SyncEvent},
|
||||
event_handler::{
|
||||
EventHandler, EventHandlerData, EventHandlerHandle, EventHandlerResult,
|
||||
EventHandlerWrapper, EventKind, SyncEvent,
|
||||
},
|
||||
http_client::HttpClient,
|
||||
room, Account, Error, Result,
|
||||
};
|
||||
@@ -101,8 +108,8 @@ const DEFAULT_UPLOAD_SPEED: u64 = 125_000;
|
||||
const MIN_UPLOAD_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 5);
|
||||
|
||||
type EventHandlerFut = Pin<Box<dyn Future<Output = ()> + Send>>;
|
||||
type EventHandlerFn = Box<dyn Fn(EventHandlerData<'_>) -> EventHandlerFut + Send + Sync>;
|
||||
type EventHandlerMap = BTreeMap<(EventKind, &'static str), Vec<EventHandlerFn>>;
|
||||
pub(crate) type EventHandlerFn = dyn Fn(EventHandlerData<'_>) -> EventHandlerFut + Send + Sync;
|
||||
type EventHandlerMap = BTreeMap<(EventKind, &'static str), Vec<EventHandlerWrapper>>;
|
||||
|
||||
type NotificationHandlerFut = EventHandlerFut;
|
||||
type NotificationHandlerFn =
|
||||
@@ -156,6 +163,9 @@ pub(crate) struct ClientInner {
|
||||
event_handlers: RwLock<EventHandlerMap>,
|
||||
/// Custom event handler context. See `register_event_handler_context`.
|
||||
event_handler_data: StdRwLock<AnyMap>,
|
||||
/// When registering a event handler, the current value is used for the
|
||||
/// handlers identification, then the counter is incremented.
|
||||
event_handler_counter: AtomicU64,
|
||||
/// Notification handlers. See `register_notification_handler`.
|
||||
notification_handlers: RwLock<Vec<NotificationHandlerFn>>,
|
||||
/// Whether the client should operate in application service style mode.
|
||||
@@ -346,9 +356,11 @@ impl Client {
|
||||
/// "context" arguments: They have to implement [`EventHandlerContext`].
|
||||
/// This trait is named that way because most of the types implementing it
|
||||
/// give additional context about an event: The room it was in, its raw form
|
||||
/// and other similar things. As an exception to this,
|
||||
/// [`Client`] also implements the `EventHandlerContext` trait
|
||||
/// so you don't have to clone your client into the event handler manually.
|
||||
/// and other similar things. As two exceptions to this,
|
||||
/// [`Client`] and [`EventHandlerHandle`] also implement the
|
||||
/// `EventHandlerContext` trait so you don't have to clone your client
|
||||
/// into the event handler manually and a handler can decide to remove
|
||||
/// itself.
|
||||
///
|
||||
/// Some context arguments are not universally applicable. A context
|
||||
/// argument that isn't available for the given event type will result in
|
||||
@@ -388,13 +400,15 @@ impl Client {
|
||||
/// # .build()
|
||||
/// # .await
|
||||
/// # .unwrap();
|
||||
///
|
||||
/// client
|
||||
/// .register_event_handler(
|
||||
/// |ev: SyncRoomMessageEvent, room: Room, client: Client| async move {
|
||||
/// // Common usage: Room event plus room and client.
|
||||
/// },
|
||||
/// )
|
||||
/// .await
|
||||
/// .await;
|
||||
/// client
|
||||
/// .register_event_handler(
|
||||
/// |ev: SyncRoomMessageEvent, room: Room, encryption_info: Option<EncryptionInfo>| {
|
||||
/// async move {
|
||||
@@ -403,7 +417,8 @@ impl Client {
|
||||
/// }
|
||||
/// },
|
||||
/// )
|
||||
/// .await
|
||||
/// .await;
|
||||
/// client
|
||||
/// .register_event_handler(|ev: SyncRoomTopicEvent| async move {
|
||||
/// // You can omit any or all arguments after the first.
|
||||
/// })
|
||||
@@ -431,54 +446,118 @@ impl Client {
|
||||
/// move |ev: SyncRoomMessageEvent | {
|
||||
/// let data = data.clone();
|
||||
/// async move {
|
||||
/// println!("Calling the handler with identifier {}", data);
|
||||
/// println!("Calling the handler with identifier {data}");
|
||||
/// }
|
||||
/// }
|
||||
/// }).await;
|
||||
/// # });
|
||||
/// ```
|
||||
pub async fn register_event_handler<Ev, Ctx, H>(&self, handler: H) -> &Self
|
||||
pub async fn register_event_handler<Ev, Ctx, H>(&self, handler: H) -> EventHandlerHandle
|
||||
where
|
||||
Ev: SyncEvent + DeserializeOwned + Send + 'static,
|
||||
H: EventHandler<Ev, Ctx>,
|
||||
<H::Future as Future>::Output: EventHandlerResult,
|
||||
{
|
||||
let event_type = H::ID.1;
|
||||
self.inner.event_handlers.write().await.entry(H::ID).or_default().push(Box::new(
|
||||
move |data| {
|
||||
let maybe_fut = serde_json::from_str(data.raw.get())
|
||||
.map(|ev| handler.clone().handle_event(ev, data));
|
||||
let event_type = Ev::TYPE;
|
||||
let key = (Ev::KIND, Ev::TYPE);
|
||||
|
||||
Box::pin(async move {
|
||||
match maybe_fut {
|
||||
Ok(Some(fut)) => {
|
||||
fut.await.print_error(event_type);
|
||||
}
|
||||
Ok(None) => {
|
||||
error!(
|
||||
"Event handler for {} has an invalid context argument",
|
||||
event_type
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Failed to deserialize `{}` event, skipping event handler.\n\
|
||||
Deserialization error: {}",
|
||||
event_type, e,
|
||||
);
|
||||
}
|
||||
let handler_fn: Box<EventHandlerFn> = Box::new(move |data| {
|
||||
let maybe_fut = serde_json::from_str(data.raw.get())
|
||||
.map(|ev| handler.clone().handle_event(ev, data));
|
||||
|
||||
Box::pin(async move {
|
||||
match maybe_fut {
|
||||
Ok(Some(fut)) => {
|
||||
fut.await.print_error(event_type);
|
||||
}
|
||||
})
|
||||
},
|
||||
));
|
||||
Ok(None) => {
|
||||
error!("Event handler for {} has an invalid context argument", event_type);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Failed to deserialize `{}` event, skipping event handler.\n\
|
||||
Deserialization error: {}",
|
||||
event_type, e,
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
self
|
||||
let handler_id = self.inner.event_handler_counter.fetch_add(1, SeqCst);
|
||||
|
||||
let handle = EventHandlerHandle { handler_id, ev_id: key };
|
||||
|
||||
self.inner
|
||||
.event_handlers
|
||||
.write()
|
||||
.await
|
||||
.entry(key)
|
||||
.or_default()
|
||||
.push(EventHandlerWrapper { handler_fn, handle });
|
||||
|
||||
handle
|
||||
}
|
||||
|
||||
pub(crate) async fn event_handlers(&self) -> RwLockReadGuard<'_, EventHandlerMap> {
|
||||
self.inner.event_handlers.read().await
|
||||
}
|
||||
|
||||
/// Remove the event handler associated with the handle.
|
||||
///
|
||||
/// Note that handlers that remove themselves will still execute
|
||||
/// with events received in the same sync cycle.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// `handle` - The [`EventHandlerHandle`] that is returned when
|
||||
/// registering the event handler with [`Client::register_event_handler`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use url::Url;
|
||||
/// # use tokio::sync::mpsc;
|
||||
/// #
|
||||
/// # let homeserver = Url::parse("http://localhost:8080").unwrap();
|
||||
/// #
|
||||
/// use matrix_sdk::{
|
||||
/// ruma::events::room::member::SyncRoomMemberEvent,
|
||||
/// Client, event_handler::EventHandlerHandle
|
||||
/// };
|
||||
/// #
|
||||
/// # block_on(async {
|
||||
/// # let client = matrix_sdk::Client::builder()
|
||||
/// # .homeserver_url(homeserver)
|
||||
/// # .server_versions([ruma::api::MatrixVersion::V1_0])
|
||||
/// # .build()
|
||||
/// # .await
|
||||
/// # .unwrap();
|
||||
///
|
||||
/// client
|
||||
/// .register_event_handler(
|
||||
/// |ev: SyncRoomMemberEvent, client: Client, handle: EventHandlerHandle| async move {
|
||||
/// // Common usage: Check arriving Event is the expected one
|
||||
/// println!("Expected RoomMemberEvent received!");
|
||||
/// client.remove_event_handler(handle);
|
||||
/// },
|
||||
/// )
|
||||
/// .await;
|
||||
/// # });
|
||||
/// ```
|
||||
pub async fn remove_event_handler(&self, handle: EventHandlerHandle) {
|
||||
let mut event_handlers = self.inner.event_handlers.write().await;
|
||||
|
||||
if let Some(v) = event_handlers.get_mut(&handle.ev_id) {
|
||||
v.retain(|e| e.handle.handler_id != handle.handler_id);
|
||||
|
||||
if v.is_empty() {
|
||||
event_handlers.remove(&handle.ev_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an arbitrary value for use as event handler context.
|
||||
///
|
||||
/// The value can be obtained in an event handler by adding an argument of
|
||||
@@ -511,8 +590,8 @@ impl Client {
|
||||
/// // Handle used to send messages to the UI part of the app
|
||||
/// let my_gui_handle: SomeType = obtain_gui_handle();
|
||||
///
|
||||
/// client.register_event_handler_context(my_gui_handle.clone());
|
||||
/// client
|
||||
/// .register_event_handler_context(my_gui_handle.clone())
|
||||
/// .register_event_handler(
|
||||
/// |ev: SyncRoomMessageEvent, room: Room, gui_handle: Ctx<SomeType>| async move {
|
||||
/// // gui_handle.send(DisplayMessage { message: ev });
|
||||
@@ -521,12 +600,11 @@ impl Client {
|
||||
/// .await;
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn register_event_handler_context<T>(&self, ctx: T) -> &Self
|
||||
pub fn register_event_handler_context<T>(&self, ctx: T)
|
||||
where
|
||||
T: Clone + Send + Sync + 'static,
|
||||
{
|
||||
self.inner.event_handler_data.write().unwrap().insert(ctx);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn event_handler_context<T>(&self) -> Option<T>
|
||||
@@ -725,7 +803,6 @@ impl Client {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use url::Url;
|
||||
/// # let homeserver = Url::parse("http://example.com").unwrap();
|
||||
@@ -742,8 +819,8 @@ impl Client {
|
||||
/// .await?;
|
||||
///
|
||||
/// println!(
|
||||
/// "Logged in as {}, got device_id {} and access_token {}",
|
||||
/// user, response.device_id, response.access_token,
|
||||
/// "Logged in as {user}, got device_id {} and access_token {}",
|
||||
/// response.device_id, response.access_token,
|
||||
/// );
|
||||
/// # anyhow::Ok(()) });
|
||||
/// ```
|
||||
@@ -792,7 +869,6 @@ impl Client {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::Client;
|
||||
/// # use matrix_sdk::ruma::{assign, DeviceId};
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -1061,7 +1137,6 @@ impl Client {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::Client;
|
||||
/// # use matrix_sdk::ruma::{
|
||||
/// # api::client::{
|
||||
@@ -1092,7 +1167,7 @@ impl Client {
|
||||
registration: impl Into<register::v3::Request<'_>>,
|
||||
) -> HttpResult<register::v3::Response> {
|
||||
let homeserver = self.homeserver().await;
|
||||
info!("Registering to {}", homeserver);
|
||||
info!("Registering to {homeserver}");
|
||||
|
||||
let config = if self.inner.appservice_mode {
|
||||
Some(RequestConfig::short_retry().force_auth())
|
||||
@@ -1224,7 +1299,6 @@ impl Client {
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// use matrix_sdk::Client;
|
||||
/// # use std::convert::TryInto;
|
||||
/// # use url::Url;
|
||||
/// # let homeserver = Url::parse("http://example.com").unwrap();
|
||||
/// # let limit = Some(10);
|
||||
@@ -1300,7 +1374,6 @@ impl Client {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use url::Url;
|
||||
/// # use matrix_sdk::Client;
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -1415,7 +1488,6 @@ impl Client {
|
||||
/// # use matrix_sdk::{Client, config::SyncSettings};
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use url::Url;
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080")?;
|
||||
/// # let mut client = Client::new(homeserver).await?;
|
||||
@@ -1498,7 +1570,6 @@ impl Client {
|
||||
/// # use matrix_sdk::{Client, config::SyncSettings};
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use url::Url;
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080")?;
|
||||
/// # let mut client = Client::new(homeserver).await?;
|
||||
@@ -1546,7 +1617,7 @@ impl Client {
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use serde_json::json;
|
||||
/// # use url::Url;
|
||||
/// # use std::{collections::BTreeMap, convert::TryFrom};
|
||||
/// # use std::collections::BTreeMap;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080")?;
|
||||
/// # let mut client = Client::new(homeserver).await?;
|
||||
@@ -1838,8 +1909,6 @@ impl Client {
|
||||
if callback(r).await == LoopCtrl::Break {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
Client::delay_sync(&mut last_sync_time).await
|
||||
|
||||
@@ -81,7 +81,6 @@ impl Device {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{Client, ruma::{device_id, user_id}};
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -123,7 +122,6 @@ impl Device {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # ruma::{
|
||||
@@ -171,7 +169,6 @@ impl Device {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{Client, ruma::{device_id, user_id}};
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -229,7 +226,6 @@ impl Device {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # ruma::{
|
||||
@@ -344,7 +340,6 @@ impl Device {
|
||||
/// Let's check if a device is verified:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # ruma::{
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
//! Verifying a device is pretty straightforward:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use std::convert::TryFrom;
|
||||
//! # use matrix_sdk::{Client, ruma::{device_id, user_id}};
|
||||
//! # use url::Url;
|
||||
//! # use futures::executor::block_on;
|
||||
@@ -61,7 +60,6 @@
|
||||
//! Verifying a user identity works largely the same:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use std::convert::TryFrom;
|
||||
//! # use matrix_sdk::{Client, ruma::user_id};
|
||||
//! # use url::Url;
|
||||
//! # use futures::executor::block_on;
|
||||
|
||||
@@ -91,7 +91,6 @@ impl UserIdentity {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{Client, ruma::user_id};
|
||||
/// # use url::Url;
|
||||
/// # let alice = user_id!("@alice:example.org");
|
||||
@@ -143,7 +142,6 @@ impl UserIdentity {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{Client, ruma::user_id};
|
||||
/// # use url::Url;
|
||||
/// # let alice = user_id!("@alice:example.org");
|
||||
@@ -195,7 +193,6 @@ impl UserIdentity {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # ruma::{
|
||||
@@ -274,7 +271,6 @@ impl UserIdentity {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # ruma::{
|
||||
@@ -318,7 +314,6 @@ impl UserIdentity {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # ruma::{
|
||||
@@ -358,7 +353,6 @@ impl UserIdentity {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # ruma::{
|
||||
|
||||
@@ -555,7 +555,6 @@ impl Encryption {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{Client, ruma::{device_id, user_id}};
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -600,7 +599,6 @@ impl Encryption {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{Client, ruma::user_id};
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -640,7 +638,6 @@ impl Encryption {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use matrix_sdk::{Client, ruma::user_id};
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -691,7 +688,7 @@ impl Encryption {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// # use std::{convert::TryFrom, collections::BTreeMap};
|
||||
/// # use std::collections::BTreeMap;
|
||||
/// # use matrix_sdk::{ruma::api::client::uiaa, Client};
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
|
||||
@@ -147,7 +147,7 @@ impl SasVerification {
|
||||
/// .collect::<Vec<_>>()
|
||||
/// .join("");
|
||||
///
|
||||
/// println!("Do the emojis match?\n{}\n{}", emoji_string, description);
|
||||
/// println!("Do the emojis match?\n{emoji_string}\n{description}");
|
||||
/// }
|
||||
/// # anyhow::Ok(()) });
|
||||
/// ```
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright 2021 Jonas Platte
|
||||
// Copyright 2022 Famedly GmbH
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -38,8 +39,9 @@ use matrix_sdk_base::deserialized_responses::{EncryptionInfo, SyncRoomEvent};
|
||||
use ruma::{events::AnySyncStateEvent, serde::Raw};
|
||||
use serde::Deserialize;
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
use tracing::error;
|
||||
|
||||
use crate::{room, Client};
|
||||
use crate::{client::EventHandlerFn, room, Client};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
@@ -80,7 +82,28 @@ impl EventKind {
|
||||
/// A statically-known event kind/type that can be retrieved from an event sync.
|
||||
pub trait SyncEvent {
|
||||
#[doc(hidden)]
|
||||
const ID: (EventKind, &'static str);
|
||||
const KIND: EventKind;
|
||||
#[doc(hidden)]
|
||||
const TYPE: &'static str;
|
||||
}
|
||||
|
||||
pub(crate) struct EventHandlerWrapper {
|
||||
pub handler_fn: Box<EventHandlerFn>,
|
||||
pub handle: EventHandlerHandle,
|
||||
}
|
||||
|
||||
/// Handle to remove a registered event handler by passing it to
|
||||
/// [`Client::remove_event_handler`].
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct EventHandlerHandle {
|
||||
pub(crate) ev_id: (EventKind, &'static str),
|
||||
pub(crate) handler_id: u64,
|
||||
}
|
||||
|
||||
impl EventHandlerContext for EventHandlerHandle {
|
||||
fn from_data(data: &EventHandlerData<'_>) -> Option<Self> {
|
||||
Some(data.handle)
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for event handlers.
|
||||
@@ -121,11 +144,6 @@ pub trait EventHandler<Ev, Ctx>: Clone + Send + Sync + 'static {
|
||||
#[doc(hidden)]
|
||||
type Future: Future + Send + 'static;
|
||||
|
||||
/// The event type being handled, for example a message event of type
|
||||
/// `m.room.message`.
|
||||
#[doc(hidden)]
|
||||
const ID: (EventKind, &'static str);
|
||||
|
||||
/// Create a future for handling the given event.
|
||||
///
|
||||
/// `data` provides additional data about the event, for example the room it
|
||||
@@ -143,6 +161,7 @@ pub struct EventHandlerData<'a> {
|
||||
pub room: Option<room::Room>,
|
||||
pub raw: &'a RawJsonValue,
|
||||
pub encryption_info: Option<&'a EncryptionInfo>,
|
||||
pub handle: EventHandlerHandle,
|
||||
}
|
||||
|
||||
/// Context for an event handler.
|
||||
@@ -237,14 +256,14 @@ impl<E: fmt::Debug + fmt::Display + 'static> EventHandlerResult for Result<(), E
|
||||
match self {
|
||||
#[cfg(feature = "anyhow")]
|
||||
Err(e) if TypeId::of::<E>() == TypeId::of::<anyhow::Error>() => {
|
||||
tracing::error!("Event handler for `{}` failed: {:?}", event_type, e);
|
||||
error!("Event handler for `{event_type}` failed: {e:?}");
|
||||
}
|
||||
#[cfg(feature = "eyre")]
|
||||
Err(e) if TypeId::of::<E>() == TypeId::of::<eyre::Report>() => {
|
||||
tracing::error!("Event handler for `{}` failed: {:?}", event_type, e);
|
||||
error!("Event handler for `{event_type}` failed: {e:?}");
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Event handler for `{}` failed: {}", event_type, e);
|
||||
error!("Event handler for `{event_type}` failed: {e}");
|
||||
}
|
||||
Ok(_) => {}
|
||||
}
|
||||
@@ -383,14 +402,15 @@ impl Client {
|
||||
.get(&event_handler_id)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.map(|handler| {
|
||||
.map(|handler_wrapper| {
|
||||
let data = EventHandlerData {
|
||||
client: self.clone(),
|
||||
room: room.clone(),
|
||||
raw: raw_event.json(),
|
||||
encryption_info,
|
||||
handle: handler_wrapper.handle,
|
||||
};
|
||||
(handler)(data)
|
||||
(handler_wrapper.handler_fn)(data)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -416,7 +436,6 @@ macro_rules! impl_event_handler {
|
||||
$($ty: EventHandlerContext),*
|
||||
{
|
||||
type Future = Fut;
|
||||
const ID: (EventKind, &'static str) = Ev::ID;
|
||||
|
||||
fn handle_event(&self, ev: Ev, _d: EventHandlerData<'_>) -> Option<Self::Future> {
|
||||
Some((self)(ev, $($ty::from_data(&_d)?),*))
|
||||
@@ -450,21 +469,24 @@ mod static_events {
|
||||
where
|
||||
C: StaticEventContent + GlobalAccountDataEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::GlobalAccountData, C::TYPE);
|
||||
const KIND: EventKind = EventKind::GlobalAccountData;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RoomAccountDataEvent<C>
|
||||
where
|
||||
C: StaticEventContent + RoomAccountDataEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::RoomAccountData, C::TYPE);
|
||||
const KIND: EventKind = EventKind::RoomAccountData;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::SyncEphemeralRoomEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EphemeralRoomEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::EphemeralRoomData, C::TYPE);
|
||||
const KIND: EventKind = EventKind::EphemeralRoomData;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::SyncMessageLikeEvent<C>
|
||||
@@ -472,40 +494,39 @@ mod static_events {
|
||||
C: StaticEventContent + MessageLikeEventContent + RedactContent,
|
||||
C::Redacted: MessageLikeEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::MessageLike, C::TYPE);
|
||||
const KIND: EventKind = EventKind::MessageLike;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::OriginalSyncMessageLikeEvent<C>
|
||||
where
|
||||
C: StaticEventContent + MessageLikeEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::OriginalMessageLike, C::TYPE);
|
||||
const KIND: EventKind = EventKind::OriginalMessageLike;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RedactedSyncMessageLikeEvent<C>
|
||||
where
|
||||
C: StaticEventContent + MessageLikeEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::RedactedMessageLike, C::TYPE);
|
||||
const KIND: EventKind = EventKind::RedactedMessageLike;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl SyncEvent for events::room::redaction::SyncRoomRedactionEvent {
|
||||
const ID: (EventKind, &'static str) =
|
||||
(EventKind::MessageLike, events::room::redaction::RoomRedactionEventContent::TYPE);
|
||||
const KIND: EventKind = EventKind::MessageLike;
|
||||
const TYPE: &'static str = events::room::redaction::RoomRedactionEventContent::TYPE;
|
||||
}
|
||||
|
||||
impl SyncEvent for events::room::redaction::OriginalSyncRoomRedactionEvent {
|
||||
const ID: (EventKind, &'static str) = (
|
||||
EventKind::OriginalMessageLike,
|
||||
events::room::redaction::RoomRedactionEventContent::TYPE,
|
||||
);
|
||||
const KIND: EventKind = EventKind::OriginalMessageLike;
|
||||
const TYPE: &'static str = events::room::redaction::RoomRedactionEventContent::TYPE;
|
||||
}
|
||||
|
||||
impl SyncEvent for events::room::redaction::RedactedSyncRoomRedactionEvent {
|
||||
const ID: (EventKind, &'static str) = (
|
||||
EventKind::RedactedMessageLike,
|
||||
events::room::redaction::RoomRedactionEventContent::TYPE,
|
||||
);
|
||||
const KIND: EventKind = EventKind::RedactedMessageLike;
|
||||
const TYPE: &'static str = events::room::redaction::RoomRedactionEventContent::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::SyncStateEvent<C>
|
||||
@@ -513,46 +534,53 @@ mod static_events {
|
||||
C: StaticEventContent + StateEventContent + RedactContent,
|
||||
C::Redacted: StateEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::State, C::TYPE);
|
||||
const KIND: EventKind = EventKind::State;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::OriginalSyncStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + StateEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::OriginalState, C::TYPE);
|
||||
const KIND: EventKind = EventKind::OriginalState;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RedactedSyncStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + StateEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::RedactedState, C::TYPE);
|
||||
const KIND: EventKind = EventKind::RedactedState;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::StrippedStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + StateEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::StrippedState, C::TYPE);
|
||||
const KIND: EventKind = EventKind::StrippedState;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::InitialStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + StateEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::InitialState, C::TYPE);
|
||||
const KIND: EventKind = EventKind::InitialState;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::ToDeviceEvent<C>
|
||||
where
|
||||
C: StaticEventContent + ToDeviceEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::ToDevice, C::TYPE);
|
||||
const KIND: EventKind = EventKind::ToDevice;
|
||||
const TYPE: &'static str = C::TYPE;
|
||||
}
|
||||
|
||||
impl SyncEvent for PresenceEvent {
|
||||
const ID: (EventKind, &'static str) = (EventKind::Presence, PresenceEventContent::TYPE);
|
||||
const KIND: EventKind = EventKind::Presence;
|
||||
const TYPE: &'static str = PresenceEventContent::TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +595,13 @@ mod tests {
|
||||
EphemeralTestEvent, EventBuilder, StateTestEvent, StrippedStateTestEvent, TimelineTestEvent,
|
||||
};
|
||||
use ruma::{
|
||||
events::room::member::{OriginalSyncRoomMemberEvent, StrippedRoomMemberEvent},
|
||||
events::{
|
||||
room::{
|
||||
member::{OriginalSyncRoomMemberEvent, StrippedRoomMemberEvent},
|
||||
power_levels::OriginalSyncRoomPowerLevelsEvent,
|
||||
},
|
||||
typing::SyncTypingEvent,
|
||||
},
|
||||
room_id,
|
||||
};
|
||||
use serde_json::json;
|
||||
@@ -575,7 +609,7 @@ mod tests {
|
||||
use crate::{room, Client};
|
||||
|
||||
#[async_test]
|
||||
async fn event_handler() -> crate::Result<()> {
|
||||
async fn register_event_handler() -> crate::Result<()> {
|
||||
use std::sync::atomic::{AtomicU8, Ordering::SeqCst};
|
||||
|
||||
let client = crate::client::tests::logged_in_client(None).await;
|
||||
@@ -593,23 +627,26 @@ mod tests {
|
||||
future::ready(())
|
||||
}
|
||||
})
|
||||
.await
|
||||
.await;
|
||||
client
|
||||
.register_event_handler({
|
||||
let typing_count = typing_count.clone();
|
||||
move |_ev: OriginalSyncRoomMemberEvent| {
|
||||
move |_ev: SyncTypingEvent| {
|
||||
typing_count.fetch_add(1, SeqCst);
|
||||
future::ready(())
|
||||
}
|
||||
})
|
||||
.await
|
||||
.await;
|
||||
client
|
||||
.register_event_handler({
|
||||
let power_levels_count = power_levels_count.clone();
|
||||
move |_ev: OriginalSyncRoomMemberEvent, _client: Client, _room: room::Room| {
|
||||
move |_ev: OriginalSyncRoomPowerLevelsEvent, _client: Client, _room: room::Room| {
|
||||
power_levels_count.fetch_add(1, SeqCst);
|
||||
future::ready(())
|
||||
}
|
||||
})
|
||||
.await
|
||||
.await;
|
||||
client
|
||||
.register_event_handler({
|
||||
let invited_member_count = invited_member_count.clone();
|
||||
move |_ev: StrippedRoomMemberEvent| {
|
||||
@@ -674,4 +711,57 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn remove_event_handler() -> crate::Result<()> {
|
||||
use std::sync::atomic::{AtomicU8, Ordering::SeqCst};
|
||||
|
||||
let client = crate::client::tests::logged_in_client(None).await;
|
||||
|
||||
let member_count = Arc::new(AtomicU8::new(0));
|
||||
|
||||
client
|
||||
.register_event_handler({
|
||||
let member_count = member_count.clone();
|
||||
move |_ev: OriginalSyncRoomMemberEvent| {
|
||||
member_count.fetch_add(1, SeqCst);
|
||||
future::ready(())
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
let handle = client
|
||||
.register_event_handler({
|
||||
move |_ev: OriginalSyncRoomMemberEvent| {
|
||||
panic!("handler should have been removed");
|
||||
#[allow(unreachable_code)]
|
||||
future::ready(())
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
client
|
||||
.register_event_handler({
|
||||
let member_count = member_count.clone();
|
||||
move |_ev: OriginalSyncRoomMemberEvent| {
|
||||
member_count.fetch_add(1, SeqCst);
|
||||
future::ready(())
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
let response = EventBuilder::default()
|
||||
.add_joined_room(
|
||||
JoinedRoomBuilder::default().add_timeline_event(TimelineTestEvent::Member),
|
||||
)
|
||||
.build_sync_response();
|
||||
|
||||
client.remove_event_handler(handle).await;
|
||||
|
||||
client.process_sync(response).await?;
|
||||
|
||||
assert_eq!(member_count.load(SeqCst), 2);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{any::type_name, convert::TryFrom, fmt::Debug, sync::Arc, time::Duration};
|
||||
use std::{any::type_name, fmt::Debug, sync::Arc, time::Duration};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
@@ -50,7 +50,6 @@ pub trait HttpSend: AsyncTraitDeps {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::convert::TryFrom;
|
||||
/// use matrix_sdk::{HttpSend, async_trait, HttpError, config::RequestConfig, bytes::Bytes};
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
#![warn(missing_debug_implementations, missing_docs)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
|
||||
#[cfg(not(any(feature = "native-tls", feature = "rustls-tls",)))]
|
||||
#[cfg(not(any(feature = "native-tls", feature = "rustls-tls")))]
|
||||
compile_error!("one of 'native-tls' or 'rustls-tls' features must be enabled");
|
||||
|
||||
#[cfg(all(feature = "native-tls", feature = "rustls-tls",))]
|
||||
#[cfg(all(feature = "native-tls", feature = "rustls-tls"))]
|
||||
compile_error!("only one of 'native-tls' or 'rustls-tls' features can be enabled");
|
||||
|
||||
#[cfg(all(feature = "sso-login", target_arch = "wasm32"))]
|
||||
|
||||
@@ -165,7 +165,6 @@ impl Common {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// use matrix_sdk::{room::MessagesOptions, Client};
|
||||
/// # use matrix_sdk::ruma::{
|
||||
/// # api::client::filter::RoomEventFilter,
|
||||
@@ -263,7 +262,6 @@ impl Common {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// use matrix_sdk::Client;
|
||||
/// # use matrix_sdk::ruma::{
|
||||
/// # api::client::filter::RoomEventFilter,
|
||||
@@ -315,8 +313,10 @@ impl Common {
|
||||
for await item in backward_store {
|
||||
match item {
|
||||
Ok(event) => yield Ok(event),
|
||||
Err(TimelineStreamError::EndCache { fetch_more_token }) => if let Err(error) = room.request_messages(&fetch_more_token).await {
|
||||
yield Err(error);
|
||||
Err(TimelineStreamError::EndCache { fetch_more_token }) => {
|
||||
if let Err(error) = room.request_messages(&fetch_more_token).await {
|
||||
yield Err(error);
|
||||
}
|
||||
},
|
||||
Err(TimelineStreamError::Store(error)) => yield Err(error.into()),
|
||||
}
|
||||
@@ -343,7 +343,6 @@ impl Common {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// use matrix_sdk::Client;
|
||||
/// # use matrix_sdk::ruma::{
|
||||
/// # api::client::filter::RoomEventFilter,
|
||||
@@ -402,7 +401,6 @@ impl Common {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```no_run
|
||||
/// # use std::convert::TryFrom;
|
||||
/// use matrix_sdk::Client;
|
||||
/// # use matrix_sdk::ruma::{
|
||||
/// # api::client::filter::RoomEventFilter,
|
||||
@@ -445,8 +443,10 @@ impl Common {
|
||||
for await item in backward_store {
|
||||
match item {
|
||||
Ok(event) => yield Ok(event),
|
||||
Err(TimelineStreamError::EndCache { fetch_more_token }) => if let Err(error) = room.request_messages(&fetch_more_token).await {
|
||||
yield Err(error);
|
||||
Err(TimelineStreamError::EndCache { fetch_more_token }) => {
|
||||
if let Err(error) = room.request_messages(&fetch_more_token).await {
|
||||
yield Err(error);
|
||||
}
|
||||
},
|
||||
Err(TimelineStreamError::Store(error)) => yield Err(error.into()),
|
||||
}
|
||||
@@ -1075,7 +1075,9 @@ impl Common {
|
||||
|
||||
/// Options for [`messages`][Common::messages].
|
||||
///
|
||||
/// See that method and <https://spec.matrix.org/v1.3/client-server-api/#get_matrixclientv3roomsroomidmessages> for details.
|
||||
/// See that method and
|
||||
/// <https://spec.matrix.org/v1.3/client-server-api/#get_matrixclientv3roomsroomidmessages>
|
||||
/// for details.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct MessagesOptions<'a> {
|
||||
|
||||
@@ -416,7 +416,6 @@ impl Joined {
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use matrix_sdk::ruma::room_id;
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # use serde::{Deserialize, Serialize};
|
||||
/// use matrix_sdk::ruma::{
|
||||
/// events::{
|
||||
@@ -513,7 +512,6 @@ impl Joined {
|
||||
/// # use url::Url;
|
||||
/// # use futures::executor::block_on;
|
||||
/// # use matrix_sdk::ruma::room_id;
|
||||
/// # use std::convert::TryFrom;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080")?;
|
||||
/// # let mut client = Client::new(homeserver).await?;
|
||||
@@ -557,7 +555,7 @@ impl Joined {
|
||||
if event_type == "m.reaction" {
|
||||
debug!(
|
||||
room_id = %self.room_id(),
|
||||
"Sending plaintext event because the event type is {}", event_type
|
||||
"Sending plaintext event because the event type is {event_type}",
|
||||
);
|
||||
(Raw::new(&content)?.cast(), event_type)
|
||||
} else {
|
||||
|
||||
@@ -36,7 +36,7 @@ impl Client {
|
||||
for (room_id, room_info) in &rooms.join {
|
||||
let room = self.get_room(room_id);
|
||||
if room.is_none() {
|
||||
error!("Can't call event handler, room {} not found", room_id);
|
||||
error!("Can't call event handler, room {room_id} not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ impl Client {
|
||||
for (room_id, room_info) in &rooms.leave {
|
||||
let room = self.get_room(room_id);
|
||||
if room.is_none() {
|
||||
error!("Can't call event handler, room {} not found", room_id);
|
||||
error!("Can't call event handler, room {room_id} not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ impl Client {
|
||||
for (room_id, room_info) in &rooms.invite {
|
||||
let room = self.get_room(room_id);
|
||||
if room.is_none() {
|
||||
error!("Can't call event handler, room {} not found", room_id);
|
||||
error!("Can't call event handler, room {room_id} not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ impl Client {
|
||||
let room = match self.get_room(room_id) {
|
||||
Some(room) => room,
|
||||
None => {
|
||||
warn!("Can't call notification handler, room {} not found", room_id);
|
||||
warn!("Can't call notification handler, room {room_id} not found");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
@@ -128,9 +128,7 @@ impl Client {
|
||||
Ok(r)
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Received an invalid response: {}", e);
|
||||
Self::sleep().await;
|
||||
|
||||
error!("Received an invalid response: {e}");
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{convert::TryFrom, fmt::Debug, sync::Arc};
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
use atty::Stream;
|
||||
use clap::{Arg, ArgMatches, Command as Argparse};
|
||||
@@ -66,7 +66,7 @@ impl InspectorHelper {
|
||||
fn complete_event_types(&self, arg: Option<&&str>) -> Vec<Pair> {
|
||||
Self::EVENT_TYPES
|
||||
.iter()
|
||||
.map(|&t| Pair { display: t.to_owned(), replacement: format!("{} ", t) })
|
||||
.map(|&t| Pair { display: t.to_owned(), replacement: format!("{t} ") })
|
||||
.filter(|r| if let Some(arg) = arg { r.replacement.starts_with(arg) } else { true })
|
||||
.collect()
|
||||
}
|
||||
@@ -105,7 +105,7 @@ impl Completer for InspectorHelper {
|
||||
("get-members", "get all the membership events in the given room"),
|
||||
]
|
||||
.iter()
|
||||
.map(|(r, d)| Pair { display: format!("{} ({})", r, d), replacement: format!("{} ", r) })
|
||||
.map(|(r, d)| Pair { display: format!("{r} ({d})"), replacement: format!("{r} ") })
|
||||
.collect();
|
||||
|
||||
if args.is_empty() {
|
||||
@@ -188,13 +188,13 @@ impl Printer {
|
||||
for line in LinesWithEndings::from(&data) {
|
||||
let ranges: Vec<(Style, &str)> = h.highlight(line, &self.ps);
|
||||
let escaped = as_24_bit_terminal_escaped(&ranges[..], false);
|
||||
print!("{}", escaped);
|
||||
print!("{escaped}");
|
||||
}
|
||||
|
||||
// Clear the formatting
|
||||
println!("\x1b[0m");
|
||||
} else {
|
||||
println!("{}", data);
|
||||
println!("{data}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,7 +318,7 @@ impl Inspector {
|
||||
self.run(m).await;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
println!("{e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -300,7 +300,7 @@ fn run_wasm_pack_tests(cmd: Option<WasmFeatureSet>) -> Result<()> {
|
||||
]);
|
||||
|
||||
let run = |(folder, arg_set): (&str, &str)| {
|
||||
let _p = pushd(format!("crates/{}", folder));
|
||||
let _p = pushd(format!("crates/{folder}"));
|
||||
cmd!("pwd").run()?; // print dir so we know what might have failed
|
||||
cmd!("wasm-pack test --node -- ").args(arg_set.split_whitespace()).run()?;
|
||||
cmd!("wasm-pack test --firefox --headless --").args(arg_set.split_whitespace()).run()
|
||||
|
||||
Reference in New Issue
Block a user