feat(client): make it possible to subscribe to key upload errors (#6135)

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
This commit is contained in:
Johannes Marbach
2026-02-11 14:11:51 +01:00
committed by GitHub
parent c6b58b0e2b
commit 70665a84aa
5 changed files with 94 additions and 8 deletions

View File

@@ -31,6 +31,9 @@ All notable changes to this project will be documented in this file.
### Features
- Add `Client::subscribe_to_duplicate_key_upload_errors` for listening to duplicate key
upload errors from `/keys/upload`.
([#6135](https://github.com/matrix-org/matrix-rust-sdk/pull/6135/))
- Add `NotificationItem::raw_event` to get the raw event content of the event that triggered the notification, which can be useful for debugging and to support clients that want to implement custom handling for certain notifications. ([#6122](https://github.com/matrix-org/matrix-rust-sdk/pull/6122))
- [**breaking**] Extend `TimelineFocus::Event` to allow marking the target
event as the root of a thread.

View File

@@ -237,6 +237,32 @@ pub trait AccountDataListener: SyncOutsideWasm + SendOutsideWasm {
fn on_change(&self, event: AccountDataEvent);
}
/// A listener for duplicate key upload errors triggered by requests to
/// /keys/upload.
#[matrix_sdk_ffi_macros::export(callback_interface)]
pub trait DuplicateKeyUploadErrorListener: SyncOutsideWasm + SendOutsideWasm {
/// Called once when uploading keys fails.
fn on_duplicate_key_upload_error(&self, message: Option<DuplicateOneTimeKeyErrorMessage>);
}
/// Information about the old and new key that caused a duplicate key upload
/// error in /keys/upload.
#[derive(uniffi::Record)]
pub struct DuplicateOneTimeKeyErrorMessage {
/// The previously uploaded one-time key, encoded as unpadded base64.
pub old_key: String,
/// The one-time key we attempted to upload, encoded as unpadded base64
pub new_key: String,
}
impl From<matrix_sdk::encryption::DuplicateOneTimeKeyErrorMessage>
for DuplicateOneTimeKeyErrorMessage
{
fn from(value: matrix_sdk::encryption::DuplicateOneTimeKeyErrorMessage) -> Self {
Self { old_key: value.old_key.to_base64(), new_key: value.new_key.to_base64() }
}
}
/// A listener for changes of room account data events.
#[matrix_sdk_ffi_macros::export(callback_interface)]
pub trait RoomAccountDataListener: SyncOutsideWasm + SendOutsideWasm {
@@ -748,6 +774,28 @@ impl Client {
})))
}
/// Subscribe to duplicate key upload errors triggered by requests to
/// /keys/upload.
pub fn subscribe_to_duplicate_key_upload_errors(
&self,
listener: Box<dyn DuplicateKeyUploadErrorListener>,
) -> Arc<TaskHandle> {
let mut subscriber = self.inner.subscribe_to_duplicate_key_upload_errors();
Arc::new(TaskHandle::new(get_runtime_handle().spawn(async move {
loop {
match subscriber.recv().await {
Ok(message) => {
listener.on_duplicate_key_upload_error(message.map(|m| m.into()))
}
Err(err) => {
error!("error when listening to key upload errors: {err}");
}
}
}
})))
}
/// Subscribe to updates of global account data events.
///
/// Be careful that only the most recent value can be observed. Subscribers

View File

@@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file.
### Features
- Add `Client::subscribe_to_duplicate_key_upload_errors` for listening to duplicate key
upload errors from `/keys/upload`.
([#6135](https://github.com/matrix-org/matrix-rust-sdk/pull/6135/))
- Add `Room::pin_event` and `Room::unpin_event`, which allow pinning and unpinning events from a
room. These were extracted from the `matrix_sdk_ui` crate, with no changes in functionality.
([#6106](https://github.com/matrix-org/matrix-rust-sdk/pull/6106))

View File

@@ -119,7 +119,10 @@ use crate::{
#[cfg(feature = "e2e-encryption")]
use crate::{
cross_process_lock::CrossProcessLock,
encryption::{Encryption, EncryptionData, EncryptionSettings, VerificationState},
encryption::{
DuplicateOneTimeKeyErrorMessage, Encryption, EncryptionData, EncryptionSettings,
VerificationState,
},
};
mod builder;
@@ -387,6 +390,12 @@ pub(crate) struct ClientInner {
/// A monitor for background tasks spawned by the client.
pub(crate) task_monitor: TaskMonitor,
/// A sender to notify subscribers about duplicate key upload errors
/// triggered by requests to /keys/upload.
#[cfg(feature = "e2e-encryption")]
pub(crate) duplicate_key_upload_error_sender:
broadcast::Sender<Option<DuplicateOneTimeKeyErrorMessage>>,
}
impl ClientInner {
@@ -454,6 +463,8 @@ impl ClientInner {
search_index: search_index_handler,
thread_subscription_catchup,
task_monitor: TaskMonitor::new(),
#[cfg(feature = "e2e-encryption")]
duplicate_key_upload_error_sender: broadcast::channel(1).0,
};
#[allow(clippy::let_and_return)]
@@ -3320,6 +3331,15 @@ impl Client {
pub fn task_monitor(&self) -> &TaskMonitor {
&self.inner.task_monitor
}
/// Add a subscriber for duplicate key upload error notifications triggered
/// by requests to /keys/upload.
#[cfg(feature = "e2e-encryption")]
pub fn subscribe_to_duplicate_key_upload_errors(
&self,
) -> broadcast::Receiver<Option<DuplicateOneTimeKeyErrorMessage>> {
self.inner.duplicate_key_upload_error_sender.subscribe()
}
}
/// Contains the disk size of the different stores, if known. It won't be

View File

@@ -368,12 +368,12 @@ impl OAuthCrossSigningResetInfo {
/// A struct that helps to parse the custom error message Synapse posts if a
/// duplicate one-time key is uploaded.
#[derive(Debug)]
struct DuplicateOneTimeKeyErrorMessage {
#[derive(Clone, Debug)]
pub struct DuplicateOneTimeKeyErrorMessage {
/// The previously uploaded one-time key.
old_key: Curve25519PublicKey,
pub old_key: Curve25519PublicKey,
/// The one-time key we're attempting to upload right now.
new_key: Curve25519PublicKey,
pub new_key: Curve25519PublicKey,
}
impl FromStr for DuplicateOneTimeKeyErrorMessage {
@@ -678,9 +678,10 @@ impl Client {
.is_some();
if message.starts_with("One time key") && !already_reported {
if let Ok(message) =
DuplicateOneTimeKeyErrorMessage::from_str(message)
{
let error_message =
DuplicateOneTimeKeyErrorMessage::from_str(message);
if let Ok(message) = &error_message {
error!(
sentry = true,
old_key = %message.old_key,
@@ -700,6 +701,17 @@ impl Client {
StateStoreDataValue::OneTimeKeyAlreadyUploaded,
)
.await?;
if let Err(e) = self
.inner
.duplicate_key_upload_error_sender
.send(error_message.ok())
{
error!(
"Failed to dispatch duplicate key upload error notification: {}",
e
);
}
}
}
}