atagen

macltok

public
Star0
Watch0
cb0668d30c14c14e0b1edddc9133ebf1e98bd5cb
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git

Blame: src/transport.rs

96fdf90aacd6atagen2026-09-08 08:24 UTC1
use std::{
96fdf90aacd6atagen2026-09-08 08:24 UTC2
    fmt,
31ce2453c82fatagen2026-09-24 13:07 UTC3
    future::Future,
96fdf90aacd6atagen2026-09-08 08:24 UTC4
    pin::Pin,
31ce2453c82fatagen2026-09-24 13:07 UTC5
    sync::Arc,
96fdf90aacd6atagen2026-09-08 08:24 UTC6
    task::{Context, Poll},
96fdf90aacd6atagen2026-09-08 08:24 UTC7
};
96fdf90aacd6atagen2026-09-08 08:24 UTC8
96fdf90aacd6atagen2026-09-08 08:24 UTC9
use matrix_sdk::{Client, RoomMemberships};
96fdf90aacd6atagen2026-09-08 08:24 UTC10
use matrix_sdk_ui::{
96fdf90aacd6atagen2026-09-08 08:24 UTC11
    notification_client::{
96fdf90aacd6atagen2026-09-08 08:24 UTC12
        NotificationClient, NotificationProcessSetup, NotificationStatus, RawNotificationEvent,
96fdf90aacd6atagen2026-09-08 08:24 UTC13
    },
31ce2453c82fatagen2026-09-24 13:07 UTC14
    spaces::{SpaceRoomList, SpaceService, room_list::SpaceRoomListPaginationState},
96fdf90aacd6atagen2026-09-08 08:24 UTC15
    sync_service::SyncService,
96fdf90aacd6atagen2026-09-08 08:24 UTC16
};
96fdf90aacd6atagen2026-09-08 08:24 UTC17
use ruma::{
5d2974de5826atagen2026-10-08 11:29 UTC18
    EventId, OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedRoomOrAliasId,
31ce2453c82fatagen2026-09-24 13:07 UTC19
    OwnedServerName, OwnedTransactionId, OwnedUserId, RoomId, UserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC20
    events::{
31ce2453c82fatagen2026-09-24 13:07 UTC21
        AnyGlobalAccountDataEventContent, AnyRoomAccountDataEvent, AnyRoomAccountDataEventContent,
31ce2453c82fatagen2026-09-24 13:07 UTC22
        GlobalAccountDataEventType, RoomAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC23
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC24
    serde::Raw,
96fdf90aacd6atagen2026-09-08 08:24 UTC25
};
96fdf90aacd6atagen2026-09-08 08:24 UTC26
use tokio::sync::{OnceCell, mpsc, oneshot, watch};
96fdf90aacd6atagen2026-09-08 08:24 UTC27
96fdf90aacd6atagen2026-09-08 08:24 UTC28
use crate::{
31ce2453c82fatagen2026-09-24 13:07 UTC29
    AccountCommand, AttachmentUpload, Command, CommandOutput, ConnectionState, CreateRoomOptions,
960ac0721079atagen2026-09-25 00:24 UTC30
    EncryptionCommand, EncryptionState, Error, ErrorKind, Event, EventRef, InteractiveAuth,
5b21b919d1e6atagen2026-09-27 11:47 UTC31
    InteractiveAuthOutcome, LifecycleCommand, Media, MediaCommand, MediaId, MediaLocation,
5b21b919d1e6atagen2026-09-27 11:47 UTC32
    MediaSize, MemberFilter, MemberSummary, MessageContent, MessageEditContent,
5b21b919d1e6atagen2026-09-27 11:47 UTC33
    NotificationCommand, OwnDevice, PowerLevelChanges, Profile, PushNotification,
5b21b919d1e6atagen2026-09-27 11:47 UTC34
    PushNotificationEvent, PushNotificationStatus, RoomCommand, RoomListFilter,
5b21b919d1e6atagen2026-09-27 11:47 UTC35
    RoomNotificationMode, RoomNotificationSettings, RoomPowerLevels, RoomSummary, SpaceChild,
5b21b919d1e6atagen2026-09-27 11:47 UTC36
    TimelineCommand, TimelineId, VerificationAction, VerificationTarget,
96fdf90aacd6atagen2026-09-08 08:24 UTC37
    encryption::encryption_state,
a250c7fa43fbatagen2026-09-26 13:35 UTC38
    engine::{MediaService, StoreLock},
96fdf90aacd6atagen2026-09-08 08:24 UTC39
    model::{PushNotificationRoom, PushNotificationSender},
31ce2453c82fatagen2026-09-24 13:07 UTC40
    normalise::{member_summary, room_summaries, space_child},
96fdf90aacd6atagen2026-09-08 08:24 UTC41
};
96fdf90aacd6atagen2026-09-08 08:24 UTC42
96fdf90aacd6atagen2026-09-08 08:24 UTC43
#[derive(Clone)]
96fdf90aacd6atagen2026-09-08 08:24 UTC44
pub struct ClientHandle {
31ce2453c82fatagen2026-09-24 13:07 UTC45
    requests: mpsc::Sender<Request>,
96fdf90aacd6atagen2026-09-08 08:24 UTC46
    client: Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC47
    connection: watch::Receiver<ConnectionState>,
96fdf90aacd6atagen2026-09-08 08:24 UTC48
    notification_client: Arc<OnceCell<NotificationClient>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC49
    sync_service: Arc<SyncService>,
31ce2453c82fatagen2026-09-24 13:07 UTC50
    media: Arc<MediaService>,
31ce2453c82fatagen2026-09-24 13:07 UTC51
    spaces: Arc<OnceCell<SpaceService>>,
a250c7fa43fbatagen2026-09-26 13:35 UTC52
    _store_lock: Option<Arc<StoreLock>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC53
}
96fdf90aacd6atagen2026-09-08 08:24 UTC54
96fdf90aacd6atagen2026-09-08 08:24 UTC55
impl fmt::Debug for ClientHandle {
96fdf90aacd6atagen2026-09-08 08:24 UTC56
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
96fdf90aacd6atagen2026-09-08 08:24 UTC57
        formatter
96fdf90aacd6atagen2026-09-08 08:24 UTC58
            .debug_struct("ClientHandle")
96fdf90aacd6atagen2026-09-08 08:24 UTC59
            .finish_non_exhaustive()
96fdf90aacd6atagen2026-09-08 08:24 UTC60
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC61
}
96fdf90aacd6atagen2026-09-08 08:24 UTC62
31ce2453c82fatagen2026-09-24 13:07 UTC63
/// a command's answer. drop it if you don't care, the command still runs
31ce2453c82fatagen2026-09-24 13:07 UTC64
#[derive(Debug)]
31ce2453c82fatagen2026-09-24 13:07 UTC65
#[must_use = "dropping it is fine but then you'll never know"]
31ce2453c82fatagen2026-09-24 13:07 UTC66
pub struct Pending(oneshot::Receiver<Result<CommandOutput, Error>>);
31ce2453c82fatagen2026-09-24 13:07 UTC67
31ce2453c82fatagen2026-09-24 13:07 UTC68
impl Future for Pending {
31ce2453c82fatagen2026-09-24 13:07 UTC69
    type Output = Result<CommandOutput, Error>;
31ce2453c82fatagen2026-09-24 13:07 UTC70
31ce2453c82fatagen2026-09-24 13:07 UTC71
    fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
31ce2453c82fatagen2026-09-24 13:07 UTC72
        Pin::new(&mut self.0)
31ce2453c82fatagen2026-09-24 13:07 UTC73
            .poll(context)
31ce2453c82fatagen2026-09-24 13:07 UTC74
            .map(|result| result.unwrap_or_else(|_| Err(Error::interrupted())))
31ce2453c82fatagen2026-09-24 13:07 UTC75
    }
31ce2453c82fatagen2026-09-24 13:07 UTC76
}
31ce2453c82fatagen2026-09-24 13:07 UTC77
96fdf90aacd6atagen2026-09-08 08:24 UTC78
impl ClientHandle {
f12377bce9b9atagen2026-09-26 12:32 UTC79
    /// current credentials, it holds secrets. the engine saves it for you unless the
f12377bce9b9atagen2026-09-26 12:32 UTC80
    /// session was built `without_persistence`
62fe32759529atagen2026-09-26 08:50 UTC81
    #[cfg(any(feature = "sqlite", feature = "indexeddb"))]
96fdf90aacd6atagen2026-09-08 08:24 UTC82
    pub fn session_record(&self) -> Result<crate::SessionRecord, crate::AccountError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC83
        crate::account::session_record(&self.client)
96fdf90aacd6atagen2026-09-08 08:24 UTC84
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC85
5b21b919d1e6atagen2026-09-27 11:47 UTC86
    /// the bearer token. it rotates on every refresh so ask again after a 401 rather than
5b21b919d1e6atagen2026-09-27 11:47 UTC87
    /// keeping it, and keep it in memory and away from all but the homeserver's media endpoints
5b21b919d1e6atagen2026-09-27 11:47 UTC88
    pub fn access_token(&self) -> Option<String> {
5b21b919d1e6atagen2026-09-27 11:47 UTC89
        self.client.access_token()
5b21b919d1e6atagen2026-09-27 11:47 UTC90
    }
5b21b919d1e6atagen2026-09-27 11:47 UTC91
31ce2453c82fatagen2026-09-24 13:07 UTC92
    /// queue a command, waiting for room in the queue if there isn't any
31ce2453c82fatagen2026-09-24 13:07 UTC93
    pub async fn send(&self, command: Command) -> Result<Pending, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC94
        let (request, pending) = Request::new(command);
31ce2453c82fatagen2026-09-24 13:07 UTC95
        self.requests
31ce2453c82fatagen2026-09-24 13:07 UTC96
            .send(request)
96fdf90aacd6atagen2026-09-08 08:24 UTC97
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC98
            .map_err(|_| Error::interrupted())?;
31ce2453c82fatagen2026-09-24 13:07 UTC99
        Ok(pending)
31ce2453c82fatagen2026-09-24 13:07 UTC100
    }
