atagen

macltok

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

Blame: src/transport.rs

96fdf90aacd6atagen2026-09-08 08:24 UTC1
use std::sync::{
96fdf90aacd6atagen2026-09-08 08:24 UTC2
    Arc,
96fdf90aacd6atagen2026-09-08 08:24 UTC3
    atomic::{AtomicU64, Ordering},
96fdf90aacd6atagen2026-09-08 08:24 UTC4
};
96fdf90aacd6atagen2026-09-08 08:24 UTC5
use std::{
96fdf90aacd6atagen2026-09-08 08:24 UTC6
    fmt,
96fdf90aacd6atagen2026-09-08 08:24 UTC7
    pin::Pin,
96fdf90aacd6atagen2026-09-08 08:24 UTC8
    task::{Context, Poll},
96fdf90aacd6atagen2026-09-08 08:24 UTC9
};
96fdf90aacd6atagen2026-09-08 08:24 UTC10
96fdf90aacd6atagen2026-09-08 08:24 UTC11
use matrix_sdk::{Client, RoomMemberships};
96fdf90aacd6atagen2026-09-08 08:24 UTC12
use matrix_sdk_ui::{
96fdf90aacd6atagen2026-09-08 08:24 UTC13
    notification_client::{
96fdf90aacd6atagen2026-09-08 08:24 UTC14
        NotificationClient, NotificationProcessSetup, NotificationStatus, RawNotificationEvent,
96fdf90aacd6atagen2026-09-08 08:24 UTC15
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC16
    sync_service::SyncService,
96fdf90aacd6atagen2026-09-08 08:24 UTC17
};
96fdf90aacd6atagen2026-09-08 08:24 UTC18
use ruma::{
96fdf90aacd6atagen2026-09-08 08:24 UTC19
    EventId, RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC20
    events::{
96fdf90aacd6atagen2026-09-08 08:24 UTC21
        AnyGlobalAccountDataEventContent, AnyRoomAccountDataEvent, GlobalAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC22
        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 thiserror::Error;
96fdf90aacd6atagen2026-09-08 08:24 UTC27
use tokio::sync::{OnceCell, mpsc, oneshot, watch};
96fdf90aacd6atagen2026-09-08 08:24 UTC28
96fdf90aacd6atagen2026-09-08 08:24 UTC29
use crate::{
96fdf90aacd6atagen2026-09-08 08:24 UTC30
    AccountCommand, Command, CommandId, ConnectionState, EncryptionState, Event, InteractiveAuth,
96fdf90aacd6atagen2026-09-08 08:24 UTC31
    InteractiveAuthOutcome, MemberFilter, MemberSummary, NotificationCommand, OwnDevice,
96fdf90aacd6atagen2026-09-08 08:24 UTC32
    PowerLevelChanges, PushNotification, PushNotificationEvent, PushNotificationStatus,
96fdf90aacd6atagen2026-09-08 08:24 UTC33
    RoomListFilter, RoomNotificationMode, RoomNotificationSettings, RoomPowerLevels, RoomSummary,
96fdf90aacd6atagen2026-09-08 08:24 UTC34
    encryption::encryption_state,
96fdf90aacd6atagen2026-09-08 08:24 UTC35
    model::{PushNotificationRoom, PushNotificationSender},
96fdf90aacd6atagen2026-09-08 08:24 UTC36
    normalise::{member_summary, room_summaries},
96fdf90aacd6atagen2026-09-08 08:24 UTC37
};
96fdf90aacd6atagen2026-09-08 08:24 UTC38
96fdf90aacd6atagen2026-09-08 08:24 UTC39
#[derive(Clone)]
96fdf90aacd6atagen2026-09-08 08:24 UTC40
pub struct ClientHandle {
96fdf90aacd6atagen2026-09-08 08:24 UTC41
    commands: mpsc::Sender<DriverRequest>,
96fdf90aacd6atagen2026-09-08 08:24 UTC42
    next_id: Arc<AtomicU64>,
96fdf90aacd6atagen2026-09-08 08:24 UTC43
    client: Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC44
    connection: watch::Receiver<ConnectionState>,
96fdf90aacd6atagen2026-09-08 08:24 UTC45
    notification_client: Arc<OnceCell<NotificationClient>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC46
    sync_service: Arc<SyncService>,
96fdf90aacd6atagen2026-09-08 08:24 UTC47
}
96fdf90aacd6atagen2026-09-08 08:24 UTC48
96fdf90aacd6atagen2026-09-08 08:24 UTC49
impl fmt::Debug for ClientHandle {
96fdf90aacd6atagen2026-09-08 08:24 UTC50
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
96fdf90aacd6atagen2026-09-08 08:24 UTC51
        formatter
96fdf90aacd6atagen2026-09-08 08:24 UTC52
            .debug_struct("ClientHandle")
96fdf90aacd6atagen2026-09-08 08:24 UTC53
            .finish_non_exhaustive()
96fdf90aacd6atagen2026-09-08 08:24 UTC54
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC55
}
96fdf90aacd6atagen2026-09-08 08:24 UTC56
96fdf90aacd6atagen2026-09-08 08:24 UTC57
impl ClientHandle {
96fdf90aacd6atagen2026-09-08 08:24 UTC58
    /// Current credentials after a refresh. Persist this snapshot atomically
96fdf90aacd6atagen2026-09-08 08:24 UTC59
    /// when `Event::SessionTokensChanged` arrives; it contains secrets.
96fdf90aacd6atagen2026-09-08 08:24 UTC60
    #[cfg(feature = "sqlite")]
96fdf90aacd6atagen2026-09-08 08:24 UTC61
    pub fn session_record(&self) -> Result<crate::SessionRecord, crate::AccountError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC62
        crate::account::session_record(&self.client)
96fdf90aacd6atagen2026-09-08 08:24 UTC63
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC64
96fdf90aacd6atagen2026-09-08 08:24 UTC65
    /// Queue a command and return its correlation ID, not its result. Drain
96fdf90aacd6atagen2026-09-08 08:24 UTC66
    /// `EventStream` concurrently and match one terminal result event by ID.
96fdf90aacd6atagen2026-09-08 08:24 UTC67
    /// A successful timeline send only means the SDK queue accepted it.
96fdf90aacd6atagen2026-09-08 08:24 UTC68
    pub async fn send(&self, command: Command) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC69
        let id = self.next_command_id();
96fdf90aacd6atagen2026-09-08 08:24 UTC70
        self.commands
96fdf90aacd6atagen2026-09-08 08:24 UTC71
            .send(DriverRequest::Command(CommandEnvelope { id, command }))
96fdf90aacd6atagen2026-09-08 08:24 UTC72
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC73
            .map_err(|_| SendCommandError::Closed)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC74
        Ok(id)
96fdf90aacd6atagen2026-09-08 08:24 UTC75
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC76
96fdf90aacd6atagen2026-09-08 08:24 UTC77
    pub async fn delete_devices(
96fdf90aacd6atagen2026-09-08 08:24 UTC78
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC79
        device_ids: Vec<ruma::OwnedDeviceId>,
96fdf90aacd6atagen2026-09-08 08:24 UTC80
        auth: Option<InteractiveAuth>,
96fdf90aacd6atagen2026-09-08 08:24 UTC81
    ) -> Result<InteractiveAuthOutcome, CommandResultError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC82
        let (reply, result) = oneshot::channel();
96fdf90aacd6atagen2026-09-08 08:24 UTC83
        self.commands
96fdf90aacd6atagen2026-09-08 08:24 UTC84
            .send(DriverRequest::DeleteDevices {
96fdf90aacd6atagen2026-09-08 08:24 UTC85
                id: self.next_command_id(),
96fdf90aacd6atagen2026-09-08 08:24 UTC86
                device_ids,
96fdf90aacd6atagen2026-09-08 08:24 UTC87
                auth,
96fdf90aacd6atagen2026-09-08 08:24 UTC88
                reply,
96fdf90aacd6atagen2026-09-08 08:24 UTC89
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC90
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC91
            .map_err(|_| SendCommandError::Closed)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC92
        result.await.map_err(|_| CommandResultError::Closed)?
96fdf90aacd6atagen2026-09-08 08:24 UTC93
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC94
96fdf90aacd6atagen2026-09-08 08:24 UTC95
    pub async fn rename_device(
96fdf90aacd6atagen2026-09-08 08:24 UTC96
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC97
        device_id: ruma::OwnedDeviceId,
96fdf90aacd6atagen2026-09-08 08:24 UTC98
        display_name: impl Into<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC99
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC100
        self.send(Command::Account(AccountCommand::RenameDevice {
96fdf90aacd6atagen2026-09-08 08:24 UTC101
            device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC102
            display_name: display_name.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC103
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC104
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC105
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC106
96fdf90aacd6atagen2026-09-08 08:24 UTC107
    pub async fn set_room_notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC108
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC109
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC110
        mode: RoomNotificationMode,
96fdf90aacd6atagen2026-09-08 08:24 UTC111
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC112
        self.send(Command::Notification(NotificationCommand::SetRoomMode {
96fdf90aacd6atagen2026-09-08 08:24 UTC113
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC114
            mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC115
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC116
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC117
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC118
96fdf90aacd6atagen2026-09-08 08:24 UTC119
    pub async fn reset_room_notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC120
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC121
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC122
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC123
        self.send(Command::Notification(NotificationCommand::ResetRoomMode(
96fdf90aacd6atagen2026-09-08 08:24 UTC124
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC125
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC126
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC127
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC128
96fdf90aacd6atagen2026-09-08 08:24 UTC129
    pub async fn set_default_notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC130
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC131
        encrypted: bool,
96fdf90aacd6atagen2026-09-08 08:24 UTC132
        one_to_one: bool,
96fdf90aacd6atagen2026-09-08 08:24 UTC133
        mode: RoomNotificationMode,
96fdf90aacd6atagen2026-09-08 08:24 UTC134
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC135
        self.send(Command::Notification(NotificationCommand::SetDefaultMode {
96fdf90aacd6atagen2026-09-08 08:24 UTC136
            encrypted,
96fdf90aacd6atagen2026-09-08 08:24 UTC137
            one_to_one,
96fdf90aacd6atagen2026-09-08 08:24 UTC138
            mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC139
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC140
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC141
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC142
96fdf90aacd6atagen2026-09-08 08:24 UTC143
    pub async fn add_notification_keyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC144
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC145
        keyword: impl Into<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC146
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC147
        self.send(Command::Notification(NotificationCommand::AddKeyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC148
            keyword.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC149
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC150
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC151
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC152
96fdf90aacd6atagen2026-09-08 08:24 UTC153
    pub async fn remove_notification_keyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC154
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC155
        keyword: impl Into<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC156
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC157
        self.send(Command::Notification(NotificationCommand::RemoveKeyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC158
            keyword.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC159
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC160
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC161
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC162
96fdf90aacd6atagen2026-09-08 08:24 UTC163
    pub async fn open_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC164
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC165
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC166
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC167
        self.send(Command::Room(crate::RoomCommand::Open(room_id)))
96fdf90aacd6atagen2026-09-08 08:24 UTC168
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC169
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC170
96fdf90aacd6atagen2026-09-08 08:24 UTC171
    pub async fn close_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC172
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC173
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC174
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC175
        self.send(Command::Room(crate::RoomCommand::Close(room_id)))
96fdf90aacd6atagen2026-09-08 08:24 UTC176
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC177
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC178
96fdf90aacd6atagen2026-09-08 08:24 UTC179
    pub async fn open_thread(
96fdf90aacd6atagen2026-09-08 08:24 UTC180
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC181
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC182
        root_event_id: ruma::OwnedEventId,
96fdf90aacd6atagen2026-09-08 08:24 UTC183
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC184
        self.send(Command::Timeline(crate::TimelineCommand::OpenThread {
96fdf90aacd6atagen2026-09-08 08:24 UTC185
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC186
            root_event_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC187
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC188
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC189
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC190
96fdf90aacd6atagen2026-09-08 08:24 UTC191
    pub async fn close_thread(
96fdf90aacd6atagen2026-09-08 08:24 UTC192
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC193
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC194
        root_event_id: ruma::OwnedEventId,
96fdf90aacd6atagen2026-09-08 08:24 UTC195
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC196
        self.send(Command::Timeline(crate::TimelineCommand::CloseThread {
96fdf90aacd6atagen2026-09-08 08:24 UTC197
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC198
            root_event_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC199
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC200
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC201
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC202
96fdf90aacd6atagen2026-09-08 08:24 UTC203
    pub async fn join_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC204
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC205
        room: ruma::OwnedRoomOrAliasId,
96fdf90aacd6atagen2026-09-08 08:24 UTC206
        via: Vec<ruma::OwnedServerName>,
96fdf90aacd6atagen2026-09-08 08:24 UTC207
    ) -> Result<ruma::OwnedRoomId, CommandResultError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC208
        self.room_result(crate::RoomCommand::Join { room, via })
96fdf90aacd6atagen2026-09-08 08:24 UTC209
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC210
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC211
96fdf90aacd6atagen2026-09-08 08:24 UTC212
    pub async fn leave_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC213
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC214
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC215
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC216
        self.send(Command::Room(crate::RoomCommand::Leave(room_id)))
96fdf90aacd6atagen2026-09-08 08:24 UTC217
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC218
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC219
96fdf90aacd6atagen2026-09-08 08:24 UTC220
    pub async fn forget_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC221
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC222
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC223
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC224
        self.send(Command::Room(crate::RoomCommand::Forget(room_id)))
96fdf90aacd6atagen2026-09-08 08:24 UTC225
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC226
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC227
96fdf90aacd6atagen2026-09-08 08:24 UTC228
    pub async fn accept_invite(
96fdf90aacd6atagen2026-09-08 08:24 UTC229
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC230
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC231
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC232
        self.send(Command::Room(crate::RoomCommand::AcceptInvite(room_id)))
96fdf90aacd6atagen2026-09-08 08:24 UTC233
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC234
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC235
96fdf90aacd6atagen2026-09-08 08:24 UTC236
    pub async fn reject_invite(
96fdf90aacd6atagen2026-09-08 08:24 UTC237
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC238
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC239
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC240
        self.send(Command::Room(crate::RoomCommand::RejectInvite(room_id)))
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 invite_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC245
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC246
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC247
        user_id: ruma::OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC248
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC249
        self.send(Command::Room(crate::RoomCommand::InviteUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC250
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC251
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC252
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC253
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC254
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC255
96fdf90aacd6atagen2026-09-08 08:24 UTC256
    pub async fn kick_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC257
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC258
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC259
        user_id: ruma::OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC260
        reason: Option<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC261
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC262
        self.send(Command::Room(crate::RoomCommand::KickUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC263
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC264
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC265
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC266
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC267
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC268
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC269
96fdf90aacd6atagen2026-09-08 08:24 UTC270
    pub async fn ban_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC271
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC272
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC273
        user_id: ruma::OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC274
        reason: Option<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC275
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC276
        self.send(Command::Room(crate::RoomCommand::BanUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC277
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC278
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC279
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC280
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC281
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC282
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC283
96fdf90aacd6atagen2026-09-08 08:24 UTC284
    pub async fn unban_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC285
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC286
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC287
        user_id: ruma::OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC288
        reason: Option<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC289
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC290
        self.send(Command::Room(crate::RoomCommand::UnbanUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC291
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC292
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC293
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC294
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC295
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC296
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC297
96fdf90aacd6atagen2026-09-08 08:24 UTC298
    pub async fn set_power_levels(
96fdf90aacd6atagen2026-09-08 08:24 UTC299
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC300
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC301
        changes: PowerLevelChanges,
96fdf90aacd6atagen2026-09-08 08:24 UTC302
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC303
        self.send(Command::Room(crate::RoomCommand::SetPowerLevels {
96fdf90aacd6atagen2026-09-08 08:24 UTC304
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC305
            changes,
96fdf90aacd6atagen2026-09-08 08:24 UTC306
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC307
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC308
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC309
96fdf90aacd6atagen2026-09-08 08:24 UTC310
    pub async fn set_user_power_level(
96fdf90aacd6atagen2026-09-08 08:24 UTC311
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC312
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC313
        user_id: ruma::OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC314
        level: i64,
96fdf90aacd6atagen2026-09-08 08:24 UTC315
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC316
        self.send(Command::Room(crate::RoomCommand::SetUserPowerLevel {
96fdf90aacd6atagen2026-09-08 08:24 UTC317
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC318
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC319
            level,
96fdf90aacd6atagen2026-09-08 08:24 UTC320
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC321
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC322
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC323
96fdf90aacd6atagen2026-09-08 08:24 UTC324
    pub async fn create_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC325
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC326
        options: crate::CreateRoomOptions,
96fdf90aacd6atagen2026-09-08 08:24 UTC327
    ) -> Result<ruma::OwnedRoomId, CommandResultError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC328
        self.room_result(crate::RoomCommand::Create(options)).await
96fdf90aacd6atagen2026-09-08 08:24 UTC329
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC330
96fdf90aacd6atagen2026-09-08 08:24 UTC331
    pub async fn create_direct(
96fdf90aacd6atagen2026-09-08 08:24 UTC332
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC333
        user_id: ruma::OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC334
    ) -> Result<ruma::OwnedRoomId, CommandResultError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC335
        self.room_result(crate::RoomCommand::CreateDirect(user_id))
96fdf90aacd6atagen2026-09-08 08:24 UTC336
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC337
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC338
96fdf90aacd6atagen2026-09-08 08:24 UTC339
    async fn room_result(
96fdf90aacd6atagen2026-09-08 08:24 UTC340
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC341
        command: crate::RoomCommand,
96fdf90aacd6atagen2026-09-08 08:24 UTC342
    ) -> Result<ruma::OwnedRoomId, CommandResultError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC343
        let (reply, result) = oneshot::channel();
96fdf90aacd6atagen2026-09-08 08:24 UTC344
        self.commands
96fdf90aacd6atagen2026-09-08 08:24 UTC345
            .send(DriverRequest::RoomResult {
96fdf90aacd6atagen2026-09-08 08:24 UTC346
                id: self.next_command_id(),
96fdf90aacd6atagen2026-09-08 08:24 UTC347
                command,
96fdf90aacd6atagen2026-09-08 08:24 UTC348
                reply,
96fdf90aacd6atagen2026-09-08 08:24 UTC349
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC350
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC351
            .map_err(|_| SendCommandError::Closed)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC352
        result.await.map_err(|_| CommandResultError::Closed)?
96fdf90aacd6atagen2026-09-08 08:24 UTC353
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC354
96fdf90aacd6atagen2026-09-08 08:24 UTC355
    pub async fn cancel_send(
96fdf90aacd6atagen2026-09-08 08:24 UTC356
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC357
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC358
        transaction_id: ruma::OwnedTransactionId,
96fdf90aacd6atagen2026-09-08 08:24 UTC359
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC360
        self.send(Command::Room(crate::RoomCommand::CancelSend {
96fdf90aacd6atagen2026-09-08 08:24 UTC361
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC362
            transaction_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC363
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC364
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC365
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC366
96fdf90aacd6atagen2026-09-08 08:24 UTC367
    pub async fn retry_send(
96fdf90aacd6atagen2026-09-08 08:24 UTC368
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC369
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC370
        transaction_id: ruma::OwnedTransactionId,
96fdf90aacd6atagen2026-09-08 08:24 UTC371
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC372
        self.send(Command::Room(crate::RoomCommand::RetrySend {
96fdf90aacd6atagen2026-09-08 08:24 UTC373
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC374
            transaction_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC375
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC376
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC377
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC378
96fdf90aacd6atagen2026-09-08 08:24 UTC379
    pub async fn upload_media(
96fdf90aacd6atagen2026-09-08 08:24 UTC380
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC381
        timeline_id: crate::TimelineId,
96fdf90aacd6atagen2026-09-08 08:24 UTC382
        filename: String,
96fdf90aacd6atagen2026-09-08 08:24 UTC383
        mimetype: String,
96fdf90aacd6atagen2026-09-08 08:24 UTC384
        bytes: Vec<u8>,
96fdf90aacd6atagen2026-09-08 08:24 UTC385
        caption: Option<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC386
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC387
        self.send(Command::Media(crate::MediaCommand::Upload {
96fdf90aacd6atagen2026-09-08 08:24 UTC388
            timeline_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC389
            filename,
96fdf90aacd6atagen2026-09-08 08:24 UTC390
            mimetype,
96fdf90aacd6atagen2026-09-08 08:24 UTC391
            bytes,
96fdf90aacd6atagen2026-09-08 08:24 UTC392
            caption,
96fdf90aacd6atagen2026-09-08 08:24 UTC393
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC394
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC395
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC396
96fdf90aacd6atagen2026-09-08 08:24 UTC397
    pub async fn upload_attachment(
96fdf90aacd6atagen2026-09-08 08:24 UTC398
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC399
        upload: crate::AttachmentUpload,
96fdf90aacd6atagen2026-09-08 08:24 UTC400
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC401
        self.send(Command::Media(crate::MediaCommand::UploadAttachment(
96fdf90aacd6atagen2026-09-08 08:24 UTC402
            upload,
96fdf90aacd6atagen2026-09-08 08:24 UTC403
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC404
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC405
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC406
96fdf90aacd6atagen2026-09-08 08:24 UTC407
    pub async fn create_key_backup(&self) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC408
        self.send(Command::Encryption(
96fdf90aacd6atagen2026-09-08 08:24 UTC409
            crate::EncryptionCommand::CreateKeyBackup,
96fdf90aacd6atagen2026-09-08 08:24 UTC410
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC411
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC412
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC413
96fdf90aacd6atagen2026-09-08 08:24 UTC414
    pub async fn enable_key_backup(&self) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC415
        self.send(Command::Encryption(
96fdf90aacd6atagen2026-09-08 08:24 UTC416
            crate::EncryptionCommand::EnableKeyBackup,
96fdf90aacd6atagen2026-09-08 08:24 UTC417
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC418
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC419
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC420
96fdf90aacd6atagen2026-09-08 08:24 UTC421
    pub async fn disable_key_backup(
96fdf90aacd6atagen2026-09-08 08:24 UTC422
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC423
        delete_from_server: bool,
96fdf90aacd6atagen2026-09-08 08:24 UTC424
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC425
        self.send(Command::Encryption(
96fdf90aacd6atagen2026-09-08 08:24 UTC426
            crate::EncryptionCommand::DisableKeyBackup { delete_from_server },
96fdf90aacd6atagen2026-09-08 08:24 UTC427
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC428
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC429
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC430
96fdf90aacd6atagen2026-09-08 08:24 UTC431
    pub async fn recover_key_backup(
96fdf90aacd6atagen2026-09-08 08:24 UTC432
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC433
        recovery_key: impl Into<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC434
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC435
        self.send(Command::Encryption(
96fdf90aacd6atagen2026-09-08 08:24 UTC436
            crate::EncryptionCommand::RecoverKeyBackup(recovery_key.into()),
96fdf90aacd6atagen2026-09-08 08:24 UTC437
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC438
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC439
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC440
96fdf90aacd6atagen2026-09-08 08:24 UTC441
    pub async fn start_verification(
96fdf90aacd6atagen2026-09-08 08:24 UTC442
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC443
        target: crate::VerificationTarget,
96fdf90aacd6atagen2026-09-08 08:24 UTC444
    ) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC445
        self.send(Command::Encryption(
96fdf90aacd6atagen2026-09-08 08:24 UTC446
            crate::EncryptionCommand::StartVerification(target),
96fdf90aacd6atagen2026-09-08 08:24 UTC447
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC448
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC449
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC450
96fdf90aacd6atagen2026-09-08 08:24 UTC451
    pub fn try_send(&self, command: Command) -> Result<CommandId, SendCommandError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC452
        let id = self.next_command_id();
96fdf90aacd6atagen2026-09-08 08:24 UTC453
        self.commands
96fdf90aacd6atagen2026-09-08 08:24 UTC454
            .try_send(DriverRequest::Command(CommandEnvelope { id, command }))
96fdf90aacd6atagen2026-09-08 08:24 UTC455
            .map_err(|error| match error {
96fdf90aacd6atagen2026-09-08 08:24 UTC456
                mpsc::error::TrySendError::Full(_) => SendCommandError::Full,
96fdf90aacd6atagen2026-09-08 08:24 UTC457
                mpsc::error::TrySendError::Closed(_) => SendCommandError::Closed,
96fdf90aacd6atagen2026-09-08 08:24 UTC458
            })?;
96fdf90aacd6atagen2026-09-08 08:24 UTC459
        Ok(id)
96fdf90aacd6atagen2026-09-08 08:24 UTC460
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC461
96fdf90aacd6atagen2026-09-08 08:24 UTC462
    fn next_command_id(&self) -> CommandId {
96fdf90aacd6atagen2026-09-08 08:24 UTC463
        CommandId::new(self.next_id.fetch_add(1, Ordering::Relaxed))
96fdf90aacd6atagen2026-09-08 08:24 UTC464
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC465
96fdf90aacd6atagen2026-09-08 08:24 UTC466
    pub async fn rooms(&self) -> Vec<RoomSummary> {
96fdf90aacd6atagen2026-09-08 08:24 UTC467
        room_summaries(&self.client).await
96fdf90aacd6atagen2026-09-08 08:24 UTC468
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC469
96fdf90aacd6atagen2026-09-08 08:24 UTC470
    pub async fn rooms_filtered(&self, filter: &RoomListFilter) -> Vec<RoomSummary> {
96fdf90aacd6atagen2026-09-08 08:24 UTC471
        let mut room_filter = filter.clone();
96fdf90aacd6atagen2026-09-08 08:24 UTC472
        let search = room_filter
96fdf90aacd6atagen2026-09-08 08:24 UTC473
            .search
96fdf90aacd6atagen2026-09-08 08:24 UTC474
            .take()
96fdf90aacd6atagen2026-09-08 08:24 UTC475
            .map(|search| search.to_lowercase());
96fdf90aacd6atagen2026-09-08 08:24 UTC476
96fdf90aacd6atagen2026-09-08 08:24 UTC477
        self.rooms()
96fdf90aacd6atagen2026-09-08 08:24 UTC478
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC479
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC480
            .filter(|room| {
96fdf90aacd6atagen2026-09-08 08:24 UTC481
                room_filter.matches(room)
96fdf90aacd6atagen2026-09-08 08:24 UTC482
                    && search.as_ref().is_none_or(|search| {
96fdf90aacd6atagen2026-09-08 08:24 UTC483
                        room.name.to_lowercase().contains(search)
96fdf90aacd6atagen2026-09-08 08:24 UTC484
                            || room.room_id.as_str().to_lowercase().contains(search)
96fdf90aacd6atagen2026-09-08 08:24 UTC485
                    })
96fdf90aacd6atagen2026-09-08 08:24 UTC486
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC487
            .collect()
96fdf90aacd6atagen2026-09-08 08:24 UTC488
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC489
96fdf90aacd6atagen2026-09-08 08:24 UTC490
    pub async fn devices(&self) -> Result<Vec<OwnDevice>, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC491
        let current_device_id = self.client.device_id();
96fdf90aacd6atagen2026-09-08 08:24 UTC492
        Ok(self
96fdf90aacd6atagen2026-09-08 08:24 UTC493
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC494
            .devices()
96fdf90aacd6atagen2026-09-08 08:24 UTC495
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC496
            .map_err(|source| ClientQueryError::Sdk(source.into()))?
96fdf90aacd6atagen2026-09-08 08:24 UTC497
            .devices
96fdf90aacd6atagen2026-09-08 08:24 UTC498
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC499
            .map(|device| OwnDevice {
96fdf90aacd6atagen2026-09-08 08:24 UTC500
                current: current_device_id == Some(device.device_id.as_ref()),
96fdf90aacd6atagen2026-09-08 08:24 UTC501
                device_id: device.device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC502
                display_name: device.display_name,
96fdf90aacd6atagen2026-09-08 08:24 UTC503
                last_seen_ip: device.last_seen_ip,
96fdf90aacd6atagen2026-09-08 08:24 UTC504
                last_seen_timestamp_ms: device.last_seen_ts.map(|timestamp| timestamp.get().into()),
96fdf90aacd6atagen2026-09-08 08:24 UTC505
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC506
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC507
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC508
96fdf90aacd6atagen2026-09-08 08:24 UTC509
    pub async fn room_notification_settings(
96fdf90aacd6atagen2026-09-08 08:24 UTC510
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC511
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC512
    ) -> Result<Option<RoomNotificationSettings>, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC513
        let room = self
96fdf90aacd6atagen2026-09-08 08:24 UTC514
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC515
            .get_room(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC516
            .ok_or_else(|| ClientQueryError::RoomUnknown(room_id.to_owned()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC517
        let custom = room.user_defined_notification_mode().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC518
        let mode = match custom {
96fdf90aacd6atagen2026-09-08 08:24 UTC519
            Some(mode) => mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC520
            None => match room.notification_mode().await {
96fdf90aacd6atagen2026-09-08 08:24 UTC521
                Some(mode) => mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC522
                None => return Ok(None),
96fdf90aacd6atagen2026-09-08 08:24 UTC523
            },
96fdf90aacd6atagen2026-09-08 08:24 UTC524
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC525
        Ok(Some(RoomNotificationSettings {
96fdf90aacd6atagen2026-09-08 08:24 UTC526
            mode: crate::normalise::notification_mode(mode),
96fdf90aacd6atagen2026-09-08 08:24 UTC527
            custom: custom.is_some(),
96fdf90aacd6atagen2026-09-08 08:24 UTC528
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC529
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC530
96fdf90aacd6atagen2026-09-08 08:24 UTC531
    pub async fn notification_keywords(&self) -> Vec<String> {
96fdf90aacd6atagen2026-09-08 08:24 UTC532
        self.client
96fdf90aacd6atagen2026-09-08 08:24 UTC533
            .notification_settings()
96fdf90aacd6atagen2026-09-08 08:24 UTC534
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC535
            .enabled_keywords()
96fdf90aacd6atagen2026-09-08 08:24 UTC536
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC537
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC538
            .collect()
96fdf90aacd6atagen2026-09-08 08:24 UTC539
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC540
96fdf90aacd6atagen2026-09-08 08:24 UTC541
    pub async fn resolve_push_notification(
96fdf90aacd6atagen2026-09-08 08:24 UTC542
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC543
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC544
        event_id: &EventId,
96fdf90aacd6atagen2026-09-08 08:24 UTC545
    ) -> Result<PushNotificationStatus, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC546
        let client = self
96fdf90aacd6atagen2026-09-08 08:24 UTC547
            .notification_client
96fdf90aacd6atagen2026-09-08 08:24 UTC548
            .get_or_try_init(|| async {
96fdf90aacd6atagen2026-09-08 08:24 UTC549
                NotificationClient::new(
96fdf90aacd6atagen2026-09-08 08:24 UTC550
                    self.client.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC551
                    NotificationProcessSetup::SingleProcess {
96fdf90aacd6atagen2026-09-08 08:24 UTC552
                        sync_service: self.sync_service.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC553
                    },
96fdf90aacd6atagen2026-09-08 08:24 UTC554
                )
96fdf90aacd6atagen2026-09-08 08:24 UTC555
                .await
96fdf90aacd6atagen2026-09-08 08:24 UTC556
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC557
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC558
            .map_err(ClientQueryError::Notification)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC559
        let status = client
96fdf90aacd6atagen2026-09-08 08:24 UTC560
            .get_notification(room_id, event_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC561
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC562
            .map_err(ClientQueryError::Notification)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC563
        Ok(normalise_push_notification(room_id, event_id, status))
96fdf90aacd6atagen2026-09-08 08:24 UTC564
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC565
96fdf90aacd6atagen2026-09-08 08:24 UTC566
    pub async fn members(
96fdf90aacd6atagen2026-09-08 08:24 UTC567
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC568
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC569
        filter: MemberFilter,
96fdf90aacd6atagen2026-09-08 08:24 UTC570
    ) -> Result<Vec<MemberSummary>, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC571
        let room = self
96fdf90aacd6atagen2026-09-08 08:24 UTC572
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC573
            .get_room(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC574
            .ok_or_else(|| ClientQueryError::RoomUnknown(room_id.to_owned()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC575
        let memberships = match filter {
96fdf90aacd6atagen2026-09-08 08:24 UTC576
            MemberFilter::Active => RoomMemberships::ACTIVE,
96fdf90aacd6atagen2026-09-08 08:24 UTC577
            MemberFilter::Joined => RoomMemberships::JOIN,
96fdf90aacd6atagen2026-09-08 08:24 UTC578
            MemberFilter::Invited => RoomMemberships::INVITE,
96fdf90aacd6atagen2026-09-08 08:24 UTC579
            // An empty mask is the SDK's unfiltered wildcard: it matches every
96fdf90aacd6atagen2026-09-08 08:24 UTC580
            // membership, including custom states that `all()` would exclude.
96fdf90aacd6atagen2026-09-08 08:24 UTC581
            MemberFilter::All => RoomMemberships::empty(),
96fdf90aacd6atagen2026-09-08 08:24 UTC582
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC583
        Ok(room
96fdf90aacd6atagen2026-09-08 08:24 UTC584
            .members(memberships)
96fdf90aacd6atagen2026-09-08 08:24 UTC585
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC586
            .map_err(ClientQueryError::Sdk)?
96fdf90aacd6atagen2026-09-08 08:24 UTC587
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC588
            .map(member_summary)
96fdf90aacd6atagen2026-09-08 08:24 UTC589
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC590
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC591
96fdf90aacd6atagen2026-09-08 08:24 UTC592
    pub async fn room_power_levels(
96fdf90aacd6atagen2026-09-08 08:24 UTC593
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC594
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC595
    ) -> Result<RoomPowerLevels, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC596
        let room = self
96fdf90aacd6atagen2026-09-08 08:24 UTC597
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC598
            .get_room(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC599
            .ok_or_else(|| ClientQueryError::RoomUnknown(room_id.to_owned()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC600
        let levels = room
96fdf90aacd6atagen2026-09-08 08:24 UTC601
            .power_levels()
96fdf90aacd6atagen2026-09-08 08:24 UTC602
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC603
            .map_err(|source| ClientQueryError::Sdk(source.into()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC604
        Ok(RoomPowerLevels {
96fdf90aacd6atagen2026-09-08 08:24 UTC605
            ban: levels.ban.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC606
            invite: levels.invite.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC607
            kick: levels.kick.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC608
            redact: levels.redact.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC609
            events_default: levels.events_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC610
            state_default: levels.state_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC611
            users_default: levels.users_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC612
            room_notification: levels.notifications.room.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC613
            users: levels
96fdf90aacd6atagen2026-09-08 08:24 UTC614
                .users
96fdf90aacd6atagen2026-09-08 08:24 UTC615
                .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC616
                .map(|(user_id, level)| (user_id, level.into()))
96fdf90aacd6atagen2026-09-08 08:24 UTC617
                .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC618
            events: levels
96fdf90aacd6atagen2026-09-08 08:24 UTC619
                .events
96fdf90aacd6atagen2026-09-08 08:24 UTC620
                .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC621
                .map(|(event_type, level)| (event_type.to_string(), level.into()))
96fdf90aacd6atagen2026-09-08 08:24 UTC622
                .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC623
        })
96fdf90aacd6atagen2026-09-08 08:24 UTC624
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC625
96fdf90aacd6atagen2026-09-08 08:24 UTC626
    pub async fn pending_send_ids(
96fdf90aacd6atagen2026-09-08 08:24 UTC627
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC628
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC629
    ) -> Result<Vec<ruma::OwnedTransactionId>, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC630
        let room = self
96fdf90aacd6atagen2026-09-08 08:24 UTC631
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC632
            .get_room(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC633
            .ok_or_else(|| ClientQueryError::RoomUnknown(room_id.to_owned()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC634
        let (echoes, _) = room
96fdf90aacd6atagen2026-09-08 08:24 UTC635
            .send_queue()
96fdf90aacd6atagen2026-09-08 08:24 UTC636
            .subscribe()
96fdf90aacd6atagen2026-09-08 08:24 UTC637
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC638
            .map_err(ClientQueryError::SendQueue)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC639
        Ok(echoes
96fdf90aacd6atagen2026-09-08 08:24 UTC640
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC641
            .filter(|echo| {
96fdf90aacd6atagen2026-09-08 08:24 UTC642
                matches!(
96fdf90aacd6atagen2026-09-08 08:24 UTC643
                    echo.content,
96fdf90aacd6atagen2026-09-08 08:24 UTC644
                    matrix_sdk::send_queue::LocalEchoContent::Event { .. }
96fdf90aacd6atagen2026-09-08 08:24 UTC645
                )
96fdf90aacd6atagen2026-09-08 08:24 UTC646
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC647
            .map(|echo| echo.transaction_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC648
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC649
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC650
96fdf90aacd6atagen2026-09-08 08:24 UTC651
    pub async fn global_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC652
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC653
        event_type: GlobalAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC654
    ) -> Result<Option<Raw<AnyGlobalAccountDataEventContent>>, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC655
        self.client
96fdf90aacd6atagen2026-09-08 08:24 UTC656
            .account()
96fdf90aacd6atagen2026-09-08 08:24 UTC657
            .account_data_raw(event_type)
96fdf90aacd6atagen2026-09-08 08:24 UTC658
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC659
            .map_err(ClientQueryError::Sdk)
96fdf90aacd6atagen2026-09-08 08:24 UTC660
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC661
96fdf90aacd6atagen2026-09-08 08:24 UTC662
    pub async fn set_global_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC663
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC664
        event_type: GlobalAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC665
        content: Raw<AnyGlobalAccountDataEventContent>,
96fdf90aacd6atagen2026-09-08 08:24 UTC666
    ) -> Result<(), ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC667
        let (reply, result) = oneshot::channel();
96fdf90aacd6atagen2026-09-08 08:24 UTC668
        self.commands
96fdf90aacd6atagen2026-09-08 08:24 UTC669
            .send(DriverRequest::SetGlobalAccountData {
96fdf90aacd6atagen2026-09-08 08:24 UTC670
                event_type,
96fdf90aacd6atagen2026-09-08 08:24 UTC671
                content,
96fdf90aacd6atagen2026-09-08 08:24 UTC672
                reply,
96fdf90aacd6atagen2026-09-08 08:24 UTC673
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC674
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC675
            .map_err(|_| ClientQueryError::EngineStopped)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC676
        result.await.map_err(|_| ClientQueryError::EngineStopped)?
96fdf90aacd6atagen2026-09-08 08:24 UTC677
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC678
96fdf90aacd6atagen2026-09-08 08:24 UTC679
    pub async fn room_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC680
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC681
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC682
        event_type: RoomAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC683
    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC684
        let room = self
96fdf90aacd6atagen2026-09-08 08:24 UTC685
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC686
            .get_room(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC687
            .ok_or_else(|| ClientQueryError::RoomUnknown(room_id.to_owned()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC688
        room.account_data(event_type)
96fdf90aacd6atagen2026-09-08 08:24 UTC689
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC690
            .map_err(ClientQueryError::Sdk)
96fdf90aacd6atagen2026-09-08 08:24 UTC691
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC692
96fdf90aacd6atagen2026-09-08 08:24 UTC693
    pub async fn set_room_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC694
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC695
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC696
        event_type: RoomAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC697
        content: Raw<ruma::events::AnyRoomAccountDataEventContent>,
96fdf90aacd6atagen2026-09-08 08:24 UTC698
    ) -> Result<(), ClientQueryError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC699
        let (reply, result) = oneshot::channel();
96fdf90aacd6atagen2026-09-08 08:24 UTC700
        self.commands
96fdf90aacd6atagen2026-09-08 08:24 UTC701
            .send(DriverRequest::SetRoomAccountData {
96fdf90aacd6atagen2026-09-08 08:24 UTC702
                room_id: room_id.to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC703
                event_type,
96fdf90aacd6atagen2026-09-08 08:24 UTC704
                content,
96fdf90aacd6atagen2026-09-08 08:24 UTC705
                reply,
96fdf90aacd6atagen2026-09-08 08:24 UTC706
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC707
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC708
            .map_err(|_| ClientQueryError::EngineStopped)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC709
        result.await.map_err(|_| ClientQueryError::EngineStopped)?
96fdf90aacd6atagen2026-09-08 08:24 UTC710
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC711
96fdf90aacd6atagen2026-09-08 08:24 UTC712
    #[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC713
    pub fn connection_state(&self) -> watch::Receiver<ConnectionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC714
        self.connection.clone()
96fdf90aacd6atagen2026-09-08 08:24 UTC715
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC716
96fdf90aacd6atagen2026-09-08 08:24 UTC717
    #[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC718
    pub fn encryption_state(&self) -> Option<EncryptionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC719
        let device_id = self.client.device_id()?.to_owned();
96fdf90aacd6atagen2026-09-08 08:24 UTC720
        let encryption = self.client.encryption();
96fdf90aacd6atagen2026-09-08 08:24 UTC721
        Some(encryption_state(
96fdf90aacd6atagen2026-09-08 08:24 UTC722
            device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC723
            encryption.recovery().state(),
96fdf90aacd6atagen2026-09-08 08:24 UTC724
            encryption.verification_state().get(),
96fdf90aacd6atagen2026-09-08 08:24 UTC725
            encryption.backups().state(),
96fdf90aacd6atagen2026-09-08 08:24 UTC726
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC727
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC728
}
96fdf90aacd6atagen2026-09-08 08:24 UTC729
96fdf90aacd6atagen2026-09-08 08:24 UTC730
#[derive(Debug, Eq, PartialEq)]
96fdf90aacd6atagen2026-09-08 08:24 UTC731
pub(crate) struct CommandEnvelope {
96fdf90aacd6atagen2026-09-08 08:24 UTC732
    pub(crate) id: CommandId,
96fdf90aacd6atagen2026-09-08 08:24 UTC733
    pub(crate) command: Command,
96fdf90aacd6atagen2026-09-08 08:24 UTC734
}
96fdf90aacd6atagen2026-09-08 08:24 UTC735
96fdf90aacd6atagen2026-09-08 08:24 UTC736
#[derive(Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC737
pub(crate) enum DriverRequest {
96fdf90aacd6atagen2026-09-08 08:24 UTC738
    Command(CommandEnvelope),
96fdf90aacd6atagen2026-09-08 08:24 UTC739
    DeleteDevices {
96fdf90aacd6atagen2026-09-08 08:24 UTC740
        id: CommandId,
96fdf90aacd6atagen2026-09-08 08:24 UTC741
        device_ids: Vec<ruma::OwnedDeviceId>,
96fdf90aacd6atagen2026-09-08 08:24 UTC742
        auth: Option<InteractiveAuth>,
96fdf90aacd6atagen2026-09-08 08:24 UTC743
        reply: oneshot::Sender<Result<InteractiveAuthOutcome, CommandResultError>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC744
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC745
    RoomResult {
96fdf90aacd6atagen2026-09-08 08:24 UTC746
        id: CommandId,
96fdf90aacd6atagen2026-09-08 08:24 UTC747
        command: crate::RoomCommand,
96fdf90aacd6atagen2026-09-08 08:24 UTC748
        reply: oneshot::Sender<Result<ruma::OwnedRoomId, CommandResultError>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC749
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC750
    SetGlobalAccountData {
96fdf90aacd6atagen2026-09-08 08:24 UTC751
        event_type: GlobalAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC752
        content: Raw<AnyGlobalAccountDataEventContent>,
96fdf90aacd6atagen2026-09-08 08:24 UTC753
        reply: oneshot::Sender<Result<(), ClientQueryError>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC754
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC755
    SetRoomAccountData {
96fdf90aacd6atagen2026-09-08 08:24 UTC756
        room_id: ruma::OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC757
        event_type: RoomAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC758
        content: Raw<ruma::events::AnyRoomAccountDataEventContent>,
96fdf90aacd6atagen2026-09-08 08:24 UTC759
        reply: oneshot::Sender<Result<(), ClientQueryError>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC760
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC761
}
96fdf90aacd6atagen2026-09-08 08:24 UTC762
96fdf90aacd6atagen2026-09-08 08:24 UTC763
#[derive(Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC764
pub struct EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC765
    events: mpsc::Receiver<Event>,
96fdf90aacd6atagen2026-09-08 08:24 UTC766
}
96fdf90aacd6atagen2026-09-08 08:24 UTC767
96fdf90aacd6atagen2026-09-08 08:24 UTC768
impl EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC769
    pub async fn recv(&mut self) -> Option<Event> {
96fdf90aacd6atagen2026-09-08 08:24 UTC770
        self.events.recv().await
96fdf90aacd6atagen2026-09-08 08:24 UTC771
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC772
96fdf90aacd6atagen2026-09-08 08:24 UTC773
    pub fn try_recv(&mut self) -> Result<Event, mpsc::error::TryRecvError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC774
        self.events.try_recv()
96fdf90aacd6atagen2026-09-08 08:24 UTC775
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC776
}
96fdf90aacd6atagen2026-09-08 08:24 UTC777
96fdf90aacd6atagen2026-09-08 08:24 UTC778
impl futures_util::Stream for EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC779
    type Item = Event;
96fdf90aacd6atagen2026-09-08 08:24 UTC780
96fdf90aacd6atagen2026-09-08 08:24 UTC781
    fn poll_next(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
96fdf90aacd6atagen2026-09-08 08:24 UTC782
        self.events.poll_recv(context)
96fdf90aacd6atagen2026-09-08 08:24 UTC783
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC784
}
96fdf90aacd6atagen2026-09-08 08:24 UTC785
96fdf90aacd6atagen2026-09-08 08:24 UTC786
#[derive(Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC787
pub(crate) struct DriverPort {
96fdf90aacd6atagen2026-09-08 08:24 UTC788
    commands: mpsc::Receiver<DriverRequest>,
96fdf90aacd6atagen2026-09-08 08:24 UTC789
    events: mpsc::Sender<Event>,
96fdf90aacd6atagen2026-09-08 08:24 UTC790
    connection: watch::Sender<ConnectionState>,
96fdf90aacd6atagen2026-09-08 08:24 UTC791
}
96fdf90aacd6atagen2026-09-08 08:24 UTC792
96fdf90aacd6atagen2026-09-08 08:24 UTC793
#[derive(Clone, Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC794
pub(crate) struct EventSender(mpsc::Sender<Event>);
96fdf90aacd6atagen2026-09-08 08:24 UTC795
96fdf90aacd6atagen2026-09-08 08:24 UTC796
impl EventSender {
96fdf90aacd6atagen2026-09-08 08:24 UTC797
    pub(crate) async fn send(&self, event: Event) -> Result<(), SendEventError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC798
        self.0.send(event).await.map_err(|_| SendEventError::Closed)
96fdf90aacd6atagen2026-09-08 08:24 UTC799
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC800
96fdf90aacd6atagen2026-09-08 08:24 UTC801
    /// Resolves once every [`EventStream`] receiver has been dropped, so the
96fdf90aacd6atagen2026-09-08 08:24 UTC802
    /// engine can notice a lost event consumer inside a `select!`.
96fdf90aacd6atagen2026-09-08 08:24 UTC803
    pub(crate) async fn closed(&self) {
96fdf90aacd6atagen2026-09-08 08:24 UTC804
        self.0.closed().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC805
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC806
}
96fdf90aacd6atagen2026-09-08 08:24 UTC807
96fdf90aacd6atagen2026-09-08 08:24 UTC808
impl DriverPort {
96fdf90aacd6atagen2026-09-08 08:24 UTC809
    pub(crate) fn event_sender(&self) -> EventSender {
96fdf90aacd6atagen2026-09-08 08:24 UTC810
        EventSender(self.events.clone())
96fdf90aacd6atagen2026-09-08 08:24 UTC811
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC812
96fdf90aacd6atagen2026-09-08 08:24 UTC813
    pub(crate) fn connection_sender(&self) -> watch::Sender<ConnectionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC814
        self.connection.clone()
96fdf90aacd6atagen2026-09-08 08:24 UTC815
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC816
96fdf90aacd6atagen2026-09-08 08:24 UTC817
    pub async fn recv(&mut self) -> Option<DriverRequest> {
96fdf90aacd6atagen2026-09-08 08:24 UTC818
        self.commands.recv().await
96fdf90aacd6atagen2026-09-08 08:24 UTC819
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC820
96fdf90aacd6atagen2026-09-08 08:24 UTC821
    pub async fn send(&self, event: Event) -> Result<(), SendEventError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC822
        self.event_sender().send(event).await
96fdf90aacd6atagen2026-09-08 08:24 UTC823
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC824
}
96fdf90aacd6atagen2026-09-08 08:24 UTC825
96fdf90aacd6atagen2026-09-08 08:24 UTC826
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
96fdf90aacd6atagen2026-09-08 08:24 UTC827
pub enum SendCommandError {
96fdf90aacd6atagen2026-09-08 08:24 UTC828
    #[error("the command channel is full")]
96fdf90aacd6atagen2026-09-08 08:24 UTC829
    Full,
96fdf90aacd6atagen2026-09-08 08:24 UTC830
    #[error("the engine has stopped")]
96fdf90aacd6atagen2026-09-08 08:24 UTC831
    Closed,
96fdf90aacd6atagen2026-09-08 08:24 UTC832
}
96fdf90aacd6atagen2026-09-08 08:24 UTC833
96fdf90aacd6atagen2026-09-08 08:24 UTC834
#[derive(Debug, Error)]
96fdf90aacd6atagen2026-09-08 08:24 UTC835
pub enum CommandResultError {
96fdf90aacd6atagen2026-09-08 08:24 UTC836
    #[error(transparent)]
96fdf90aacd6atagen2026-09-08 08:24 UTC837
    Send(#[from] SendCommandError),
96fdf90aacd6atagen2026-09-08 08:24 UTC838
    #[error("the engine stopped before the operation completed")]
96fdf90aacd6atagen2026-09-08 08:24 UTC839
    Closed,
96fdf90aacd6atagen2026-09-08 08:24 UTC840
    #[error("{0:?}")]
96fdf90aacd6atagen2026-09-08 08:24 UTC841
    Failed(crate::CommandFailure),
96fdf90aacd6atagen2026-09-08 08:24 UTC842
}
96fdf90aacd6atagen2026-09-08 08:24 UTC843
96fdf90aacd6atagen2026-09-08 08:24 UTC844
#[derive(Debug, Error)]
96fdf90aacd6atagen2026-09-08 08:24 UTC845
pub enum ClientQueryError {
96fdf90aacd6atagen2026-09-08 08:24 UTC846
    #[error("room {0} is not available in the local store")]
96fdf90aacd6atagen2026-09-08 08:24 UTC847
    RoomUnknown(ruma::OwnedRoomId),
96fdf90aacd6atagen2026-09-08 08:24 UTC848
    #[error("Matrix query failed")]
96fdf90aacd6atagen2026-09-08 08:24 UTC849
    Sdk(#[source] matrix_sdk::Error),
96fdf90aacd6atagen2026-09-08 08:24 UTC850
    #[error("reading the send queue failed")]
96fdf90aacd6atagen2026-09-08 08:24 UTC851
    SendQueue(#[source] matrix_sdk::send_queue::RoomSendQueueError),
96fdf90aacd6atagen2026-09-08 08:24 UTC852
    #[error("resolving the push notification failed")]
96fdf90aacd6atagen2026-09-08 08:24 UTC853
    Notification(#[source] matrix_sdk_ui::notification_client::Error),
96fdf90aacd6atagen2026-09-08 08:24 UTC854
    #[error("the engine stopped before the operation completed")]
96fdf90aacd6atagen2026-09-08 08:24 UTC855
    EngineStopped,
96fdf90aacd6atagen2026-09-08 08:24 UTC856
}
96fdf90aacd6atagen2026-09-08 08:24 UTC857
96fdf90aacd6atagen2026-09-08 08:24 UTC858
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
96fdf90aacd6atagen2026-09-08 08:24 UTC859
pub(crate) enum SendEventError {
96fdf90aacd6atagen2026-09-08 08:24 UTC860
    #[error("the event receiver has closed")]
96fdf90aacd6atagen2026-09-08 08:24 UTC861
    Closed,
96fdf90aacd6atagen2026-09-08 08:24 UTC862
}
96fdf90aacd6atagen2026-09-08 08:24 UTC863
96fdf90aacd6atagen2026-09-08 08:24 UTC864
#[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC865
pub(crate) fn transport_pair(
96fdf90aacd6atagen2026-09-08 08:24 UTC866
    client: Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC867
    sync_service: Arc<SyncService>,
96fdf90aacd6atagen2026-09-08 08:24 UTC868
    command_capacity: usize,
96fdf90aacd6atagen2026-09-08 08:24 UTC869
    event_capacity: usize,
96fdf90aacd6atagen2026-09-08 08:24 UTC870
) -> (ClientHandle, DriverPort, EventStream) {
96fdf90aacd6atagen2026-09-08 08:24 UTC871
    let (command_tx, command_rx) = mpsc::channel(command_capacity);
96fdf90aacd6atagen2026-09-08 08:24 UTC872
    let (event_tx, event_rx) = mpsc::channel(event_capacity);
96fdf90aacd6atagen2026-09-08 08:24 UTC873
    let (connection_tx, connection_rx) = watch::channel(ConnectionState::Idle);
96fdf90aacd6atagen2026-09-08 08:24 UTC874
    (
96fdf90aacd6atagen2026-09-08 08:24 UTC875
        ClientHandle {
96fdf90aacd6atagen2026-09-08 08:24 UTC876
            commands: command_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC877
            next_id: Arc::new(AtomicU64::new(1)),
96fdf90aacd6atagen2026-09-08 08:24 UTC878
            client,
96fdf90aacd6atagen2026-09-08 08:24 UTC879
            connection: connection_rx,
96fdf90aacd6atagen2026-09-08 08:24 UTC880
            notification_client: Arc::new(OnceCell::new()),
96fdf90aacd6atagen2026-09-08 08:24 UTC881
            sync_service,
96fdf90aacd6atagen2026-09-08 08:24 UTC882
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC883
        DriverPort {
96fdf90aacd6atagen2026-09-08 08:24 UTC884
            commands: command_rx,
96fdf90aacd6atagen2026-09-08 08:24 UTC885
            events: event_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC886
            connection: connection_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC887
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC888
        EventStream { events: event_rx },
96fdf90aacd6atagen2026-09-08 08:24 UTC889
    )
96fdf90aacd6atagen2026-09-08 08:24 UTC890
}
96fdf90aacd6atagen2026-09-08 08:24 UTC891
96fdf90aacd6atagen2026-09-08 08:24 UTC892
fn normalise_push_notification(
96fdf90aacd6atagen2026-09-08 08:24 UTC893
    room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC894
    event_id: &EventId,
96fdf90aacd6atagen2026-09-08 08:24 UTC895
    status: NotificationStatus,
96fdf90aacd6atagen2026-09-08 08:24 UTC896
) -> PushNotificationStatus {
96fdf90aacd6atagen2026-09-08 08:24 UTC897
    match status {
96fdf90aacd6atagen2026-09-08 08:24 UTC898
        NotificationStatus::Event(item) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC899
            let event = match &item.raw_event {
96fdf90aacd6atagen2026-09-08 08:24 UTC900
                RawNotificationEvent::Timeline(event) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC901
                    PushNotificationEvent::Timeline(event.clone())
96fdf90aacd6atagen2026-09-08 08:24 UTC902
                }
96fdf90aacd6atagen2026-09-08 08:24 UTC903
                RawNotificationEvent::Invite(event) => PushNotificationEvent::Invite(event.clone()),
96fdf90aacd6atagen2026-09-08 08:24 UTC904
            };
96fdf90aacd6atagen2026-09-08 08:24 UTC905
            PushNotificationStatus::Event(Box::new(PushNotification {
96fdf90aacd6atagen2026-09-08 08:24 UTC906
                event_id: event_id.to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC907
                event,
96fdf90aacd6atagen2026-09-08 08:24 UTC908
                sender: PushNotificationSender {
96fdf90aacd6atagen2026-09-08 08:24 UTC909
                    user_id: item.event.sender().to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC910
                    display_name: item.sender_display_name,
96fdf90aacd6atagen2026-09-08 08:24 UTC911
                    avatar_url: item.sender_avatar_url.map(Into::into),
96fdf90aacd6atagen2026-09-08 08:24 UTC912
                    name_ambiguous: item.is_sender_name_ambiguous,
96fdf90aacd6atagen2026-09-08 08:24 UTC913
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC914
                room: PushNotificationRoom {
96fdf90aacd6atagen2026-09-08 08:24 UTC915
                    room_id: room_id.to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC916
                    name: item.room_computed_display_name,
96fdf90aacd6atagen2026-09-08 08:24 UTC917
                    avatar_url: item.room_avatar_url.map(Into::into),
96fdf90aacd6atagen2026-09-08 08:24 UTC918
                    canonical_alias: item
96fdf90aacd6atagen2026-09-08 08:24 UTC919
                        .room_canonical_alias
96fdf90aacd6atagen2026-09-08 08:24 UTC920
                        .as_deref()
96fdf90aacd6atagen2026-09-08 08:24 UTC921
                        .and_then(|alias| alias.parse().ok()),
96fdf90aacd6atagen2026-09-08 08:24 UTC922
                    topic: item.room_topic,
96fdf90aacd6atagen2026-09-08 08:24 UTC923
                    encrypted: item.is_room_encrypted,
96fdf90aacd6atagen2026-09-08 08:24 UTC924
                    direct: item.room_is_dm,
96fdf90aacd6atagen2026-09-08 08:24 UTC925
                    joined_members_count: item.joined_members_count,
96fdf90aacd6atagen2026-09-08 08:24 UTC926
                    service_members: item
96fdf90aacd6atagen2026-09-08 08:24 UTC927
                        .service_members
96fdf90aacd6atagen2026-09-08 08:24 UTC928
                        .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC929
                        .filter_map(|user_id| user_id.parse().ok())
96fdf90aacd6atagen2026-09-08 08:24 UTC930
                        .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC931
                    active_service_members_count: item.active_service_members_count,
96fdf90aacd6atagen2026-09-08 08:24 UTC932
                    space: item.is_space,
96fdf90aacd6atagen2026-09-08 08:24 UTC933
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC934
                noisy: item.is_noisy,
96fdf90aacd6atagen2026-09-08 08:24 UTC935
                has_mention: item.has_mention,
96fdf90aacd6atagen2026-09-08 08:24 UTC936
                thread_id: item.thread_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC937
            }))
96fdf90aacd6atagen2026-09-08 08:24 UTC938
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC939
        NotificationStatus::EventNotFound => PushNotificationStatus::NotFound,
96fdf90aacd6atagen2026-09-08 08:24 UTC940
        NotificationStatus::EventFilteredOut => PushNotificationStatus::FilteredOut,
96fdf90aacd6atagen2026-09-08 08:24 UTC941
        NotificationStatus::EventRedacted => PushNotificationStatus::Redacted,
96fdf90aacd6atagen2026-09-08 08:24 UTC942
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC943
}
96fdf90aacd6atagen2026-09-08 08:24 UTC944
96fdf90aacd6atagen2026-09-08 08:24 UTC945
#[cfg(test)]
96fdf90aacd6atagen2026-09-08 08:24 UTC946
mod tests {
96fdf90aacd6atagen2026-09-08 08:24 UTC947
    use matrix_sdk::{Client, SessionMeta, SessionTokens, authentication::matrix::MatrixSession};
96fdf90aacd6atagen2026-09-08 08:24 UTC948
96fdf90aacd6atagen2026-09-08 08:24 UTC949
    use crate::{ConnectionState, LifecycleCommand};
96fdf90aacd6atagen2026-09-08 08:24 UTC950
96fdf90aacd6atagen2026-09-08 08:24 UTC951
    use super::*;
96fdf90aacd6atagen2026-09-08 08:24 UTC952
96fdf90aacd6atagen2026-09-08 08:24 UTC953
    async fn sync_service(client: Client) -> Arc<SyncService> {
96fdf90aacd6atagen2026-09-08 08:24 UTC954
        Arc::new(SyncService::builder(client).build().await.unwrap())
96fdf90aacd6atagen2026-09-08 08:24 UTC955
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC956
96fdf90aacd6atagen2026-09-08 08:24 UTC957
    async fn test_client() -> Client {
96fdf90aacd6atagen2026-09-08 08:24 UTC958
        let client = Client::builder()
96fdf90aacd6atagen2026-09-08 08:24 UTC959
            .homeserver_url("http://localhost")
96fdf90aacd6atagen2026-09-08 08:24 UTC960
            .build()
96fdf90aacd6atagen2026-09-08 08:24 UTC961
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC962
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC963
        client
96fdf90aacd6atagen2026-09-08 08:24 UTC964
            .restore_session(MatrixSession {
96fdf90aacd6atagen2026-09-08 08:24 UTC965
                meta: SessionMeta {
96fdf90aacd6atagen2026-09-08 08:24 UTC966
                    user_id: "@test:localhost".parse().unwrap(),
96fdf90aacd6atagen2026-09-08 08:24 UTC967
                    device_id: "DEVICE".into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC968
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC969
                tokens: SessionTokens {
96fdf90aacd6atagen2026-09-08 08:24 UTC970
                    access_token: "access_token".to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC971
                    refresh_token: None,
96fdf90aacd6atagen2026-09-08 08:24 UTC972
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC973
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC974
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC975
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC976
        client
96fdf90aacd6atagen2026-09-08 08:24 UTC977
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC978
96fdf90aacd6atagen2026-09-08 08:24 UTC979
    #[tokio::test]
96fdf90aacd6atagen2026-09-08 08:24 UTC980
    async fn transports_are_isolated() {
96fdf90aacd6atagen2026-09-08 08:24 UTC981
        let first_client = test_client().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC982
        let second_client = test_client().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC983
        let (first_handle, mut first_driver, mut first_events) =
96fdf90aacd6atagen2026-09-08 08:24 UTC984
            transport_pair(first_client.clone(), sync_service(first_client).await, 2, 2);
96fdf90aacd6atagen2026-09-08 08:24 UTC985
        let (_second_handle, mut second_driver, mut second_events) = transport_pair(
96fdf90aacd6atagen2026-09-08 08:24 UTC986
            second_client.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC987
            sync_service(second_client).await,
96fdf90aacd6atagen2026-09-08 08:24 UTC988
            2,
96fdf90aacd6atagen2026-09-08 08:24 UTC989
            2,
96fdf90aacd6atagen2026-09-08 08:24 UTC990
        );
96fdf90aacd6atagen2026-09-08 08:24 UTC991
96fdf90aacd6atagen2026-09-08 08:24 UTC992
        let id = first_handle
96fdf90aacd6atagen2026-09-08 08:24 UTC993
            .send(Command::Lifecycle(LifecycleCommand::Shutdown))
96fdf90aacd6atagen2026-09-08 08:24 UTC994
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC995
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC996
        let request = first_driver.recv().await.unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC997
        assert!(matches!(
96fdf90aacd6atagen2026-09-08 08:24 UTC998
            request,
96fdf90aacd6atagen2026-09-08 08:24 UTC999
            DriverRequest::Command(CommandEnvelope {
96fdf90aacd6atagen2026-09-08 08:24 UTC1000
                id: received_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC1001
                command: Command::Lifecycle(LifecycleCommand::Shutdown),
96fdf90aacd6atagen2026-09-08 08:24 UTC1002
            }) if received_id == id
96fdf90aacd6atagen2026-09-08 08:24 UTC1003
        ));
96fdf90aacd6atagen2026-09-08 08:24 UTC1004
        assert!(second_driver.commands.try_recv().is_err());
96fdf90aacd6atagen2026-09-08 08:24 UTC1005
96fdf90aacd6atagen2026-09-08 08:24 UTC1006
        first_driver
96fdf90aacd6atagen2026-09-08 08:24 UTC1007
            .send(Event::ConnectionChanged(ConnectionState::Online))
96fdf90aacd6atagen2026-09-08 08:24 UTC1008
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC1009
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC1010
        assert_eq!(
96fdf90aacd6atagen2026-09-08 08:24 UTC1011
            first_events.recv().await,
96fdf90aacd6atagen2026-09-08 08:24 UTC1012
            Some(Event::ConnectionChanged(ConnectionState::Online))
96fdf90aacd6atagen2026-09-08 08:24 UTC1013
        );
96fdf90aacd6atagen2026-09-08 08:24 UTC1014
        assert!(second_events.try_recv().is_err());
96fdf90aacd6atagen2026-09-08 08:24 UTC1015
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1016
96fdf90aacd6atagen2026-09-08 08:24 UTC1017
    #[tokio::test]
96fdf90aacd6atagen2026-09-08 08:24 UTC1018
    async fn bounded_command_channel_reports_pressure() {
96fdf90aacd6atagen2026-09-08 08:24 UTC1019
        let client = test_client().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC1020
        let (handle, _driver, _events) =
96fdf90aacd6atagen2026-09-08 08:24 UTC1021
            transport_pair(client.clone(), sync_service(client).await, 1, 1);
96fdf90aacd6atagen2026-09-08 08:24 UTC1022
96fdf90aacd6atagen2026-09-08 08:24 UTC1023
        handle
96fdf90aacd6atagen2026-09-08 08:24 UTC1024
            .try_send(Command::Lifecycle(LifecycleCommand::Shutdown))
96fdf90aacd6atagen2026-09-08 08:24 UTC1025
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC1026
        assert_eq!(
96fdf90aacd6atagen2026-09-08 08:24 UTC1027
            handle.try_send(Command::Lifecycle(LifecycleCommand::Shutdown)),
96fdf90aacd6atagen2026-09-08 08:24 UTC1028
            Err(SendCommandError::Full)
96fdf90aacd6atagen2026-09-08 08:24 UTC1029
        );
96fdf90aacd6atagen2026-09-08 08:24 UTC1030
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1031
96fdf90aacd6atagen2026-09-08 08:24 UTC1032
    #[tokio::test]
96fdf90aacd6atagen2026-09-08 08:24 UTC1033
    async fn cloned_handles_share_command_id_sequence() {
96fdf90aacd6atagen2026-09-08 08:24 UTC1034
        let client = test_client().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC1035
        let (handle, mut driver, _events) =
96fdf90aacd6atagen2026-09-08 08:24 UTC1036
            transport_pair(client.clone(), sync_service(client).await, 1, 1);
96fdf90aacd6atagen2026-09-08 08:24 UTC1037
        let cloned = handle.clone();
96fdf90aacd6atagen2026-09-08 08:24 UTC1038
        let first = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC1039
            .try_send(Command::Lifecycle(LifecycleCommand::Shutdown))
96fdf90aacd6atagen2026-09-08 08:24 UTC1040
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC1041
        assert_eq!(first.get(), 1);
96fdf90aacd6atagen2026-09-08 08:24 UTC1042
        assert_eq!(
96fdf90aacd6atagen2026-09-08 08:24 UTC1043
            cloned.try_send(Command::Lifecycle(LifecycleCommand::Shutdown)),
96fdf90aacd6atagen2026-09-08 08:24 UTC1044
            Err(SendCommandError::Full)
96fdf90aacd6atagen2026-09-08 08:24 UTC1045
        );
96fdf90aacd6atagen2026-09-08 08:24 UTC1046
        driver.recv().await.unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC1047
96fdf90aacd6atagen2026-09-08 08:24 UTC1048
        let third = cloned
96fdf90aacd6atagen2026-09-08 08:24 UTC1049
            .send(Command::Lifecycle(LifecycleCommand::Shutdown))
96fdf90aacd6atagen2026-09-08 08:24 UTC1050
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC1051
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC1052
        assert_eq!(third.get(), 3);
96fdf90aacd6atagen2026-09-08 08:24 UTC1053
        driver.recv().await.unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC1054
96fdf90aacd6atagen2026-09-08 08:24 UTC1055
        let fourth = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC1056
            .try_send(Command::Lifecycle(LifecycleCommand::Shutdown))
96fdf90aacd6atagen2026-09-08 08:24 UTC1057
            .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC1058
        assert_eq!(fourth.get(), 4);
96fdf90aacd6atagen2026-09-08 08:24 UTC1059
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1060
}