31ce2453c82fatagen2026-09-24 13:07 UTC101
31ce2453c82fatagen2026-09-24 13:07 UTC102
    /// queue a command or fail with `QueueFull` right now
31ce2453c82fatagen2026-09-24 13:07 UTC103
    pub fn try_send(&self, command: Command) -> Result<Pending, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC104
        let (request, pending) = Request::new(command);
31ce2453c82fatagen2026-09-24 13:07 UTC105
        self.requests
31ce2453c82fatagen2026-09-24 13:07 UTC106
            .try_send(request)
31ce2453c82fatagen2026-09-24 13:07 UTC107
            .map_err(|error| match error {
31ce2453c82fatagen2026-09-24 13:07 UTC108
                mpsc::error::TrySendError::Full(_) => {
31ce2453c82fatagen2026-09-24 13:07 UTC109
                    Error::new(ErrorKind::QueueFull, "the command queue is full")
31ce2453c82fatagen2026-09-24 13:07 UTC110
                }
31ce2453c82fatagen2026-09-24 13:07 UTC111
                mpsc::error::TrySendError::Closed(_) => Error::interrupted(),
31ce2453c82fatagen2026-09-24 13:07 UTC112
            })?;
31ce2453c82fatagen2026-09-24 13:07 UTC113
        Ok(pending)
31ce2453c82fatagen2026-09-24 13:07 UTC114
    }
31ce2453c82fatagen2026-09-24 13:07 UTC115
31ce2453c82fatagen2026-09-24 13:07 UTC116
    /// queue a command and wait for its answer. timeline sends answer once the
31ce2453c82fatagen2026-09-24 13:07 UTC117
    /// sdk send queue has them, delivery shows up later as the item's send state
31ce2453c82fatagen2026-09-24 13:07 UTC118
    pub async fn execute(&self, command: Command) -> Result<CommandOutput, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC119
        self.send(command).await?.await
31ce2453c82fatagen2026-09-24 13:07 UTC120
    }
31ce2453c82fatagen2026-09-24 13:07 UTC121
31ce2453c82fatagen2026-09-24 13:07 UTC122
    async fn run(&self, command: Command) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC123
        self.execute(command).await.map(drop)
31ce2453c82fatagen2026-09-24 13:07 UTC124
    }
31ce2453c82fatagen2026-09-24 13:07 UTC125
31ce2453c82fatagen2026-09-24 13:07 UTC126
    async fn run_for_room(&self, command: RoomCommand) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC127
        match self.execute(Command::Room(command)).await? {
31ce2453c82fatagen2026-09-24 13:07 UTC128
            CommandOutput::Room(room_id) => Ok(room_id),
31ce2453c82fatagen2026-09-24 13:07 UTC129
            output => Err(Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC130
                ErrorKind::Other,
31ce2453c82fatagen2026-09-24 13:07 UTC131
                format!("expected a room but got {output:?}"),
31ce2453c82fatagen2026-09-24 13:07 UTC132
            )),
31ce2453c82fatagen2026-09-24 13:07 UTC133
        }
31ce2453c82fatagen2026-09-24 13:07 UTC134
    }
31ce2453c82fatagen2026-09-24 13:07 UTC135
31ce2453c82fatagen2026-09-24 13:07 UTC136
    pub async fn shutdown(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC137
        self.run(Command::Lifecycle(LifecycleCommand::Shutdown))
31ce2453c82fatagen2026-09-24 13:07 UTC138
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC139
    }
31ce2453c82fatagen2026-09-24 13:07 UTC140
31ce2453c82fatagen2026-09-24 13:07 UTC141
    pub async fn logout(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC142
        self.run(Command::Account(AccountCommand::Logout)).await
96fdf90aacd6atagen2026-09-08 08:24 UTC143
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC144
96fdf90aacd6atagen2026-09-08 08:24 UTC145
    pub async fn delete_devices(
96fdf90aacd6atagen2026-09-08 08:24 UTC146
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC147
        device_ids: Vec<OwnedDeviceId>,
96fdf90aacd6atagen2026-09-08 08:24 UTC148
        auth: Option<InteractiveAuth>,
31ce2453c82fatagen2026-09-24 13:07 UTC149
    ) -> Result<InteractiveAuthOutcome, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC150
        match self
31ce2453c82fatagen2026-09-24 13:07 UTC151
            .run(Command::Account(AccountCommand::DeleteDevices {
96fdf90aacd6atagen2026-09-08 08:24 UTC152
                device_ids,
96fdf90aacd6atagen2026-09-08 08:24 UTC153
                auth,
31ce2453c82fatagen2026-09-24 13:07 UTC154
            }))
96fdf90aacd6atagen2026-09-08 08:24 UTC155
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC156
        {
31ce2453c82fatagen2026-09-24 13:07 UTC157
            Ok(()) => Ok(InteractiveAuthOutcome::Completed),
31ce2453c82fatagen2026-09-24 13:07 UTC158
            Err(Error {
31ce2453c82fatagen2026-09-24 13:07 UTC159
                challenge: Some(challenge),
31ce2453c82fatagen2026-09-24 13:07 UTC160
                ..
31ce2453c82fatagen2026-09-24 13:07 UTC161
            }) => Ok(InteractiveAuthOutcome::Challenge(*challenge)),
31ce2453c82fatagen2026-09-24 13:07 UTC162
            Err(error) => Err(error),
31ce2453c82fatagen2026-09-24 13:07 UTC163
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC164
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC165
96fdf90aacd6atagen2026-09-08 08:24 UTC166
    pub async fn rename_device(
96fdf90aacd6atagen2026-09-08 08:24 UTC167
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC168
        device_id: OwnedDeviceId,
96fdf90aacd6atagen2026-09-08 08:24 UTC169
        display_name: impl Into<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC170
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC171
        self.run(Command::Account(AccountCommand::RenameDevice {
96fdf90aacd6atagen2026-09-08 08:24 UTC172
            device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC173
            display_name: display_name.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC174
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC175
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC176
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC177
31ce2453c82fatagen2026-09-24 13:07 UTC178
    pub async fn set_global_account_data(
31ce2453c82fatagen2026-09-24 13:07 UTC179
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC180
        event_type: GlobalAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC181
        content: Raw<AnyGlobalAccountDataEventContent>,
31ce2453c82fatagen2026-09-24 13:07 UTC182
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC183
        self.run(Command::Account(AccountCommand::SetAccountData {
31ce2453c82fatagen2026-09-24 13:07 UTC184
            event_type,
31ce2453c82fatagen2026-09-24 13:07 UTC185
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC186
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC187
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC188
    }
31ce2453c82fatagen2026-09-24 13:07 UTC189
31ce2453c82fatagen2026-09-24 13:07 UTC190
    pub async fn set_room_account_data(
31ce2453c82fatagen2026-09-24 13:07 UTC191
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC192
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC193
        event_type: RoomAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC194
        content: Raw<AnyRoomAccountDataEventContent>,
31ce2453c82fatagen2026-09-24 13:07 UTC195
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC196
        self.run(Command::Room(RoomCommand::SetAccountData {
31ce2453c82fatagen2026-09-24 13:07 UTC197
            room_id,
31ce2453c82fatagen2026-09-24 13:07 UTC198
            event_type,
31ce2453c82fatagen2026-09-24 13:07 UTC199
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC200
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC201
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC202
    }
31ce2453c82fatagen2026-09-24 13:07 UTC203
96fdf90aacd6atagen2026-09-08 08:24 UTC204
    pub async fn set_room_notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC205
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC206
        room_id: OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC207
        mode: RoomNotificationMode,
31ce2453c82fatagen2026-09-24 13:07 UTC208
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC209
        self.run(Command::Notification(NotificationCommand::SetRoomMode {
96fdf90aacd6atagen2026-09-08 08:24 UTC210
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC211
            mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC212
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC213
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC214
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC215
31ce2453c82fatagen2026-09-24 13:07 UTC216
    pub async fn reset_room_notification_mode(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC217
        self.run(Command::Notification(NotificationCommand::ResetRoomMode(
96fdf90aacd6atagen2026-09-08 08:24 UTC218
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC219
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC220
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC221
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC222
96fdf90aacd6atagen2026-09-08 08:24 UTC223
    pub async fn set_default_notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC224
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC225
        encrypted: bool,
96fdf90aacd6atagen2026-09-08 08:24 UTC226
        one_to_one: bool,
96fdf90aacd6atagen2026-09-08 08:24 UTC227
        mode: RoomNotificationMode,
31ce2453c82fatagen2026-09-24 13:07 UTC228
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC229
        self.run(Command::Notification(NotificationCommand::SetDefaultMode {
96fdf90aacd6atagen2026-09-08 08:24 UTC230
            encrypted,
96fdf90aacd6atagen2026-09-08 08:24 UTC231
            one_to_one,
96fdf90aacd6atagen2026-09-08 08:24 UTC232
            mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC233
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC234
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC235
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC236
31ce2453c82fatagen2026-09-24 13:07 UTC237
    pub async fn add_notification_keyword(&self, keyword: impl Into<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC238
        self.run(Command::Notification(NotificationCommand::AddKeyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC239
            keyword.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC240
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC241
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC242
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC243
96fdf90aacd6atagen2026-09-08 08:24 UTC244
    pub async fn remove_notification_keyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC245
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC246
        keyword: impl Into<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC247
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC248
        self.run(Command::Notification(NotificationCommand::RemoveKeyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC249
            keyword.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC250
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC251
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC252
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC253
31ce2453c82fatagen2026-09-24 13:07 UTC254
    pub async fn open_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC255
        self.run(Command::Room(RoomCommand::Open(room_id))).await
96fdf90aacd6atagen2026-09-08 08:24 UTC256
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC257
31ce2453c82fatagen2026-09-24 13:07 UTC258
    pub async fn close_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC259
        self.run(Command::Room(RoomCommand::Close(room_id))).await
96fdf90aacd6atagen2026-09-08 08:24 UTC260
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC261
96fdf90aacd6atagen2026-09-08 08:24 UTC262
    pub async fn open_thread(
96fdf90aacd6atagen2026-09-08 08:24 UTC263
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC264
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC265
        root_event_id: OwnedEventId,
31ce2453c82fatagen2026-09-24 13:07 UTC266
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC267
        self.run(Command::Timeline(TimelineCommand::OpenThread {
96fdf90aacd6atagen2026-09-08 08:24 UTC268
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC269
            root_event_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC270
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC271
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC272
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC273
96fdf90aacd6atagen2026-09-08 08:24 UTC274
    pub async fn close_thread(
96fdf90aacd6atagen2026-09-08 08:24 UTC275
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC276
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC277
        root_event_id: OwnedEventId,
31ce2453c82fatagen2026-09-24 13:07 UTC278
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC279
        self.run(Command::Timeline(TimelineCommand::CloseThread {
96fdf90aacd6atagen2026-09-08 08:24 UTC280
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC281
            root_event_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC282
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC283
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC284
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC285
31ce2453c82fatagen2026-09-24 13:07 UTC286
    pub async fn resync(&self, timeline_id: TimelineId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC287
        self.run(Command::Timeline(TimelineCommand::Resync { timeline_id }))
96fdf90aacd6atagen2026-09-08 08:24 UTC288
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC289
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC290
31ce2453c82fatagen2026-09-24 13:07 UTC291
    pub async fn paginate(&self, timeline_id: TimelineId, limit: u16) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC292
        self.run(Command::Timeline(TimelineCommand::Paginate {
31ce2453c82fatagen2026-09-24 13:07 UTC293
            timeline_id,
31ce2453c82fatagen2026-09-24 13:07 UTC294
            limit,
31ce2453c82fatagen2026-09-24 13:07 UTC295
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC296
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC297
    }
31ce2453c82fatagen2026-09-24 13:07 UTC298
31ce2453c82fatagen2026-09-24 13:07 UTC299
    pub async fn send_message(
96fdf90aacd6atagen2026-09-08 08:24 UTC300
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC301
        timeline_id: TimelineId,
31ce2453c82fatagen2026-09-24 13:07 UTC302
        content: MessageContent,
31ce2453c82fatagen2026-09-24 13:07 UTC303
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC304
        self.run(Command::Timeline(TimelineCommand::Send {
31ce2453c82fatagen2026-09-24 13:07 UTC305
            timeline_id,
31ce2453c82fatagen2026-09-24 13:07 UTC306
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC307
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC308
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC309
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC310
31ce2453c82fatagen2026-09-24 13:07 UTC311
    pub async fn edit_message(
96fdf90aacd6atagen2026-09-08 08:24 UTC312
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC313
        timeline_id: TimelineId,
960ac0721079atagen2026-09-25 00:24 UTC314
        target: impl Into<EventRef>,
31ce2453c82fatagen2026-09-24 13:07 UTC315
        content: MessageEditContent,
31ce2453c82fatagen2026-09-24 13:07 UTC316
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC317
        self.run(Command::Timeline(TimelineCommand::Edit {
31ce2453c82fatagen2026-09-24 13:07 UTC318
            timeline_id,
960ac0721079atagen2026-09-25 00:24 UTC319
            target: target.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC320
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC321
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC322
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC323
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC324
31ce2453c82fatagen2026-09-24 13:07 UTC325
    pub async fn redact(
96fdf90aacd6atagen2026-09-08 08:24 UTC326
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC327
        timeline_id: TimelineId,
960ac0721079atagen2026-09-25 00:24 UTC328
        target: impl Into<EventRef>,
31ce2453c82fatagen2026-09-24 13:07 UTC329
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC330
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC331
        self.run(Command::Timeline(TimelineCommand::Redact {
31ce2453c82fatagen2026-09-24 13:07 UTC332
            timeline_id,
960ac0721079atagen2026-09-25 00:24 UTC333
            target: target.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC334
            reason,
31ce2453c82fatagen2026-09-24 13:07 UTC335
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC336
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC337
    }
31ce2453c82fatagen2026-09-24 13:07 UTC338
31ce2453c82fatagen2026-09-24 13:07 UTC339
    pub async fn toggle_reaction(
31ce2453c82fatagen2026-09-24 13:07 UTC340
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC341
        timeline_id: TimelineId,
960ac0721079atagen2026-09-25 00:24 UTC342
        target: impl Into<EventRef>,
31ce2453c82fatagen2026-09-24 13:07 UTC343
        key: impl Into<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC344
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC345
        self.run(Command::Timeline(TimelineCommand::ToggleReaction {
31ce2453c82fatagen2026-09-24 13:07 UTC346
            timeline_id,
960ac0721079atagen2026-09-25 00:24 UTC347
            target: target.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC348
            key: key.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC349
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC350
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC351
    }
31ce2453c82fatagen2026-09-24 13:07 UTC352
31ce2453c82fatagen2026-09-24 13:07 UTC353
    pub async fn mark_read(
31ce2453c82fatagen2026-09-24 13:07 UTC354
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC355
        timeline_id: TimelineId,
31ce2453c82fatagen2026-09-24 13:07 UTC356
        event_id: OwnedEventId,
31ce2453c82fatagen2026-09-24 13:07 UTC357
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC358
        self.run(Command::Timeline(TimelineCommand::MarkRead {
31ce2453c82fatagen2026-09-24 13:07 UTC359
            timeline_id,
31ce2453c82fatagen2026-09-24 13:07 UTC360
            event_id,
31ce2453c82fatagen2026-09-24 13:07 UTC361
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC362
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC363
    }
31ce2453c82fatagen2026-09-24 13:07 UTC364
31ce2453c82fatagen2026-09-24 13:07 UTC365
    pub async fn set_typing(&self, room_id: OwnedRoomId, typing: bool) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC366
        self.run(Command::Room(RoomCommand::SetTyping { room_id, typing }))
96fdf90aacd6atagen2026-09-08 08:24 UTC367
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC368
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC369
38c4caecdb3datagen2026-09-26 13:35 UTC370
    pub async fn prepare_to_send(&self, room_id: OwnedRoomId) -> Result<(), Error> {
38c4caecdb3datagen2026-09-26 13:35 UTC371
        self.run(Command::Room(RoomCommand::PrepareToSend(room_id)))
38c4caecdb3datagen2026-09-26 13:35 UTC372
            .await
38c4caecdb3datagen2026-09-26 13:35 UTC373
    }
38c4caecdb3datagen2026-09-26 13:35 UTC374
31ce2453c82fatagen2026-09-24 13:07 UTC375
    pub async fn join_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC376
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC377
        room: OwnedRoomOrAliasId,
31ce2453c82fatagen2026-09-24 13:07 UTC378
        via: Vec<OwnedServerName>,
31ce2453c82fatagen2026-09-24 13:07 UTC379
    ) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC380
        self.run_for_room(RoomCommand::Join { room, via }).await
31ce2453c82fatagen2026-09-24 13:07 UTC381
    }
31ce2453c82fatagen2026-09-24 13:07 UTC382
31ce2453c82fatagen2026-09-24 13:07 UTC383
    pub async fn leave_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC384
        self.run(Command::Room(RoomCommand::Leave(room_id))).await
31ce2453c82fatagen2026-09-24 13:07 UTC385
    }
31ce2453c82fatagen2026-09-24 13:07 UTC386
31ce2453c82fatagen2026-09-24 13:07 UTC387
    pub async fn forget_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC388
        self.run(Command::Room(RoomCommand::Forget(room_id))).await
31ce2453c82fatagen2026-09-24 13:07 UTC389
    }
31ce2453c82fatagen2026-09-24 13:07 UTC390
31ce2453c82fatagen2026-09-24 13:07 UTC391
    pub async fn accept_invite(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC392
        self.run(Command::Room(RoomCommand::AcceptInvite(room_id)))
31ce2453c82fatagen2026-09-24 13:07 UTC393
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC394
    }
31ce2453c82fatagen2026-09-24 13:07 UTC395
31ce2453c82fatagen2026-09-24 13:07 UTC396
    pub async fn reject_invite(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC397
        self.run(Command::Room(RoomCommand::RejectInvite(room_id)))
96fdf90aacd6atagen2026-09-08 08:24 UTC398
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC399
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC400
96fdf90aacd6atagen2026-09-08 08:24 UTC401
    pub async fn invite_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC402
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC403
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC404
        user_id: OwnedUserId,
31ce2453c82fatagen2026-09-24 13:07 UTC405
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC406
        self.run(Command::Room(RoomCommand::InviteUser { room_id, user_id }))
31ce2453c82fatagen2026-09-24 13:07 UTC407
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC408
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC409
96fdf90aacd6atagen2026-09-08 08:24 UTC410
    pub async fn kick_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC411
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC412
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC413
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC414
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC415
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC416
        self.run(Command::Room(RoomCommand::KickUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC417
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC418
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC419
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC420
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC421
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC422
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC423
96fdf90aacd6atagen2026-09-08 08:24 UTC424
    pub async fn ban_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC425
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC426
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC427
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC428
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC429
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC430
        self.run(Command::Room(RoomCommand::BanUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC431
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC432
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC433
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC434
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC435
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC436
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC437
96fdf90aacd6atagen2026-09-08 08:24 UTC438
    pub async fn unban_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC439
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC440
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC441
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC442
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC443
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC444
        self.run(Command::Room(RoomCommand::UnbanUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC445
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC446
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC447
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC448
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC449
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC450
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC451
96fdf90aacd6atagen2026-09-08 08:24 UTC452
    pub async fn set_power_levels(
96fdf90aacd6atagen2026-09-08 08:24 UTC453
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC454
        room_id: OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC455
        changes: PowerLevelChanges,
31ce2453c82fatagen2026-09-24 13:07 UTC456
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC457
        self.run(Command::Room(RoomCommand::SetPowerLevels {
96fdf90aacd6atagen2026-09-08 08:24 UTC458
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC459
            changes,
96fdf90aacd6atagen2026-09-08 08:24 UTC460
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC461
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC462
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC463
96fdf90aacd6atagen2026-09-08 08:24 UTC464
    pub async fn set_user_power_level(
96fdf90aacd6atagen2026-09-08 08:24 UTC465
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC466
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC467
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC468
        level: i64,
31ce2453c82fatagen2026-09-24 13:07 UTC469
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC470
        self.run(Command::Room(RoomCommand::SetUserPowerLevel {
96fdf90aacd6atagen2026-09-08 08:24 UTC471
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC472
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC473
            level,
96fdf90aacd6atagen2026-09-08 08:24 UTC474
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC475
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC476
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC477
31ce2453c82fatagen2026-09-24 13:07 UTC478
    pub async fn create_room(&self, options: CreateRoomOptions) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC479
        self.run_for_room(RoomCommand::Create(options)).await
96fdf90aacd6atagen2026-09-08 08:24 UTC480
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC481
31ce2453c82fatagen2026-09-24 13:07 UTC482
    /// hands back the existing dm with them if there is one
31ce2453c82fatagen2026-09-24 13:07 UTC483
    pub async fn create_direct(&self, user_id: OwnedUserId) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC484
        self.run_for_room(RoomCommand::CreateDirect(user_id)).await
96fdf90aacd6atagen2026-09-08 08:24 UTC485
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC486
96fdf90aacd6atagen2026-09-08 08:24 UTC487
    pub async fn cancel_send(
96fdf90aacd6atagen2026-09-08 08:24 UTC488
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC489
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC490
        transaction_id: OwnedTransactionId,
31ce2453c82fatagen2026-09-24 13:07 UTC491
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC492
        self.run(Command::Room(RoomCommand::CancelSend {
96fdf90aacd6atagen2026-09-08 08:24 UTC493
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC494
            transaction_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC495
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC496
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC497
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC498
96fdf90aacd6atagen2026-09-08 08:24 UTC499
    pub async fn retry_send(
96fdf90aacd6atagen2026-09-08 08:24 UTC500
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC501
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC502
        transaction_id: OwnedTransactionId,
31ce2453c82fatagen2026-09-24 13:07 UTC503
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC504
        self.run(Command::Room(RoomCommand::RetrySend {
96fdf90aacd6atagen2026-09-08 08:24 UTC505
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC506
            transaction_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC507
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC508
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC509
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC510
31ce2453c82fatagen2026-09-24 13:07 UTC511
    pub async fn upload(&self, upload: AttachmentUpload) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC512
        self.run(Command::Media(MediaCommand::Upload(upload))).await
96fdf90aacd6atagen2026-09-08 08:24 UTC513
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC514
31ce2453c82fatagen2026-09-24 13:07 UTC515
    pub async fn recover(&self, recovery_key: impl Into<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC516
        self.run(Command::Encryption(EncryptionCommand::Recover(
31ce2453c82fatagen2026-09-24 13:07 UTC517
            recovery_key.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC518
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC519
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC520
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC521
31ce2453c82fatagen2026-09-24 13:07 UTC522
    pub async fn create_key_backup(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC523
        self.run(Command::Encryption(EncryptionCommand::CreateKeyBackup))
31ce2453c82fatagen2026-09-24 13:07 UTC524
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC525
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC526
31ce2453c82fatagen2026-09-24 13:07 UTC527
    pub async fn enable_key_backup(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC528
        self.run(Command::Encryption(EncryptionCommand::EnableKeyBackup))
31ce2453c82fatagen2026-09-24 13:07 UTC529
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC530
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC531
31ce2453c82fatagen2026-09-24 13:07 UTC532
    pub async fn disable_key_backup(&self, delete_from_server: bool) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC533
        self.run(Command::Encryption(EncryptionCommand::DisableKeyBackup {
31ce2453c82fatagen2026-09-24 13:07 UTC534
            delete_from_server,
31ce2453c82fatagen2026-09-24 13:07 UTC535
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC536
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC537
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC538
31ce2453c82fatagen2026-09-24 13:07 UTC539
    pub async fn recover_key_backup(&self, recovery_key: impl Into<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC540
        self.run(Command::Encryption(EncryptionCommand::RecoverKeyBackup(
31ce2453c82fatagen2026-09-24 13:07 UTC541
            recovery_key.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC542
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC543
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC544
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC545
31ce2453c82fatagen2026-09-24 13:07 UTC546
    pub async fn start_verification(&self, target: VerificationTarget) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC547
        self.run(Command::Encryption(EncryptionCommand::StartVerification(
31ce2453c82fatagen2026-09-24 13:07 UTC548
            target,
31ce2453c82fatagen2026-09-24 13:07 UTC549
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC550
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC551
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC552
31ce2453c82fatagen2026-09-24 13:07 UTC553
    pub async fn verify(&self, action: VerificationAction) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC554
        self.run(Command::Encryption(EncryptionCommand::Verify(action)))
31ce2453c82fatagen2026-09-24 13:07 UTC555
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC556
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC557
5d2974de5826atagen2026-10-08 11:29 UTC558
    /// bytes for an avatar, or for media a retained timeline showed you. concurrent asks share
5d2974de5826atagen2026-10-08 11:29 UTC559
    /// one download
31ce2453c82fatagen2026-09-24 13:07 UTC560
    pub async fn media(&self, media_id: &MediaId, size: MediaSize) -> Result<Media, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC561
        self.media.timeline_media(media_id, size).await
31ce2453c82fatagen2026-09-24 13:07 UTC562
    }
31ce2453c82fatagen2026-09-24 13:07 UTC563
5b21b919d1e6atagen2026-09-27 11:47 UTC564
    /// where `media` would fetch from, for a host streaming big files itself. the byte cap
5b21b919d1e6atagen2026-09-27 11:47 UTC565
    /// doesn't apply since nothing is buffered
5b21b919d1e6atagen2026-09-27 11:47 UTC566
    pub async fn media_source(
5b21b919d1e6atagen2026-09-27 11:47 UTC567
        &self,
5b21b919d1e6atagen2026-09-27 11:47 UTC568
        media_id: &MediaId,
5b21b919d1e6atagen2026-09-27 11:47 UTC569
        size: MediaSize,
5b21b919d1e6atagen2026-09-27 11:47 UTC570
    ) -> Result<MediaLocation, Error> {
5b21b919d1e6atagen2026-09-27 11:47 UTC571
        self.media.media_location(media_id, size).await
5b21b919d1e6atagen2026-09-27 11:47 UTC572
    }
5b21b919d1e6atagen2026-09-27 11:47 UTC573
31ce2453c82fatagen2026-09-24 13:07 UTC574
    /// the space graph builds on first use and then keeps itself current
31ce2453c82fatagen2026-09-24 13:07 UTC575
    async fn spaces(&self) -> &SpaceService {
31ce2453c82fatagen2026-09-24 13:07 UTC576
        self.spaces
31ce2453c82fatagen2026-09-24 13:07 UTC577
            .get_or_init(|| SpaceService::new(self.client.clone()))
31ce2453c82fatagen2026-09-24 13:07 UTC578
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC579
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC580
96fdf90aacd6atagen2026-09-08 08:24 UTC581
    pub async fn rooms(&self) -> Vec<RoomSummary> {
31ce2453c82fatagen2026-09-24 13:07 UTC582
        room_summaries(&self.client, self.spaces().await).await
96fdf90aacd6atagen2026-09-08 08:24 UTC583
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC584
31ce2453c82fatagen2026-09-24 13:07 UTC585
    /// browse a space the way the server sees it, rooms you haven't joined included
31ce2453c82fatagen2026-09-24 13:07 UTC586
    pub async fn space_hierarchy(&self, space_id: OwnedRoomId) -> SpaceHierarchy {
31ce2453c82fatagen2026-09-24 13:07 UTC587
        SpaceHierarchy(SpaceRoomList::new(self.client.clone(), space_id).await)
31ce2453c82fatagen2026-09-24 13:07 UTC588
    }
31ce2453c82fatagen2026-09-24 13:07 UTC589
31ce2453c82fatagen2026-09-24 13:07 UTC590
    pub async fn own_profile(&self) -> Result<Profile, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC591
        let user_id = self
31ce2453c82fatagen2026-09-24 13:07 UTC592
            .client
31ce2453c82fatagen2026-09-24 13:07 UTC593
            .user_id()
31ce2453c82fatagen2026-09-24 13:07 UTC594
            .ok_or_else(|| Error::new(ErrorKind::Unauthenticated, "the client is not logged in"))?
31ce2453c82fatagen2026-09-24 13:07 UTC595
            .to_owned();
31ce2453c82fatagen2026-09-24 13:07 UTC596
        let response = self
31ce2453c82fatagen2026-09-24 13:07 UTC597
            .client
31ce2453c82fatagen2026-09-24 13:07 UTC598
            .account()
31ce2453c82fatagen2026-09-24 13:07 UTC599
            .fetch_user_profile()
31ce2453c82fatagen2026-09-24 13:07 UTC600
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC601
            .map_err(|source| Error::from_sdk("fetching the profile failed", source))?;
31ce2453c82fatagen2026-09-24 13:07 UTC602
        profile(user_id, &response)
31ce2453c82fatagen2026-09-24 13:07 UTC603
    }
31ce2453c82fatagen2026-09-24 13:07 UTC604
31ce2453c82fatagen2026-09-24 13:07 UTC605
    pub async fn user_profile(&self, user_id: &UserId) -> Result<Profile, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC606
        let response = self
31ce2453c82fatagen2026-09-24 13:07 UTC607
            .client
31ce2453c82fatagen2026-09-24 13:07 UTC608
            .account()
31ce2453c82fatagen2026-09-24 13:07 UTC609
            .fetch_user_profile_of(user_id)
31ce2453c82fatagen2026-09-24 13:07 UTC610
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC611
            .map_err(|source| Error::from_sdk("fetching the profile failed", source))?;
31ce2453c82fatagen2026-09-24 13:07 UTC612
        profile(user_id.to_owned(), &response)
31ce2453c82fatagen2026-09-24 13:07 UTC613
    }
31ce2453c82fatagen2026-09-24 13:07 UTC614
31ce2453c82fatagen2026-09-24 13:07 UTC615
    pub async fn set_display_name(&self, name: Option<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC616
        self.run(Command::Account(AccountCommand::SetDisplayName(name)))
31ce2453c82fatagen2026-09-24 13:07 UTC617
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC618
    }
31ce2453c82fatagen2026-09-24 13:07 UTC619
31ce2453c82fatagen2026-09-24 13:07 UTC620
    pub async fn set_avatar(&self, avatar: Option<OwnedMxcUri>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC621
        self.run(Command::Account(AccountCommand::SetAvatar(avatar)))
31ce2453c82fatagen2026-09-24 13:07 UTC622
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC623
    }
31ce2453c82fatagen2026-09-24 13:07 UTC624
31ce2453c82fatagen2026-09-24 13:07 UTC625
    pub async fn upload_avatar(
31ce2453c82fatagen2026-09-24 13:07 UTC626
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC627
        mimetype: impl Into<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC628
        bytes: Vec<u8>,
31ce2453c82fatagen2026-09-24 13:07 UTC629
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC630
        self.run(Command::Account(AccountCommand::UploadAvatar {
31ce2453c82fatagen2026-09-24 13:07 UTC631
            mimetype: mimetype.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC632
            bytes,
31ce2453c82fatagen2026-09-24 13:07 UTC633
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC634
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC635
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC636
31ce2453c82fatagen2026-09-24 13:07 UTC637
    pub async fn rooms_filtered(&self, filter: &RoomListFilter) -> Vec<RoomSummary> {
31ce2453c82fatagen2026-09-24 13:07 UTC638
        let matcher = filter.matcher();
96fdf90aacd6atagen2026-09-08 08:24 UTC639
        self.rooms()
96fdf90aacd6atagen2026-09-08 08:24 UTC640
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC641
            .into_iter()
31ce2453c82fatagen2026-09-24 13:07 UTC642
            .filter(|room| matcher.matches(room))
96fdf90aacd6atagen2026-09-08 08:24 UTC643
            .collect()
96fdf90aacd6atagen2026-09-08 08:24 UTC644
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC645
31ce2453c82fatagen2026-09-24 13:07 UTC646
    pub async fn devices(&self) -> Result<Vec<OwnDevice>, Error> {
96fdf90aacd6atagen2026-09-08 08:24 UTC647
        let current_device_id = self.client.device_id();
96fdf90aacd6atagen2026-09-08 08:24 UTC648
        Ok(self
96fdf90aacd6atagen2026-09-08 08:24 UTC649
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC650
            .devices()
96fdf90aacd6atagen2026-09-08 08:24 UTC651
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC652
            .map_err(|source| Error::from_http("listing devices failed", source))?
96fdf90aacd6atagen2026-09-08 08:24 UTC653
            .devices
96fdf90aacd6atagen2026-09-08 08:24 UTC654
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC655
            .map(|device| OwnDevice {
96fdf90aacd6atagen2026-09-08 08:24 UTC656
                current: current_device_id == Some(device.device_id.as_ref()),
96fdf90aacd6atagen2026-09-08 08:24 UTC657
                device_id: device.device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC658
                display_name: device.display_name,
96fdf90aacd6atagen2026-09-08 08:24 UTC659
                last_seen_ip: device.last_seen_ip,
96fdf90aacd6atagen2026-09-08 08:24 UTC660
                last_seen_timestamp_ms: device.last_seen_ts.map(|timestamp| timestamp.get().into()),
96fdf90aacd6atagen2026-09-08 08:24 UTC661
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC662
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC663
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC664
31ce2453c82fatagen2026-09-24 13:07 UTC665
    fn room(&self, room_id: &RoomId) -> Result<matrix_sdk::Room, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC666
        self.client
31ce2453c82fatagen2026-09-24 13:07 UTC667
            .get_room(room_id)
31ce2453c82fatagen2026-09-24 13:07 UTC668
            .ok_or_else(Error::room_unknown)
31ce2453c82fatagen2026-09-24 13:07 UTC669
    }
31ce2453c82fatagen2026-09-24 13:07 UTC670
96fdf90aacd6atagen2026-09-08 08:24 UTC671
    pub async fn room_notification_settings(
96fdf90aacd6atagen2026-09-08 08:24 UTC672
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC673
        room_id: &RoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC674
    ) -> Result<Option<RoomNotificationSettings>, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC675
        let room = self.room(room_id)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC676
        let custom = room.user_defined_notification_mode().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC677
        let mode = match custom {
96fdf90aacd6atagen2026-09-08 08:24 UTC678
            Some(mode) => mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC679
            None => match room.notification_mode().await {
96fdf90aacd6atagen2026-09-08 08:24 UTC680
                Some(mode) => mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC681
                None => return Ok(None),
96fdf90aacd6atagen2026-09-08 08:24 UTC682
            },
96fdf90aacd6atagen2026-09-08 08:24 UTC683
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC684
        Ok(Some(RoomNotificationSettings {
96fdf90aacd6atagen2026-09-08 08:24 UTC685
            mode: crate::normalise::notification_mode(mode),
96fdf90aacd6atagen2026-09-08 08:24 UTC686
            custom: custom.is_some(),
96fdf90aacd6atagen2026-09-08 08:24 UTC687
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC688
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC689
96fdf90aacd6atagen2026-09-08 08:24 UTC690
    pub async fn notification_keywords(&self) -> Vec<String> {
96fdf90aacd6atagen2026-09-08 08:24 UTC691
        self.client
96fdf90aacd6atagen2026-09-08 08:24 UTC692
            .notification_settings()
96fdf90aacd6atagen2026-09-08 08:24 UTC693
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC694
            .enabled_keywords()
96fdf90aacd6atagen2026-09-08 08:24 UTC695
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC696
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC697
            .collect()
96fdf90aacd6atagen2026-09-08 08:24 UTC698
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC699
96fdf90aacd6atagen2026-09-08 08:24 UTC700
    pub async fn resolve_push_notification(
96fdf90aacd6atagen2026-09-08 08:24 UTC701
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC702
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC703
        event_id: &EventId,
31ce2453c82fatagen2026-09-24 13:07 UTC704
    ) -> Result<PushNotificationStatus, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC705
        let notification_failed = |source| {
31ce2453c82fatagen2026-09-24 13:07 UTC706
            Error::with_source(
31ce2453c82fatagen2026-09-24 13:07 UTC707
                ErrorKind::Other,
31ce2453c82fatagen2026-09-24 13:07 UTC708
                "resolving the push notification failed",
31ce2453c82fatagen2026-09-24 13:07 UTC709
                source,
31ce2453c82fatagen2026-09-24 13:07 UTC710
            )
31ce2453c82fatagen2026-09-24 13:07 UTC711
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC712
        let client = self
96fdf90aacd6atagen2026-09-08 08:24 UTC713
            .notification_client
96fdf90aacd6atagen2026-09-08 08:24 UTC714
            .get_or_try_init(|| async {
96fdf90aacd6atagen2026-09-08 08:24 UTC715
                NotificationClient::new(
96fdf90aacd6atagen2026-09-08 08:24 UTC716
                    self.client.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC717
                    NotificationProcessSetup::SingleProcess {
96fdf90aacd6atagen2026-09-08 08:24 UTC718
                        sync_service: self.sync_service.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC719
                    },
96fdf90aacd6atagen2026-09-08 08:24 UTC720
                )
96fdf90aacd6atagen2026-09-08 08:24 UTC721
                .await
96fdf90aacd6atagen2026-09-08 08:24 UTC722
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC723
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC724
            .map_err(notification_failed)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC725
        let status = client
96fdf90aacd6atagen2026-09-08 08:24 UTC726
            .get_notification(room_id, event_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC727
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC728
            .map_err(notification_failed)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC729
        Ok(normalise_push_notification(room_id, event_id, status))
96fdf90aacd6atagen2026-09-08 08:24 UTC730
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC731
96fdf90aacd6atagen2026-09-08 08:24 UTC732
    pub async fn members(
96fdf90aacd6atagen2026-09-08 08:24 UTC733
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC734
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC735
        filter: MemberFilter,
31ce2453c82fatagen2026-09-24 13:07 UTC736
    ) -> Result<Vec<MemberSummary>, Error> {
96fdf90aacd6atagen2026-09-08 08:24 UTC737
        let memberships = match filter {
96fdf90aacd6atagen2026-09-08 08:24 UTC738
            MemberFilter::Active => RoomMemberships::ACTIVE,
96fdf90aacd6atagen2026-09-08 08:24 UTC739
            MemberFilter::Joined => RoomMemberships::JOIN,
96fdf90aacd6atagen2026-09-08 08:24 UTC740
            MemberFilter::Invited => RoomMemberships::INVITE,
5a52012c9b1datagen2026-09-24 23:45 UTC741
            MemberFilter::Banned => RoomMemberships::BAN,
5a52012c9b1datagen2026-09-24 23:45 UTC742
            MemberFilter::Left => RoomMemberships::LEAVE,
96fdf90aacd6atagen2026-09-08 08:24 UTC743
            // An empty mask is the SDK's unfiltered wildcard: it matches every
96fdf90aacd6atagen2026-09-08 08:24 UTC744
            // membership, including custom states that `all()` would exclude.
96fdf90aacd6atagen2026-09-08 08:24 UTC745
            MemberFilter::All => RoomMemberships::empty(),
96fdf90aacd6atagen2026-09-08 08:24 UTC746
        };
31ce2453c82fatagen2026-09-24 13:07 UTC747
        Ok(self
31ce2453c82fatagen2026-09-24 13:07 UTC748
            .room(room_id)?
96fdf90aacd6atagen2026-09-08 08:24 UTC749
            .members(memberships)
96fdf90aacd6atagen2026-09-08 08:24 UTC750
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC751
            .map_err(|source| Error::from_sdk("listing members failed", source))?
96fdf90aacd6atagen2026-09-08 08:24 UTC752
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC753
            .map(member_summary)
96fdf90aacd6atagen2026-09-08 08:24 UTC754
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC755
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC756
31ce2453c82fatagen2026-09-24 13:07 UTC757
    pub async fn room_power_levels(&self, room_id: &RoomId) -> Result<RoomPowerLevels, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC758
        let levels = self
31ce2453c82fatagen2026-09-24 13:07 UTC759
            .room(room_id)?
96fdf90aacd6atagen2026-09-08 08:24 UTC760
            .power_levels()
96fdf90aacd6atagen2026-09-08 08:24 UTC761
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC762
            .map_err(|source| Error::from_sdk("reading power levels failed", source.into()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC763
        Ok(RoomPowerLevels {
96fdf90aacd6atagen2026-09-08 08:24 UTC764
            ban: levels.ban.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC765
            invite: levels.invite.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC766
            kick: levels.kick.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC767
            redact: levels.redact.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC768
            events_default: levels.events_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC769
            state_default: levels.state_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC770
            users_default: levels.users_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC771
            room_notification: levels.notifications.room.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC772
            users: levels
96fdf90aacd6atagen2026-09-08 08:24 UTC773
                .users
96fdf90aacd6atagen2026-09-08 08:24 UTC774
                .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC775
                .map(|(user_id, level)| (user_id, level.into()))
96fdf90aacd6atagen2026-09-08 08:24 UTC776
                .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC777
            events: levels
96fdf90aacd6atagen2026-09-08 08:24 UTC778
                .events
96fdf90aacd6atagen2026-09-08 08:24 UTC779
                .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC780
                .map(|(event_type, level)| (event_type.to_string(), level.into()))
96fdf90aacd6atagen2026-09-08 08:24 UTC781
                .collect(),
5a52012c9b1datagen2026-09-24 23:45 UTC782
            creators: levels
5a52012c9b1datagen2026-09-24 23:45 UTC783
                .rules
5a52012c9b1datagen2026-09-24 23:45 UTC784
                .privileged_creators
5a52012c9b1datagen2026-09-24 23:45 UTC785
                .into_iter()
5a52012c9b1datagen2026-09-24 23:45 UTC786
                .flatten()
5a52012c9b1datagen2026-09-24 23:45 UTC787
                .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC788
        })
96fdf90aacd6atagen2026-09-08 08:24 UTC789
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC790
96fdf90aacd6atagen2026-09-08 08:24 UTC791
    pub async fn pending_send_ids(
96fdf90aacd6atagen2026-09-08 08:24 UTC792
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC793
        room_id: &RoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC794
    ) -> Result<Vec<OwnedTransactionId>, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC795
        let (echoes, _) = self
31ce2453c82fatagen2026-09-24 13:07 UTC796
            .room(room_id)?
96fdf90aacd6atagen2026-09-08 08:24 UTC797
            .send_queue()
96fdf90aacd6atagen2026-09-08 08:24 UTC798
            .subscribe()
96fdf90aacd6atagen2026-09-08 08:24 UTC799
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC800
            .map_err(|source| {
31ce2453c82fatagen2026-09-24 13:07 UTC801
                Error::with_source(ErrorKind::Store, "reading the send queue failed", source)
31ce2453c82fatagen2026-09-24 13:07 UTC802
            })?;
96fdf90aacd6atagen2026-09-08 08:24 UTC803
        Ok(echoes
96fdf90aacd6atagen2026-09-08 08:24 UTC804
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC805
            .filter(|echo| {
96fdf90aacd6atagen2026-09-08 08:24 UTC806
                matches!(
96fdf90aacd6atagen2026-09-08 08:24 UTC807
                    echo.content,
96fdf90aacd6atagen2026-09-08 08:24 UTC808
                    matrix_sdk::send_queue::LocalEchoContent::Event { .. }
96fdf90aacd6atagen2026-09-08 08:24 UTC809
                )
96fdf90aacd6atagen2026-09-08 08:24 UTC810
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC811
            .map(|echo| echo.transaction_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC812
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC813
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC814
96fdf90aacd6atagen2026-09-08 08:24 UTC815
    pub async fn global_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC816
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC817
        event_type: GlobalAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC818
    ) -> Result<Option<Raw<AnyGlobalAccountDataEventContent>>, Error> {
96fdf90aacd6atagen2026-09-08 08:24 UTC819
        self.client
96fdf90aacd6atagen2026-09-08 08:24 UTC820
            .account()
96fdf90aacd6atagen2026-09-08 08:24 UTC821
            .account_data_raw(event_type)
96fdf90aacd6atagen2026-09-08 08:24 UTC822
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC823
            .map_err(|source| Error::from_sdk("reading account data failed", source))
96fdf90aacd6atagen2026-09-08 08:24 UTC824
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC825
96fdf90aacd6atagen2026-09-08 08:24 UTC826
    pub async fn room_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC827
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC828
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC829
        event_type: RoomAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC830
    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC831
        self.room(room_id)?
31ce2453c82fatagen2026-09-24 13:07 UTC832
            .account_data(event_type)
96fdf90aacd6atagen2026-09-08 08:24 UTC833
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC834
            .map_err(|source| Error::from_sdk("reading room account data failed", source))
96fdf90aacd6atagen2026-09-08 08:24 UTC835
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC836
96fdf90aacd6atagen2026-09-08 08:24 UTC837
    #[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC838
    pub fn connection_state(&self) -> watch::Receiver<ConnectionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC839
        self.connection.clone()
96fdf90aacd6atagen2026-09-08 08:24 UTC840
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC841
96fdf90aacd6atagen2026-09-08 08:24 UTC842
    #[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC843
    pub fn encryption_state(&self) -> Option<EncryptionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC844
        let device_id = self.client.device_id()?.to_owned();
96fdf90aacd6atagen2026-09-08 08:24 UTC845
        let encryption = self.client.encryption();
96fdf90aacd6atagen2026-09-08 08:24 UTC846
        Some(encryption_state(
96fdf90aacd6atagen2026-09-08 08:24 UTC847
            device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC848
            encryption.recovery().state(),
96fdf90aacd6atagen2026-09-08 08:24 UTC849
            encryption.verification_state().get(),
96fdf90aacd6atagen2026-09-08 08:24 UTC850
            encryption.backups().state(),
96fdf90aacd6atagen2026-09-08 08:24 UTC851
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC852
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC853
}
96fdf90aacd6atagen2026-09-08 08:24 UTC854
31ce2453c82fatagen2026-09-24 13:07 UTC855
/// one space's hierarchy, a page at a time. hold on to it while you browse, it remembers where it got to
31ce2453c82fatagen2026-09-24 13:07 UTC856
pub struct SpaceHierarchy(SpaceRoomList);
31ce2453c82fatagen2026-09-24 13:07 UTC857
31ce2453c82fatagen2026-09-24 13:07 UTC858
impl fmt::Debug for SpaceHierarchy {
31ce2453c82fatagen2026-09-24 13:07 UTC859
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31ce2453c82fatagen2026-09-24 13:07 UTC860
        formatter
31ce2453c82fatagen2026-09-24 13:07 UTC861
            .debug_struct("SpaceHierarchy")
31ce2453c82fatagen2026-09-24 13:07 UTC862
            .finish_non_exhaustive()
31ce2453c82fatagen2026-09-24 13:07 UTC863
    }
31ce2453c82fatagen2026-09-24 13:07 UTC864
}
31ce2453c82fatagen2026-09-24 13:07 UTC865
31ce2453c82fatagen2026-09-24 13:07 UTC866
impl SpaceHierarchy {
31ce2453c82fatagen2026-09-24 13:07 UTC867
    /// fetches the next page. a no-op once the end is reached or while a page is in flight
31ce2453c82fatagen2026-09-24 13:07 UTC868
    pub async fn paginate(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC869
        self.0.paginate().await.map_err(|source| {
31ce2453c82fatagen2026-09-24 13:07 UTC870
            Error::with_source(
31ce2453c82fatagen2026-09-24 13:07 UTC871
                ErrorKind::Server,
31ce2453c82fatagen2026-09-24 13:07 UTC872
                "fetching the space hierarchy failed",
31ce2453c82fatagen2026-09-24 13:07 UTC873
                source,
31ce2453c82fatagen2026-09-24 13:07 UTC874
            )
31ce2453c82fatagen2026-09-24 13:07 UTC875
        })
31ce2453c82fatagen2026-09-24 13:07 UTC876
    }
31ce2453c82fatagen2026-09-24 13:07 UTC877
31ce2453c82fatagen2026-09-24 13:07 UTC878
    /// everything fetched so far, the space itself excluded
31ce2453c82fatagen2026-09-24 13:07 UTC879
    pub async fn rooms(&self) -> Vec<SpaceChild> {
31ce2453c82fatagen2026-09-24 13:07 UTC880
        self.0.rooms().await.into_iter().map(space_child).collect()
31ce2453c82fatagen2026-09-24 13:07 UTC881
    }
31ce2453c82fatagen2026-09-24 13:07 UTC882
31ce2453c82fatagen2026-09-24 13:07 UTC883
    #[must_use]
31ce2453c82fatagen2026-09-24 13:07 UTC884
    pub fn end_reached(&self) -> bool {
31ce2453c82fatagen2026-09-24 13:07 UTC885
        matches!(
31ce2453c82fatagen2026-09-24 13:07 UTC886
            self.0.pagination_state(),
31ce2453c82fatagen2026-09-24 13:07 UTC887
            SpaceRoomListPaginationState::Idle { end_reached: true }
31ce2453c82fatagen2026-09-24 13:07 UTC888
        )
31ce2453c82fatagen2026-09-24 13:07 UTC889
    }
31ce2453c82fatagen2026-09-24 13:07 UTC890
}
31ce2453c82fatagen2026-09-24 13:07 UTC891
31ce2453c82fatagen2026-09-24 13:07 UTC892
fn profile(
31ce2453c82fatagen2026-09-24 13:07 UTC893
    user_id: OwnedUserId,
31ce2453c82fatagen2026-09-24 13:07 UTC894
    response: &ruma::api::client::profile::get_profile::v3::Response,
31ce2453c82fatagen2026-09-24 13:07 UTC895
) -> Result<Profile, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC896
    use ruma::api::client::profile::{AvatarUrl, DisplayName};
31ce2453c82fatagen2026-09-24 13:07 UTC897
    let malformed = |source| {
31ce2453c82fatagen2026-09-24 13:07 UTC898
        Error::with_source(
31ce2453c82fatagen2026-09-24 13:07 UTC899
            ErrorKind::Server,
31ce2453c82fatagen2026-09-24 13:07 UTC900
            "the server sent a malformed profile",
31ce2453c82fatagen2026-09-24 13:07 UTC901
            source,
31ce2453c82fatagen2026-09-24 13:07 UTC902
        )
31ce2453c82fatagen2026-09-24 13:07 UTC903
    };
31ce2453c82fatagen2026-09-24 13:07 UTC904
    Ok(Profile {
31ce2453c82fatagen2026-09-24 13:07 UTC905
        user_id,
31ce2453c82fatagen2026-09-24 13:07 UTC906
        display_name: response.get_static::<DisplayName>().map_err(malformed)?,
5d2974de5826atagen2026-10-08 11:29 UTC907
        avatar: response
5d2974de5826atagen2026-10-08 11:29 UTC908
            .get_static::<AvatarUrl>()
5d2974de5826atagen2026-10-08 11:29 UTC909
            .map_err(malformed)?
5d2974de5826atagen2026-10-08 11:29 UTC910
            .as_deref()
5d2974de5826atagen2026-10-08 11:29 UTC911
            .map(MediaId::plain),
31ce2453c82fatagen2026-09-24 13:07 UTC912
    })
31ce2453c82fatagen2026-09-24 13:07 UTC913
}
31ce2453c82fatagen2026-09-24 13:07 UTC914
31ce2453c82fatagen2026-09-24 13:07 UTC915
#[derive(Debug)]
31ce2453c82fatagen2026-09-24 13:07 UTC916
pub(crate) struct Request {
96fdf90aacd6atagen2026-09-08 08:24 UTC917
    pub(crate) command: Command,
31ce2453c82fatagen2026-09-24 13:07 UTC918
    pub(crate) reply: Responder,
31ce2453c82fatagen2026-09-24 13:07 UTC919
}
31ce2453c82fatagen2026-09-24 13:07 UTC920
31ce2453c82fatagen2026-09-24 13:07 UTC921
impl Request {
31ce2453c82fatagen2026-09-24 13:07 UTC922
    fn new(command: Command) -> (Self, Pending) {
31ce2453c82fatagen2026-09-24 13:07 UTC923
        let (reply, pending) = oneshot::channel();
31ce2453c82fatagen2026-09-24 13:07 UTC924
        (
31ce2453c82fatagen2026-09-24 13:07 UTC925
            Self {
31ce2453c82fatagen2026-09-24 13:07 UTC926
                command,
31ce2453c82fatagen2026-09-24 13:07 UTC927
                reply: Responder(reply),
31ce2453c82fatagen2026-09-24 13:07 UTC928
            },
31ce2453c82fatagen2026-09-24 13:07 UTC929
            Pending(pending),
31ce2453c82fatagen2026-09-24 13:07 UTC930
        )
31ce2453c82fatagen2026-09-24 13:07 UTC931
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC932
}
96fdf90aacd6atagen2026-09-08 08:24 UTC933
31ce2453c82fatagen2026-09-24 13:07 UTC934
/// whoever holds this owes the caller an answer. dropping it answers `Interrupted`
96fdf90aacd6atagen2026-09-08 08:24 UTC935
#[derive(Debug)]
31ce2453c82fatagen2026-09-24 13:07 UTC936
pub(crate) struct Responder(oneshot::Sender<Result<CommandOutput, Error>>);
31ce2453c82fatagen2026-09-24 13:07 UTC937
31ce2453c82fatagen2026-09-24 13:07 UTC938
impl Responder {
31ce2453c82fatagen2026-09-24 13:07 UTC939
    pub(crate) fn send(self, result: Result<CommandOutput, Error>) {
31ce2453c82fatagen2026-09-24 13:07 UTC940
        if let Err(error) = &result {
31ce2453c82fatagen2026-09-24 13:07 UTC941
            tracing::debug!(%error, kind = ?error.kind, "command failed");
31ce2453c82fatagen2026-09-24 13:07 UTC942
        }
31ce2453c82fatagen2026-09-24 13:07 UTC943
        let _ = self.0.send(result);
31ce2453c82fatagen2026-09-24 13:07 UTC944
    }
31ce2453c82fatagen2026-09-24 13:07 UTC945
31ce2453c82fatagen2026-09-24 13:07 UTC946
    pub(crate) fn done(self, result: Result<(), Error>) {
31ce2453c82fatagen2026-09-24 13:07 UTC947
        self.send(result.map(|()| CommandOutput::Done));
31ce2453c82fatagen2026-09-24 13:07 UTC948
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC949
}
96fdf90aacd6atagen2026-09-08 08:24 UTC950
96fdf90aacd6atagen2026-09-08 08:24 UTC951
#[derive(Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC952
pub struct EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC953
    events: mpsc::Receiver<Event>,
96fdf90aacd6atagen2026-09-08 08:24 UTC954
}
96fdf90aacd6atagen2026-09-08 08:24 UTC955
96fdf90aacd6atagen2026-09-08 08:24 UTC956
impl EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC957
    pub async fn recv(&mut self) -> Option<Event> {
96fdf90aacd6atagen2026-09-08 08:24 UTC958
        self.events.recv().await
96fdf90aacd6atagen2026-09-08 08:24 UTC959
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC960
96fdf90aacd6atagen2026-09-08 08:24 UTC961
    pub fn try_recv(&mut self) -> Result<Event, mpsc::error::TryRecvError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC962
        self.events.try_recv()
96fdf90aacd6atagen2026-09-08 08:24 UTC963
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC964
}
96fdf90aacd6atagen2026-09-08 08:24 UTC965
96fdf90aacd6atagen2026-09-08 08:24 UTC966
impl futures_util::Stream for EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC967
    type Item = Event;
96fdf90aacd6atagen2026-09-08 08:24 UTC968
96fdf90aacd6atagen2026-09-08 08:24 UTC969
    fn poll_next(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
96fdf90aacd6atagen2026-09-08 08:24 UTC970
        self.events.poll_recv(context)
96fdf90aacd6atagen2026-09-08 08:24 UTC971
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC972
}
96fdf90aacd6atagen2026-09-08 08:24 UTC973
96fdf90aacd6atagen2026-09-08 08:24 UTC974
#[derive(Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC975
pub(crate) struct DriverPort {
31ce2453c82fatagen2026-09-24 13:07 UTC976
    requests: mpsc::Receiver<Request>,
96fdf90aacd6atagen2026-09-08 08:24 UTC977
    events: mpsc::Sender<Event>,
96fdf90aacd6atagen2026-09-08 08:24 UTC978
    connection: watch::Sender<ConnectionState>,
96fdf90aacd6atagen2026-09-08 08:24 UTC979
}
96fdf90aacd6atagen2026-09-08 08:24 UTC980
96fdf90aacd6atagen2026-09-08 08:24 UTC981
#[derive(Clone, Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC982
pub(crate) struct EventSender(mpsc::Sender<Event>);
96fdf90aacd6atagen2026-09-08 08:24 UTC983
96fdf90aacd6atagen2026-09-08 08:24 UTC984
impl EventSender {
96fdf90aacd6atagen2026-09-08 08:24 UTC985
    pub(crate) async fn send(&self, event: Event) -> Result<(), SendEventError> {
31ce2453c82fatagen2026-09-24 13:07 UTC986
        self.0.send(event).await.map_err(|_| SendEventError)
96fdf90aacd6atagen2026-09-08 08:24 UTC987
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC988
31ce2453c82fatagen2026-09-24 13:07 UTC989
    /// resolves once every `EventStream` is gone
96fdf90aacd6atagen2026-09-08 08:24 UTC990
    pub(crate) async fn closed(&self) {
96fdf90aacd6atagen2026-09-08 08:24 UTC991
        self.0.closed().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC992
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC993
}
96fdf90aacd6atagen2026-09-08 08:24 UTC994
96fdf90aacd6atagen2026-09-08 08:24 UTC995
impl DriverPort {
96fdf90aacd6atagen2026-09-08 08:24 UTC996
    pub(crate) fn event_sender(&self) -> EventSender {
96fdf90aacd6atagen2026-09-08 08:24 UTC997
        EventSender(self.events.clone())
96fdf90aacd6atagen2026-09-08 08:24 UTC998
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC999
96fdf90aacd6atagen2026-09-08 08:24 UTC1000
    pub(crate) fn connection_sender(&self) -> watch::Sender<ConnectionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1001
        self.connection.clone()
96fdf90aacd6atagen2026-09-08 08:24 UTC1002
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1003
31ce2453c82fatagen2026-09-24 13:07 UTC1004
    pub(crate) async fn recv(&mut self) -> Option<Request> {
31ce2453c82fatagen2026-09-24 13:07 UTC1005
        self.requests.recv().await
96fdf90aacd6atagen2026-09-08 08:24 UTC1006
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1007
5a52012c9b1datagen2026-09-24 23:45 UTC1008
    pub(crate) fn try_recv(&mut self) -> Option<Request> {
5a52012c9b1datagen2026-09-24 23:45 UTC1009
        self.requests.try_recv().ok()
5a52012c9b1datagen2026-09-24 23:45 UTC1010
    }
5a52012c9b1datagen2026-09-24 23:45 UTC1011
31ce2453c82fatagen2026-09-24 13:07 UTC1012
    pub(crate) fn close(&mut self) {
31ce2453c82fatagen2026-09-24 13:07 UTC1013
        self.requests.close();
96fdf90aacd6atagen2026-09-08 08:24 UTC1014
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1015
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1016
31ce2453c82fatagen2026-09-24 13:07 UTC1017
#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
31ce2453c82fatagen2026-09-24 13:07 UTC1018
#[error("the event receiver has closed")]
31ce2453c82fatagen2026-09-24 13:07 UTC1019
pub(crate) struct SendEventError;
96fdf90aacd6atagen2026-09-08 08:24 UTC1020
96fdf90aacd6atagen2026-09-08 08:24 UTC1021
#[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC1022
pub(crate) fn transport_pair(
96fdf90aacd6atagen2026-09-08 08:24 UTC1023
    client: Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC1024
    sync_service: Arc<SyncService>,
31ce2453c82fatagen2026-09-24 13:07 UTC1025
    media: Arc<MediaService>,
a250c7fa43fbatagen2026-09-26 13:35 UTC1026
    store_lock: Option<Arc<StoreLock>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC1027
    command_capacity: usize,
96fdf90aacd6atagen2026-09-08 08:24 UTC1028
    event_capacity: usize,
96fdf90aacd6atagen2026-09-08 08:24 UTC1029
) -> (ClientHandle, DriverPort, EventStream) {
31ce2453c82fatagen2026-09-24 13:07 UTC1030
    let (request_tx, request_rx) = mpsc::channel(command_capacity);
96fdf90aacd6atagen2026-09-08 08:24 UTC1031
    let (event_tx, event_rx) = mpsc::channel(event_capacity);
96fdf90aacd6atagen2026-09-08 08:24 UTC1032
    let (connection_tx, connection_rx) = watch::channel(ConnectionState::Idle);
96fdf90aacd6atagen2026-09-08 08:24 UTC1033
    (
96fdf90aacd6atagen2026-09-08 08:24 UTC1034
        ClientHandle {
31ce2453c82fatagen2026-09-24 13:07 UTC1035
            requests: request_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1036
            client,
96fdf90aacd6atagen2026-09-08 08:24 UTC1037
            connection: connection_rx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1038
            notification_client: Arc::new(OnceCell::new()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1039
            sync_service,
31ce2453c82fatagen2026-09-24 13:07 UTC1040
            media,
31ce2453c82fatagen2026-09-24 13:07 UTC1041
            spaces: Arc::new(OnceCell::new()),
a250c7fa43fbatagen2026-09-26 13:35 UTC1042
            _store_lock: store_lock,
96fdf90aacd6atagen2026-09-08 08:24 UTC1043
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC1044
        DriverPort {
31ce2453c82fatagen2026-09-24 13:07 UTC1045
            requests: request_rx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1046
            events: event_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1047
            connection: connection_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1048
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC1049
        EventStream { events: event_rx },
96fdf90aacd6atagen2026-09-08 08:24 UTC1050
    )
96fdf90aacd6atagen2026-09-08 08:24 UTC1051
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1052
96fdf90aacd6atagen2026-09-08 08:24 UTC1053
fn normalise_push_notification(
96fdf90aacd6atagen2026-09-08 08:24 UTC1054
    room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC1055
    event_id: &EventId,
96fdf90aacd6atagen2026-09-08 08:24 UTC1056
    status: NotificationStatus,
96fdf90aacd6atagen2026-09-08 08:24 UTC1057
) -> PushNotificationStatus {
96fdf90aacd6atagen2026-09-08 08:24 UTC1058
    match status {
96fdf90aacd6atagen2026-09-08 08:24 UTC1059
        NotificationStatus::Event(item) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC1060
            let event = match &item.raw_event {
96fdf90aacd6atagen2026-09-08 08:24 UTC1061
                RawNotificationEvent::Timeline(event) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC1062
                    PushNotificationEvent::Timeline(event.clone())
96fdf90aacd6atagen2026-09-08 08:24 UTC1063
                }
96fdf90aacd6atagen2026-09-08 08:24 UTC1064
                RawNotificationEvent::Invite(event) => PushNotificationEvent::Invite(event.clone()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1065
            };
96fdf90aacd6atagen2026-09-08 08:24 UTC1066
            PushNotificationStatus::Event(Box::new(PushNotification {
96fdf90aacd6atagen2026-09-08 08:24 UTC1067
                event_id: event_id.to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1068
                event,
96fdf90aacd6atagen2026-09-08 08:24 UTC1069
                sender: PushNotificationSender {
96fdf90aacd6atagen2026-09-08 08:24 UTC1070
                    user_id: item.event.sender().to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1071
                    display_name: item.sender_display_name,
5d2974de5826atagen2026-10-08 11:29 UTC1072
                    avatar_url: item.sender_avatar_url.as_deref().map(MediaId::plain),
96fdf90aacd6atagen2026-09-08 08:24 UTC1073
                    name_ambiguous: item.is_sender_name_ambiguous,
96fdf90aacd6atagen2026-09-08 08:24 UTC1074
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC1075
                room: PushNotificationRoom {
96fdf90aacd6atagen2026-09-08 08:24 UTC1076
                    room_id: room_id.to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1077
                    name: item.room_computed_display_name,
5d2974de5826atagen2026-10-08 11:29 UTC1078
                    avatar_url: item.room_avatar_url.as_deref().map(MediaId::plain),
96fdf90aacd6atagen2026-09-08 08:24 UTC1079
                    canonical_alias: item
96fdf90aacd6atagen2026-09-08 08:24 UTC1080
                        .room_canonical_alias
96fdf90aacd6atagen2026-09-08 08:24 UTC1081
                        .as_deref()
96fdf90aacd6atagen2026-09-08 08:24 UTC1082
                        .and_then(|alias| alias.parse().ok()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1083
                    topic: item.room_topic,
96fdf90aacd6atagen2026-09-08 08:24 UTC1084
                    encrypted: item.is_room_encrypted,
96fdf90aacd6atagen2026-09-08 08:24 UTC1085
                    direct: item.room_is_dm,
96fdf90aacd6atagen2026-09-08 08:24 UTC1086
                    joined_members_count: item.joined_members_count,
96fdf90aacd6atagen2026-09-08 08:24 UTC1087
                    service_members: item
96fdf90aacd6atagen2026-09-08 08:24 UTC1088
                        .service_members
96fdf90aacd6atagen2026-09-08 08:24 UTC1089
                        .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC1090
                        .filter_map(|user_id| user_id.parse().ok())
96fdf90aacd6atagen2026-09-08 08:24 UTC1091
                        .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1092
                    active_service_members_count: item.active_service_members_count,
96fdf90aacd6atagen2026-09-08 08:24 UTC1093
                    space: item.is_space,
96fdf90aacd6atagen2026-09-08 08:24 UTC1094
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC1095
                noisy: item.is_noisy,
96fdf90aacd6atagen2026-09-08 08:24 UTC1096
                has_mention: item.has_mention,
96fdf90aacd6atagen2026-09-08 08:24 UTC1097
                thread_id: item.thread_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC1098
            }))
96fdf90aacd6atagen2026-09-08 08:24 UTC1099
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC1100
        NotificationStatus::EventNotFound => PushNotificationStatus::NotFound,
96fdf90aacd6atagen2026-09-08 08:24 UTC1101
        NotificationStatus::EventFilteredOut => PushNotificationStatus::FilteredOut,
96fdf90aacd6atagen2026-09-08 08:24 UTC1102
        NotificationStatus::EventRedacted => PushNotificationStatus::Redacted,
96fdf90aacd6atagen2026-09-08 08:24 UTC1103
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1104
}