atagen

macltok

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

Blame: src/transport.rs

96fdf90aacd6atagen2026-09-08 08:24 UTC1
use std::{
121a56ce119datagen2026-10-24 06:42 UTC2
    collections::HashSet,
96fdf90aacd6atagen2026-09-08 08:24 UTC3
    fmt,
31ce2453c82fatagen2026-09-24 13:07 UTC4
    future::Future,
96fdf90aacd6atagen2026-09-08 08:24 UTC5
    pin::Pin,
80381e06a573atagen2026-10-25 03:02 UTC6
    sync::{Arc, Mutex, Weak},
96fdf90aacd6atagen2026-09-08 08:24 UTC7
    task::{Context, Poll},
96fdf90aacd6atagen2026-09-08 08:24 UTC8
};
96fdf90aacd6atagen2026-09-08 08:24 UTC9
96fdf90aacd6atagen2026-09-08 08:24 UTC10
use matrix_sdk::{Client, RoomMemberships};
96fdf90aacd6atagen2026-09-08 08:24 UTC11
use matrix_sdk_ui::{
96fdf90aacd6atagen2026-09-08 08:24 UTC12
    notification_client::{
96fdf90aacd6atagen2026-09-08 08:24 UTC13
        NotificationClient, NotificationProcessSetup, NotificationStatus, RawNotificationEvent,
96fdf90aacd6atagen2026-09-08 08:24 UTC14
    },
31ce2453c82fatagen2026-09-24 13:07 UTC15
    spaces::{SpaceRoomList, SpaceService, room_list::SpaceRoomListPaginationState},
96fdf90aacd6atagen2026-09-08 08:24 UTC16
    sync_service::SyncService,
96fdf90aacd6atagen2026-09-08 08:24 UTC17
};
96fdf90aacd6atagen2026-09-08 08:24 UTC18
use ruma::{
5d2974de5826atagen2026-10-08 11:29 UTC19
    EventId, OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedRoomOrAliasId,
31ce2453c82fatagen2026-09-24 13:07 UTC20
    OwnedServerName, OwnedTransactionId, OwnedUserId, RoomId, UserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC21
    events::{
31ce2453c82fatagen2026-09-24 13:07 UTC22
        AnyGlobalAccountDataEventContent, AnyRoomAccountDataEvent, AnyRoomAccountDataEventContent,
31ce2453c82fatagen2026-09-24 13:07 UTC23
        GlobalAccountDataEventType, RoomAccountDataEventType,
96fdf90aacd6atagen2026-09-08 08:24 UTC24
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC25
    serde::Raw,
96fdf90aacd6atagen2026-09-08 08:24 UTC26
};
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::{
31ce2453c82fatagen2026-09-24 13:07 UTC30
    AccountCommand, AttachmentUpload, Command, CommandOutput, ConnectionState, CreateRoomOptions,
da8896938cf0atagen2026-10-25 10:04 UTC31
    EncryptionCommand, EncryptionState, Error, ErrorKind, Event, EventContextCommand,
2006a11ce142atagen2026-10-26 04:02 UTC32
    EventContextPage, EventContextSession, EventRef, HistoryRepairCommand, HttpPusher,
2006a11ce142atagen2026-10-26 04:02 UTC33
    ImagePackSource, ImagePacks, InteractiveAuth, InteractiveAuthOutcome, LifecycleCommand,
2006a11ce142atagen2026-10-26 04:02 UTC34
    LinkPreview, Media, MediaCommand, MediaId, MediaLocation, MediaSize, MemberFilter,
2006a11ce142atagen2026-10-26 04:02 UTC35
    MemberSummary, MentionKey, MentionsBoundary, MentionsCommand, MentionsPage, MessageContent,
2006a11ce142atagen2026-10-26 04:02 UTC36
    MessageEditContent, NotificationCommand, OwnDevice, PackCommand, PackImageInfo, PackUsage,
2006a11ce142atagen2026-10-26 04:02 UTC37
    Patch, PowerLevelChanges, Profile, PushFormat, PushNotification, PushNotificationEvent,
2006a11ce142atagen2026-10-26 04:02 UTC38
    PushNotificationStatus, PusherKey, RecoveryKey, RoomCommand, RoomListFilter,
2006a11ce142atagen2026-10-26 04:02 UTC39
    RoomNotificationMode, RoomNotificationSettings, RoomPowerLevels, RoomSummary,
2006a11ce142atagen2026-10-26 04:02 UTC40
    SavedMentionContext, SearchCommand, SearchCoverage, SearchPage, SearchScope, SearchSession,
2006a11ce142atagen2026-10-26 04:02 UTC41
    SpaceChild, ThreadListCommand, TimelineCommand, TimelineId, VerificationAction,
2006a11ce142atagen2026-10-26 04:02 UTC42
    VerificationTarget,
96fdf90aacd6atagen2026-09-08 08:24 UTC43
    encryption::encryption_state,
a250c7fa43fbatagen2026-09-26 13:35 UTC44
    engine::{MediaService, StoreLock},
96fdf90aacd6atagen2026-09-08 08:24 UTC45
    model::{PushNotificationRoom, PushNotificationSender},
0291516d40b5atagen2026-10-22 08:31 UTC46
    normalise::{image_packs, member_summary, room_summaries, space_child, url_previews_allowed},
96fdf90aacd6atagen2026-09-08 08:24 UTC47
};
96fdf90aacd6atagen2026-09-08 08:24 UTC48
96fdf90aacd6atagen2026-09-08 08:24 UTC49
#[derive(Clone)]
96fdf90aacd6atagen2026-09-08 08:24 UTC50
pub struct ClientHandle {
31ce2453c82fatagen2026-09-24 13:07 UTC51
    requests: mpsc::Sender<Request>,
96fdf90aacd6atagen2026-09-08 08:24 UTC52
    client: Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC53
    connection: watch::Receiver<ConnectionState>,
96fdf90aacd6atagen2026-09-08 08:24 UTC54
    notification_client: Arc<OnceCell<NotificationClient>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC55
    sync_service: Arc<SyncService>,
31ce2453c82fatagen2026-09-24 13:07 UTC56
    media: Arc<MediaService>,
31ce2453c82fatagen2026-09-24 13:07 UTC57
    spaces: Arc<OnceCell<SpaceService>>,
121a56ce119datagen2026-10-24 06:42 UTC58
    members_checked: Arc<Mutex<HashSet<OwnedRoomId>>>,
80381e06a573atagen2026-10-25 03:02 UTC59
    publication: Arc<PublicationRegistry>,
a250c7fa43fbatagen2026-09-26 13:35 UTC60
    _store_lock: Option<Arc<StoreLock>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC61
}
96fdf90aacd6atagen2026-09-08 08:24 UTC62
96fdf90aacd6atagen2026-09-08 08:24 UTC63
impl fmt::Debug for ClientHandle {
96fdf90aacd6atagen2026-09-08 08:24 UTC64
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
96fdf90aacd6atagen2026-09-08 08:24 UTC65
        formatter
96fdf90aacd6atagen2026-09-08 08:24 UTC66
            .debug_struct("ClientHandle")
96fdf90aacd6atagen2026-09-08 08:24 UTC67
            .finish_non_exhaustive()
96fdf90aacd6atagen2026-09-08 08:24 UTC68
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC69
}
96fdf90aacd6atagen2026-09-08 08:24 UTC70
31ce2453c82fatagen2026-09-24 13:07 UTC71
/// a command's answer. drop it if you don't care, the command still runs
31ce2453c82fatagen2026-09-24 13:07 UTC72
#[derive(Debug)]
31ce2453c82fatagen2026-09-24 13:07 UTC73
#[must_use = "dropping it is fine but then you'll never know"]
31ce2453c82fatagen2026-09-24 13:07 UTC74
pub struct Pending(oneshot::Receiver<Result<CommandOutput, Error>>);
31ce2453c82fatagen2026-09-24 13:07 UTC75
31ce2453c82fatagen2026-09-24 13:07 UTC76
impl Future for Pending {
31ce2453c82fatagen2026-09-24 13:07 UTC77
    type Output = Result<CommandOutput, Error>;
31ce2453c82fatagen2026-09-24 13:07 UTC78
31ce2453c82fatagen2026-09-24 13:07 UTC79
    fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
31ce2453c82fatagen2026-09-24 13:07 UTC80
        Pin::new(&mut self.0)
31ce2453c82fatagen2026-09-24 13:07 UTC81
            .poll(context)
31ce2453c82fatagen2026-09-24 13:07 UTC82
            .map(|result| result.unwrap_or_else(|_| Err(Error::interrupted())))
31ce2453c82fatagen2026-09-24 13:07 UTC83
    }
31ce2453c82fatagen2026-09-24 13:07 UTC84
}
31ce2453c82fatagen2026-09-24 13:07 UTC85
96fdf90aacd6atagen2026-09-08 08:24 UTC86
impl ClientHandle {
80381e06a573atagen2026-10-25 03:02 UTC87
    pub(crate) fn register_publication_mirror(&self) -> PublicationRegistration {
80381e06a573atagen2026-10-25 03:02 UTC88
        self.publication.register_mirror()
80381e06a573atagen2026-10-25 03:02 UTC89
    }
80381e06a573atagen2026-10-25 03:02 UTC90
f12377bce9b9atagen2026-09-26 12:32 UTC91
    /// current credentials, it holds secrets. the engine saves it for you unless the
f12377bce9b9atagen2026-09-26 12:32 UTC92
    /// session was built `without_persistence`
62fe32759529atagen2026-09-26 08:50 UTC93
    #[cfg(any(feature = "sqlite", feature = "indexeddb"))]
96fdf90aacd6atagen2026-09-08 08:24 UTC94
    pub fn session_record(&self) -> Result<crate::SessionRecord, crate::AccountError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC95
        crate::account::session_record(&self.client)
96fdf90aacd6atagen2026-09-08 08:24 UTC96
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC97
5b21b919d1e6atagen2026-09-27 11:47 UTC98
    /// the bearer token. it rotates on every refresh so ask again after a 401 rather than
5b21b919d1e6atagen2026-09-27 11:47 UTC99
    /// keeping it, and keep it in memory and away from all but the homeserver's media endpoints
5b21b919d1e6atagen2026-09-27 11:47 UTC100
    pub fn access_token(&self) -> Option<String> {
5b21b919d1e6atagen2026-09-27 11:47 UTC101
        self.client.access_token()
5b21b919d1e6atagen2026-09-27 11:47 UTC102
    }
5b21b919d1e6atagen2026-09-27 11:47 UTC103
31ce2453c82fatagen2026-09-24 13:07 UTC104
    /// queue a command, waiting for room in the queue if there isn't any
31ce2453c82fatagen2026-09-24 13:07 UTC105
    pub async fn send(&self, command: Command) -> Result<Pending, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC106
        let (request, pending) = Request::new(command);
31ce2453c82fatagen2026-09-24 13:07 UTC107
        self.requests
31ce2453c82fatagen2026-09-24 13:07 UTC108
            .send(request)
96fdf90aacd6atagen2026-09-08 08:24 UTC109
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC110
            .map_err(|_| Error::interrupted())?;
31ce2453c82fatagen2026-09-24 13:07 UTC111
        Ok(pending)
31ce2453c82fatagen2026-09-24 13:07 UTC112
    }
31ce2453c82fatagen2026-09-24 13:07 UTC113
31ce2453c82fatagen2026-09-24 13:07 UTC114
    /// queue a command or fail with `QueueFull` right now
31ce2453c82fatagen2026-09-24 13:07 UTC115
    pub fn try_send(&self, command: Command) -> Result<Pending, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC116
        let (request, pending) = Request::new(command);
31ce2453c82fatagen2026-09-24 13:07 UTC117
        self.requests
31ce2453c82fatagen2026-09-24 13:07 UTC118
            .try_send(request)
31ce2453c82fatagen2026-09-24 13:07 UTC119
            .map_err(|error| match error {
31ce2453c82fatagen2026-09-24 13:07 UTC120
                mpsc::error::TrySendError::Full(_) => {
31ce2453c82fatagen2026-09-24 13:07 UTC121
                    Error::new(ErrorKind::QueueFull, "the command queue is full")
31ce2453c82fatagen2026-09-24 13:07 UTC122
                }
31ce2453c82fatagen2026-09-24 13:07 UTC123
                mpsc::error::TrySendError::Closed(_) => Error::interrupted(),
31ce2453c82fatagen2026-09-24 13:07 UTC124
            })?;
31ce2453c82fatagen2026-09-24 13:07 UTC125
        Ok(pending)
31ce2453c82fatagen2026-09-24 13:07 UTC126
    }
31ce2453c82fatagen2026-09-24 13:07 UTC127
31ce2453c82fatagen2026-09-24 13:07 UTC128
    /// queue a command and wait for its answer. timeline sends answer once the
31ce2453c82fatagen2026-09-24 13:07 UTC129
    /// sdk send queue has them, delivery shows up later as the item's send state
31ce2453c82fatagen2026-09-24 13:07 UTC130
    pub async fn execute(&self, command: Command) -> Result<CommandOutput, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC131
        self.send(command).await?.await
31ce2453c82fatagen2026-09-24 13:07 UTC132
    }
31ce2453c82fatagen2026-09-24 13:07 UTC133
31ce2453c82fatagen2026-09-24 13:07 UTC134
    async fn run(&self, command: Command) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC135
        self.execute(command).await.map(drop)
31ce2453c82fatagen2026-09-24 13:07 UTC136
    }
31ce2453c82fatagen2026-09-24 13:07 UTC137
31ce2453c82fatagen2026-09-24 13:07 UTC138
    async fn run_for_room(&self, command: RoomCommand) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC139
        match self.execute(Command::Room(command)).await? {
31ce2453c82fatagen2026-09-24 13:07 UTC140
            CommandOutput::Room(room_id) => Ok(room_id),
31ce2453c82fatagen2026-09-24 13:07 UTC141
            output => Err(Error::new(
31ce2453c82fatagen2026-09-24 13:07 UTC142
                ErrorKind::Other,
31ce2453c82fatagen2026-09-24 13:07 UTC143
                format!("expected a room but got {output:?}"),
31ce2453c82fatagen2026-09-24 13:07 UTC144
            )),
31ce2453c82fatagen2026-09-24 13:07 UTC145
        }
31ce2453c82fatagen2026-09-24 13:07 UTC146
    }
31ce2453c82fatagen2026-09-24 13:07 UTC147
31ce2453c82fatagen2026-09-24 13:07 UTC148
    pub async fn shutdown(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC149
        self.run(Command::Lifecycle(LifecycleCommand::Shutdown))
31ce2453c82fatagen2026-09-24 13:07 UTC150
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC151
    }
31ce2453c82fatagen2026-09-24 13:07 UTC152
2006a11ce142atagen2026-10-26 04:02 UTC153
    pub async fn logout(&self, remove_pushers: Vec<PusherKey>) -> Result<(), Error> {
2006a11ce142atagen2026-10-26 04:02 UTC154
        self.run(Command::Account(AccountCommand::Logout { remove_pushers }))
2006a11ce142atagen2026-10-26 04:02 UTC155
            .await
2006a11ce142atagen2026-10-26 04:02 UTC156
    }
2006a11ce142atagen2026-10-26 04:02 UTC157
2006a11ce142atagen2026-10-26 04:02 UTC158
    /// replaces any pusher with the same app id and pushkey
2006a11ce142atagen2026-10-26 04:02 UTC159
    pub async fn set_pusher(&self, pusher: HttpPusher) -> Result<(), Error> {
2006a11ce142atagen2026-10-26 04:02 UTC160
        use ruma::{
2006a11ce142atagen2026-10-26 04:02 UTC161
            api::client::push::{PusherIds, PusherInit, PusherKind},
2006a11ce142atagen2026-10-26 04:02 UTC162
            push::{HttpPusherData, PushFormat as SdkFormat},
2006a11ce142atagen2026-10-26 04:02 UTC163
        };
2006a11ce142atagen2026-10-26 04:02 UTC164
        let mut data = HttpPusherData::new(pusher.url);
2006a11ce142atagen2026-10-26 04:02 UTC165
        data.format = match pusher.format {
2006a11ce142atagen2026-10-26 04:02 UTC166
            PushFormat::Full => None,
2006a11ce142atagen2026-10-26 04:02 UTC167
            PushFormat::EventIdOnly => Some(SdkFormat::EventIdOnly),
2006a11ce142atagen2026-10-26 04:02 UTC168
        };
2006a11ce142atagen2026-10-26 04:02 UTC169
        data.data = pusher.data;
2006a11ce142atagen2026-10-26 04:02 UTC170
        let pusher = PusherInit {
2006a11ce142atagen2026-10-26 04:02 UTC171
            ids: PusherIds::new(pusher.pushkey, pusher.app_id),
2006a11ce142atagen2026-10-26 04:02 UTC172
            kind: PusherKind::Http(data),
2006a11ce142atagen2026-10-26 04:02 UTC173
            app_display_name: pusher.app_display_name,
2006a11ce142atagen2026-10-26 04:02 UTC174
            device_display_name: pusher.device_display_name,
2006a11ce142atagen2026-10-26 04:02 UTC175
            profile_tag: None,
2006a11ce142atagen2026-10-26 04:02 UTC176
            lang: pusher.lang,
2006a11ce142atagen2026-10-26 04:02 UTC177
        };
2006a11ce142atagen2026-10-26 04:02 UTC178
        self.client
2006a11ce142atagen2026-10-26 04:02 UTC179
            .pusher()
2006a11ce142atagen2026-10-26 04:02 UTC180
            .set(pusher.into(), false)
2006a11ce142atagen2026-10-26 04:02 UTC181
            .await
2006a11ce142atagen2026-10-26 04:02 UTC182
            .map_err(|source| Error::from_sdk("setting the pusher failed", source))
2006a11ce142atagen2026-10-26 04:02 UTC183
    }
2006a11ce142atagen2026-10-26 04:02 UTC184
2006a11ce142atagen2026-10-26 04:02 UTC185
    pub async fn remove_pusher(&self, pusher: PusherKey) -> Result<(), Error> {
2006a11ce142atagen2026-10-26 04:02 UTC186
        remove_pusher(&self.client, pusher).await
2006a11ce142atagen2026-10-26 04:02 UTC187
    }
2006a11ce142atagen2026-10-26 04:02 UTC188
2006a11ce142atagen2026-10-26 04:02 UTC189
    /// the account's http pushers, every device's alike
2006a11ce142atagen2026-10-26 04:02 UTC190
    pub async fn pushers(&self) -> Result<Vec<HttpPusher>, Error> {
2006a11ce142atagen2026-10-26 04:02 UTC191
        use ruma::{
2006a11ce142atagen2026-10-26 04:02 UTC192
            api::client::push::{PusherKind, get_pushers},
2006a11ce142atagen2026-10-26 04:02 UTC193
            push::PushFormat as SdkFormat,
2006a11ce142atagen2026-10-26 04:02 UTC194
        };
2006a11ce142atagen2026-10-26 04:02 UTC195
        let response = self
2006a11ce142atagen2026-10-26 04:02 UTC196
            .client
2006a11ce142atagen2026-10-26 04:02 UTC197
            .send(get_pushers::v3::Request::new())
2006a11ce142atagen2026-10-26 04:02 UTC198
            .await
2006a11ce142atagen2026-10-26 04:02 UTC199
            .map_err(|source| Error::from_sdk("fetching pushers failed", source.into()))?;
2006a11ce142atagen2026-10-26 04:02 UTC200
        Ok(response
2006a11ce142atagen2026-10-26 04:02 UTC201
            .pushers
2006a11ce142atagen2026-10-26 04:02 UTC202
            .into_iter()
2006a11ce142atagen2026-10-26 04:02 UTC203
            .filter_map(|pusher| match pusher.kind {
2006a11ce142atagen2026-10-26 04:02 UTC204
                PusherKind::Http(data) => Some(HttpPusher {
2006a11ce142atagen2026-10-26 04:02 UTC205
                    app_id: pusher.ids.app_id,
2006a11ce142atagen2026-10-26 04:02 UTC206
                    pushkey: pusher.ids.pushkey,
2006a11ce142atagen2026-10-26 04:02 UTC207
                    app_display_name: pusher.app_display_name,
2006a11ce142atagen2026-10-26 04:02 UTC208
                    device_display_name: pusher.device_display_name,
2006a11ce142atagen2026-10-26 04:02 UTC209
                    lang: pusher.lang,
2006a11ce142atagen2026-10-26 04:02 UTC210
                    url: data.url,
2006a11ce142atagen2026-10-26 04:02 UTC211
                    format: match data.format {
2006a11ce142atagen2026-10-26 04:02 UTC212
                        Some(SdkFormat::EventIdOnly) => PushFormat::EventIdOnly,
2006a11ce142atagen2026-10-26 04:02 UTC213
                        _ => PushFormat::Full,
2006a11ce142atagen2026-10-26 04:02 UTC214
                    },
2006a11ce142atagen2026-10-26 04:02 UTC215
                    data: data.data,
2006a11ce142atagen2026-10-26 04:02 UTC216
                }),
2006a11ce142atagen2026-10-26 04:02 UTC217
                _ => None,
2006a11ce142atagen2026-10-26 04:02 UTC218
            })
2006a11ce142atagen2026-10-26 04:02 UTC219
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC220
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC221
96fdf90aacd6atagen2026-09-08 08:24 UTC222
    pub async fn delete_devices(
96fdf90aacd6atagen2026-09-08 08:24 UTC223
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC224
        device_ids: Vec<OwnedDeviceId>,
96fdf90aacd6atagen2026-09-08 08:24 UTC225
        auth: Option<InteractiveAuth>,
31ce2453c82fatagen2026-09-24 13:07 UTC226
    ) -> Result<InteractiveAuthOutcome, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC227
        match self
31ce2453c82fatagen2026-09-24 13:07 UTC228
            .run(Command::Account(AccountCommand::DeleteDevices {
96fdf90aacd6atagen2026-09-08 08:24 UTC229
                device_ids,
96fdf90aacd6atagen2026-09-08 08:24 UTC230
                auth,
31ce2453c82fatagen2026-09-24 13:07 UTC231
            }))
96fdf90aacd6atagen2026-09-08 08:24 UTC232
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC233
        {
31ce2453c82fatagen2026-09-24 13:07 UTC234
            Ok(()) => Ok(InteractiveAuthOutcome::Completed),
31ce2453c82fatagen2026-09-24 13:07 UTC235
            Err(Error {
31ce2453c82fatagen2026-09-24 13:07 UTC236
                challenge: Some(challenge),
31ce2453c82fatagen2026-09-24 13:07 UTC237
                ..
31ce2453c82fatagen2026-09-24 13:07 UTC238
            }) => Ok(InteractiveAuthOutcome::Challenge(*challenge)),
31ce2453c82fatagen2026-09-24 13:07 UTC239
            Err(error) => Err(error),
31ce2453c82fatagen2026-09-24 13:07 UTC240
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC241
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC242
96fdf90aacd6atagen2026-09-08 08:24 UTC243
    pub async fn rename_device(
96fdf90aacd6atagen2026-09-08 08:24 UTC244
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC245
        device_id: OwnedDeviceId,
96fdf90aacd6atagen2026-09-08 08:24 UTC246
        display_name: impl Into<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC247
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC248
        self.run(Command::Account(AccountCommand::RenameDevice {
96fdf90aacd6atagen2026-09-08 08:24 UTC249
            device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC250
            display_name: display_name.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC251
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC252
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC253
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC254
31ce2453c82fatagen2026-09-24 13:07 UTC255
    pub async fn set_global_account_data(
31ce2453c82fatagen2026-09-24 13:07 UTC256
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC257
        event_type: GlobalAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC258
        content: Raw<AnyGlobalAccountDataEventContent>,
31ce2453c82fatagen2026-09-24 13:07 UTC259
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC260
        self.run(Command::Account(AccountCommand::SetAccountData {
31ce2453c82fatagen2026-09-24 13:07 UTC261
            event_type,
31ce2453c82fatagen2026-09-24 13:07 UTC262
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC263
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC264
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC265
    }
31ce2453c82fatagen2026-09-24 13:07 UTC266
31ce2453c82fatagen2026-09-24 13:07 UTC267
    pub async fn set_room_account_data(
31ce2453c82fatagen2026-09-24 13:07 UTC268
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC269
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC270
        event_type: RoomAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC271
        content: Raw<AnyRoomAccountDataEventContent>,
31ce2453c82fatagen2026-09-24 13:07 UTC272
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC273
        self.run(Command::Room(RoomCommand::SetAccountData {
31ce2453c82fatagen2026-09-24 13:07 UTC274
            room_id,
31ce2453c82fatagen2026-09-24 13:07 UTC275
            event_type,
31ce2453c82fatagen2026-09-24 13:07 UTC276
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC277
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC278
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC279
    }
31ce2453c82fatagen2026-09-24 13:07 UTC280
96fdf90aacd6atagen2026-09-08 08:24 UTC281
    pub async fn set_room_notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC282
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC283
        room_id: OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC284
        mode: RoomNotificationMode,
31ce2453c82fatagen2026-09-24 13:07 UTC285
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC286
        self.run(Command::Notification(NotificationCommand::SetRoomMode {
96fdf90aacd6atagen2026-09-08 08:24 UTC287
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC288
            mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC289
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC290
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC291
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC292
31ce2453c82fatagen2026-09-24 13:07 UTC293
    pub async fn reset_room_notification_mode(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC294
        self.run(Command::Notification(NotificationCommand::ResetRoomMode(
96fdf90aacd6atagen2026-09-08 08:24 UTC295
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC296
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC297
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC298
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC299
96fdf90aacd6atagen2026-09-08 08:24 UTC300
    pub async fn set_default_notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC301
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC302
        encrypted: bool,
96fdf90aacd6atagen2026-09-08 08:24 UTC303
        one_to_one: bool,
96fdf90aacd6atagen2026-09-08 08:24 UTC304
        mode: RoomNotificationMode,
31ce2453c82fatagen2026-09-24 13:07 UTC305
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC306
        self.run(Command::Notification(NotificationCommand::SetDefaultMode {
96fdf90aacd6atagen2026-09-08 08:24 UTC307
            encrypted,
96fdf90aacd6atagen2026-09-08 08:24 UTC308
            one_to_one,
96fdf90aacd6atagen2026-09-08 08:24 UTC309
            mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC310
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC311
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC312
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC313
31ce2453c82fatagen2026-09-24 13:07 UTC314
    pub async fn add_notification_keyword(&self, keyword: impl Into<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC315
        self.run(Command::Notification(NotificationCommand::AddKeyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC316
            keyword.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC317
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC318
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC319
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC320
96fdf90aacd6atagen2026-09-08 08:24 UTC321
    pub async fn remove_notification_keyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC322
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC323
        keyword: impl Into<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC324
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC325
        self.run(Command::Notification(NotificationCommand::RemoveKeyword(
96fdf90aacd6atagen2026-09-08 08:24 UTC326
            keyword.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC327
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC328
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC329
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC330
31ce2453c82fatagen2026-09-24 13:07 UTC331
    pub async fn open_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC332
        self.run(Command::Room(RoomCommand::Open(room_id))).await
96fdf90aacd6atagen2026-09-08 08:24 UTC333
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC334
31ce2453c82fatagen2026-09-24 13:07 UTC335
    pub async fn close_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC336
        self.run(Command::Room(RoomCommand::Close(room_id))).await
96fdf90aacd6atagen2026-09-08 08:24 UTC337
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC338
96fdf90aacd6atagen2026-09-08 08:24 UTC339
    pub async fn open_thread(
96fdf90aacd6atagen2026-09-08 08:24 UTC340
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC341
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC342
        root_event_id: OwnedEventId,
31ce2453c82fatagen2026-09-24 13:07 UTC343
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC344
        self.run(Command::Timeline(TimelineCommand::OpenThread {
96fdf90aacd6atagen2026-09-08 08:24 UTC345
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC346
            root_event_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC347
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC348
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC349
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC350
96fdf90aacd6atagen2026-09-08 08:24 UTC351
    pub async fn close_thread(
96fdf90aacd6atagen2026-09-08 08:24 UTC352
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC353
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC354
        root_event_id: OwnedEventId,
31ce2453c82fatagen2026-09-24 13:07 UTC355
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC356
        self.run(Command::Timeline(TimelineCommand::CloseThread {
96fdf90aacd6atagen2026-09-08 08:24 UTC357
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC358
            root_event_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC359
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC360
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC361
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC362
fa5b4e09943aatagen2026-10-24 09:33 UTC363
    /// the room's pins as `TimelineId::Pinned`, kept current as they change. the room has to be open
fa5b4e09943aatagen2026-10-24 09:33 UTC364
    pub async fn open_pinned(&self, room_id: OwnedRoomId) -> Result<(), Error> {
fa5b4e09943aatagen2026-10-24 09:33 UTC365
        self.run(Command::Timeline(TimelineCommand::OpenPinned(room_id)))
fa5b4e09943aatagen2026-10-24 09:33 UTC366
            .await
fa5b4e09943aatagen2026-10-24 09:33 UTC367
    }
fa5b4e09943aatagen2026-10-24 09:33 UTC368
fa5b4e09943aatagen2026-10-24 09:33 UTC369
    pub async fn close_pinned(&self, room_id: OwnedRoomId) -> Result<(), Error> {
fa5b4e09943aatagen2026-10-24 09:33 UTC370
        self.run(Command::Timeline(TimelineCommand::ClosePinned(room_id)))
fa5b4e09943aatagen2026-10-24 09:33 UTC371
            .await
fa5b4e09943aatagen2026-10-24 09:33 UTC372
    }
fa5b4e09943aatagen2026-10-24 09:33 UTC373
66db1b3cd895atagen2026-10-25 10:28 UTC374
    /// the room's threads, newest activity first, kept current as they gain replies.
66db1b3cd895atagen2026-10-25 10:28 UTC375
    /// the room needn't be open. it starts empty, `paginate_thread_list` fills it
66db1b3cd895atagen2026-10-25 10:28 UTC376
    pub async fn open_thread_list(&self, room_id: OwnedRoomId) -> Result<(), Error> {
66db1b3cd895atagen2026-10-25 10:28 UTC377
        self.run(Command::ThreadList(ThreadListCommand::Open(room_id)))
66db1b3cd895atagen2026-10-25 10:28 UTC378
            .await
66db1b3cd895atagen2026-10-25 10:28 UTC379
    }
66db1b3cd895atagen2026-10-25 10:28 UTC380
66db1b3cd895atagen2026-10-25 10:28 UTC381
    pub async fn paginate_thread_list(
66db1b3cd895atagen2026-10-25 10:28 UTC382
        &self,
66db1b3cd895atagen2026-10-25 10:28 UTC383
        room_id: OwnedRoomId,
66db1b3cd895atagen2026-10-25 10:28 UTC384
        limit: u16,
66db1b3cd895atagen2026-10-25 10:28 UTC385
    ) -> Result<(), Error> {
66db1b3cd895atagen2026-10-25 10:28 UTC386
        self.run(Command::ThreadList(ThreadListCommand::Paginate {
66db1b3cd895atagen2026-10-25 10:28 UTC387
            room_id,
66db1b3cd895atagen2026-10-25 10:28 UTC388
            limit,
66db1b3cd895atagen2026-10-25 10:28 UTC389
        }))
66db1b3cd895atagen2026-10-25 10:28 UTC390
        .await
66db1b3cd895atagen2026-10-25 10:28 UTC391
    }
66db1b3cd895atagen2026-10-25 10:28 UTC392
66db1b3cd895atagen2026-10-25 10:28 UTC393
    pub async fn close_thread_list(&self, room_id: OwnedRoomId) -> Result<(), Error> {
66db1b3cd895atagen2026-10-25 10:28 UTC394
        self.run(Command::ThreadList(ThreadListCommand::Close(room_id)))
66db1b3cd895atagen2026-10-25 10:28 UTC395
            .await
66db1b3cd895atagen2026-10-25 10:28 UTC396
    }
66db1b3cd895atagen2026-10-25 10:28 UTC397
fa5b4e09943aatagen2026-10-24 09:33 UTC398
    /// reads the server's list so a pin made elsewhere just before isn't dropped
fa5b4e09943aatagen2026-10-24 09:33 UTC399
    pub async fn set_pinned(
fa5b4e09943aatagen2026-10-24 09:33 UTC400
        &self,
fa5b4e09943aatagen2026-10-24 09:33 UTC401
        room_id: OwnedRoomId,
fa5b4e09943aatagen2026-10-24 09:33 UTC402
        event_id: OwnedEventId,
fa5b4e09943aatagen2026-10-24 09:33 UTC403
        pinned: bool,
fa5b4e09943aatagen2026-10-24 09:33 UTC404
    ) -> Result<(), Error> {
fa5b4e09943aatagen2026-10-24 09:33 UTC405
        self.run(Command::Room(RoomCommand::SetPinned {
fa5b4e09943aatagen2026-10-24 09:33 UTC406
            room_id,
fa5b4e09943aatagen2026-10-24 09:33 UTC407
            event_id,
fa5b4e09943aatagen2026-10-24 09:33 UTC408
            pinned,
fa5b4e09943aatagen2026-10-24 09:33 UTC409
        }))
fa5b4e09943aatagen2026-10-24 09:33 UTC410
        .await
fa5b4e09943aatagen2026-10-24 09:33 UTC411
    }
fa5b4e09943aatagen2026-10-24 09:33 UTC412
31ce2453c82fatagen2026-09-24 13:07 UTC413
    pub async fn resync(&self, timeline_id: TimelineId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC414
        self.run(Command::Timeline(TimelineCommand::Resync { timeline_id }))
96fdf90aacd6atagen2026-09-08 08:24 UTC415
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC416
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC417
31ce2453c82fatagen2026-09-24 13:07 UTC418
    pub async fn paginate(&self, timeline_id: TimelineId, limit: u16) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC419
        self.run(Command::Timeline(TimelineCommand::Paginate {
31ce2453c82fatagen2026-09-24 13:07 UTC420
            timeline_id,
31ce2453c82fatagen2026-09-24 13:07 UTC421
            limit,
31ce2453c82fatagen2026-09-24 13:07 UTC422
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC423
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC424
    }
31ce2453c82fatagen2026-09-24 13:07 UTC425
80381e06a573atagen2026-10-25 03:02 UTC426
    pub async fn cancel_history_repair(&self, room_id: OwnedRoomId) -> Result<(), Error> {
80381e06a573atagen2026-10-25 03:02 UTC427
        self.run(Command::HistoryRepair(HistoryRepairCommand::Cancel {
80381e06a573atagen2026-10-25 03:02 UTC428
            room_id,
80381e06a573atagen2026-10-25 03:02 UTC429
        }))
80381e06a573atagen2026-10-25 03:02 UTC430
        .await
80381e06a573atagen2026-10-25 03:02 UTC431
    }
80381e06a573atagen2026-10-25 03:02 UTC432
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC433
    pub async fn fill_history_gap(
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC434
        &self,
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC435
        room_id: OwnedRoomId,
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC436
        gap_id: ruma::OwnedTransactionId,
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC437
    ) -> Result<(), Error> {
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC438
        self.run(Command::HistoryRepair(HistoryRepairCommand::FillGap {
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC439
            room_id,
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC440
            gap_id,
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC441
        }))
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC442
        .await
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC443
    }
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC444
d9b96952ec60atagen2026-10-25 09:07 UTC445
    pub async fn retry_recent_history(&self, room_id: OwnedRoomId) -> Result<(), Error> {
d9b96952ec60atagen2026-10-25 09:07 UTC446
        self.run(Command::HistoryRepair(HistoryRepairCommand::RetryRecent {
d9b96952ec60atagen2026-10-25 09:07 UTC447
            room_id,
d9b96952ec60atagen2026-10-25 09:07 UTC448
        }))
80381e06a573atagen2026-10-25 03:02 UTC449
        .await
80381e06a573atagen2026-10-25 03:02 UTC450
    }
80381e06a573atagen2026-10-25 03:02 UTC451
da8896938cf0atagen2026-10-25 10:04 UTC452
    /// close the session when the view goes, or its media stay registered
89bc9f8d246datagen2026-10-24 13:40 UTC453
    pub async fn event_context(
89bc9f8d246datagen2026-10-24 13:40 UTC454
        &self,
89bc9f8d246datagen2026-10-24 13:40 UTC455
        room_id: &RoomId,
89bc9f8d246datagen2026-10-24 13:40 UTC456
        event_id: &EventId,
cb7b3362e1ceatagen2026-10-25 09:08 UTC457
        before_limit: u16,
cb7b3362e1ceatagen2026-10-25 09:08 UTC458
        after_limit: u16,
da8896938cf0atagen2026-10-25 10:04 UTC459
    ) -> Result<EventContextSession, Error> {
89bc9f8d246datagen2026-10-24 13:40 UTC460
        match self
89bc9f8d246datagen2026-10-24 13:40 UTC461
            .execute(Command::EventContext(EventContextCommand::Fetch {
89bc9f8d246datagen2026-10-24 13:40 UTC462
                room_id: room_id.to_owned(),
89bc9f8d246datagen2026-10-24 13:40 UTC463
                event_id: event_id.to_owned(),
cb7b3362e1ceatagen2026-10-25 09:08 UTC464
                before_limit,
cb7b3362e1ceatagen2026-10-25 09:08 UTC465
                after_limit,
89bc9f8d246datagen2026-10-24 13:40 UTC466
            }))
89bc9f8d246datagen2026-10-24 13:40 UTC467
            .await?
89bc9f8d246datagen2026-10-24 13:40 UTC468
        {
da8896938cf0atagen2026-10-25 10:04 UTC469
            CommandOutput::EventContext(session) => Ok(session),
89bc9f8d246datagen2026-10-24 13:40 UTC470
            output => Err(unexpected("event context", &output)),
89bc9f8d246datagen2026-10-24 13:40 UTC471
        }
89bc9f8d246datagen2026-10-24 13:40 UTC472
    }
89bc9f8d246datagen2026-10-24 13:40 UTC473
89bc9f8d246datagen2026-10-24 13:40 UTC474
    pub async fn event_context_before(
89bc9f8d246datagen2026-10-24 13:40 UTC475
        &self,
da8896938cf0atagen2026-10-25 10:04 UTC476
        context_id: &str,
89bc9f8d246datagen2026-10-24 13:40 UTC477
        token: &str,
cb7b3362e1ceatagen2026-10-25 09:08 UTC478
        limit: u16,
89bc9f8d246datagen2026-10-24 13:40 UTC479
    ) -> Result<EventContextPage, Error> {
89bc9f8d246datagen2026-10-24 13:40 UTC480
        self.event_context_page(EventContextCommand::Before {
da8896938cf0atagen2026-10-25 10:04 UTC481
            context_id: context_id.to_owned(),
cb7b3362e1ceatagen2026-10-25 09:08 UTC482
            limit,
89bc9f8d246datagen2026-10-24 13:40 UTC483
            token: token.to_owned(),
89bc9f8d246datagen2026-10-24 13:40 UTC484
        })
89bc9f8d246datagen2026-10-24 13:40 UTC485
        .await
89bc9f8d246datagen2026-10-24 13:40 UTC486
    }
89bc9f8d246datagen2026-10-24 13:40 UTC487
89bc9f8d246datagen2026-10-24 13:40 UTC488
    pub async fn event_context_after(
89bc9f8d246datagen2026-10-24 13:40 UTC489
        &self,
da8896938cf0atagen2026-10-25 10:04 UTC490
        context_id: &str,
89bc9f8d246datagen2026-10-24 13:40 UTC491
        token: &str,
cb7b3362e1ceatagen2026-10-25 09:08 UTC492
        limit: u16,
89bc9f8d246datagen2026-10-24 13:40 UTC493
    ) -> Result<EventContextPage, Error> {
89bc9f8d246datagen2026-10-24 13:40 UTC494
        self.event_context_page(EventContextCommand::After {
da8896938cf0atagen2026-10-25 10:04 UTC495
            context_id: context_id.to_owned(),
cb7b3362e1ceatagen2026-10-25 09:08 UTC496
            limit,
89bc9f8d246datagen2026-10-24 13:40 UTC497
            token: token.to_owned(),
89bc9f8d246datagen2026-10-24 13:40 UTC498
        })
89bc9f8d246datagen2026-10-24 13:40 UTC499
        .await
89bc9f8d246datagen2026-10-24 13:40 UTC500
    }
89bc9f8d246datagen2026-10-24 13:40 UTC501
da8896938cf0atagen2026-10-25 10:04 UTC502
    pub async fn close_event_context(&self, context_id: &str) -> Result<(), Error> {
da8896938cf0atagen2026-10-25 10:04 UTC503
        self.run(Command::EventContext(EventContextCommand::Close {
da8896938cf0atagen2026-10-25 10:04 UTC504
            context_id: context_id.to_owned(),
da8896938cf0atagen2026-10-25 10:04 UTC505
        }))
da8896938cf0atagen2026-10-25 10:04 UTC506
        .await
da8896938cf0atagen2026-10-25 10:04 UTC507
    }
da8896938cf0atagen2026-10-25 10:04 UTC508
89bc9f8d246datagen2026-10-24 13:40 UTC509
    async fn event_context_page(
89bc9f8d246datagen2026-10-24 13:40 UTC510
        &self,
89bc9f8d246datagen2026-10-24 13:40 UTC511
        command: EventContextCommand,
89bc9f8d246datagen2026-10-24 13:40 UTC512
    ) -> Result<EventContextPage, Error> {
89bc9f8d246datagen2026-10-24 13:40 UTC513
        match self.execute(Command::EventContext(command)).await? {
89bc9f8d246datagen2026-10-24 13:40 UTC514
            CommandOutput::EventContextPage(page) => Ok(page),
89bc9f8d246datagen2026-10-24 13:40 UTC515
            output => Err(unexpected("event context page", &output)),
89bc9f8d246datagen2026-10-24 13:40 UTC516
        }
89bc9f8d246datagen2026-10-24 13:40 UTC517
    }
89bc9f8d246datagen2026-10-24 13:40 UTC518
cbb715e11963atagen2026-10-24 23:24 UTC519
    pub async fn mentions_page(
cbb715e11963atagen2026-10-24 23:24 UTC520
        &self,
cbb715e11963atagen2026-10-24 23:24 UTC521
        cursor: Option<String>,
cbb715e11963atagen2026-10-24 23:24 UTC522
        limit: u32,
cbb715e11963atagen2026-10-24 23:24 UTC523
    ) -> Result<MentionsPage, Error> {
cbb715e11963atagen2026-10-24 23:24 UTC524
        match self
cbb715e11963atagen2026-10-24 23:24 UTC525
            .execute(Command::Mentions(MentionsCommand::Page {
cbb715e11963atagen2026-10-24 23:24 UTC526
                cursor,
cbb715e11963atagen2026-10-24 23:24 UTC527
                limit: limit.min(50) as u16,
cbb715e11963atagen2026-10-24 23:24 UTC528
            }))
cbb715e11963atagen2026-10-24 23:24 UTC529
            .await?
cbb715e11963atagen2026-10-24 23:24 UTC530
        {
cbb715e11963atagen2026-10-24 23:24 UTC531
            CommandOutput::MentionsPage(page) => Ok(page),
cbb715e11963atagen2026-10-24 23:24 UTC532
            output => Err(unexpected("mentions page", &output)),
cbb715e11963atagen2026-10-24 23:24 UTC533
        }
cbb715e11963atagen2026-10-24 23:24 UTC534
    }
cbb715e11963atagen2026-10-24 23:24 UTC535
cbb715e11963atagen2026-10-24 23:24 UTC536
    pub async fn mention_context(
cbb715e11963atagen2026-10-24 23:24 UTC537
        &self,
cbb715e11963atagen2026-10-24 23:24 UTC538
        room_id: &RoomId,
cbb715e11963atagen2026-10-24 23:24 UTC539
        event_id: &EventId,
cbb715e11963atagen2026-10-24 23:24 UTC540
    ) -> Result<SavedMentionContext, Error> {
cbb715e11963atagen2026-10-24 23:24 UTC541
        self.mention_context_command(MentionsCommand::Context(MentionKey {
cbb715e11963atagen2026-10-24 23:24 UTC542
            room_id: room_id.to_owned(),
cbb715e11963atagen2026-10-24 23:24 UTC543
            event_id: event_id.to_owned(),
cbb715e11963atagen2026-10-24 23:24 UTC544
        }))
cbb715e11963atagen2026-10-24 23:24 UTC545
        .await
cbb715e11963atagen2026-10-24 23:24 UTC546
    }
cbb715e11963atagen2026-10-24 23:24 UTC547
cbb715e11963atagen2026-10-24 23:24 UTC548
    pub async fn retry_mention_context(
cbb715e11963atagen2026-10-24 23:24 UTC549
        &self,
cbb715e11963atagen2026-10-24 23:24 UTC550
        room_id: &RoomId,
cbb715e11963atagen2026-10-24 23:24 UTC551
        event_id: &EventId,
cbb715e11963atagen2026-10-24 23:24 UTC552
    ) -> Result<SavedMentionContext, Error> {
cbb715e11963atagen2026-10-24 23:24 UTC553
        self.mention_context_command(MentionsCommand::RetryContext(MentionKey {
cbb715e11963atagen2026-10-24 23:24 UTC554
            room_id: room_id.to_owned(),
cbb715e11963atagen2026-10-24 23:24 UTC555
            event_id: event_id.to_owned(),
cbb715e11963atagen2026-10-24 23:24 UTC556
        }))
cbb715e11963atagen2026-10-24 23:24 UTC557
        .await
cbb715e11963atagen2026-10-24 23:24 UTC558
    }
cbb715e11963atagen2026-10-24 23:24 UTC559
cbb715e11963atagen2026-10-24 23:24 UTC560
    async fn mention_context_command(
cbb715e11963atagen2026-10-24 23:24 UTC561
        &self,
cbb715e11963atagen2026-10-24 23:24 UTC562
        command: MentionsCommand,
cbb715e11963atagen2026-10-24 23:24 UTC563
    ) -> Result<SavedMentionContext, Error> {
cbb715e11963atagen2026-10-24 23:24 UTC564
        match self.execute(Command::Mentions(command)).await? {
cbb715e11963atagen2026-10-24 23:24 UTC565
            CommandOutput::MentionContext(context) => Ok(context),
cbb715e11963atagen2026-10-24 23:24 UTC566
            output => Err(unexpected("mention context", &output)),
cbb715e11963atagen2026-10-24 23:24 UTC567
        }
cbb715e11963atagen2026-10-24 23:24 UTC568
    }
cbb715e11963atagen2026-10-24 23:24 UTC569
cbb715e11963atagen2026-10-24 23:24 UTC570
    pub async fn set_mentions_read(&self, keys: Vec<MentionKey>, read: bool) -> Result<(), Error> {
cbb715e11963atagen2026-10-24 23:24 UTC571
        self.run(Command::Mentions(MentionsCommand::SetRead { keys, read }))
cbb715e11963atagen2026-10-24 23:24 UTC572
            .await
cbb715e11963atagen2026-10-24 23:24 UTC573
    }
cbb715e11963atagen2026-10-24 23:24 UTC574
cbb715e11963atagen2026-10-24 23:24 UTC575
    pub async fn mark_mentions_read_through(
cbb715e11963atagen2026-10-24 23:24 UTC576
        &self,
cbb715e11963atagen2026-10-24 23:24 UTC577
        boundary: MentionsBoundary,
cbb715e11963atagen2026-10-24 23:24 UTC578
    ) -> Result<(), Error> {
cbb715e11963atagen2026-10-24 23:24 UTC579
        self.run(Command::Mentions(MentionsCommand::ReadThrough(boundary)))
cbb715e11963atagen2026-10-24 23:24 UTC580
            .await
cbb715e11963atagen2026-10-24 23:24 UTC581
    }
cbb715e11963atagen2026-10-24 23:24 UTC582
cbb715e11963atagen2026-10-24 23:24 UTC583
    pub async fn recover_mentions(&self) -> Result<(), Error> {
cbb715e11963atagen2026-10-24 23:24 UTC584
        self.run(Command::Mentions(MentionsCommand::Recover)).await
cbb715e11963atagen2026-10-24 23:24 UTC585
    }
cbb715e11963atagen2026-10-24 23:24 UTC586
c9effeac326aatagen2026-10-25 10:32 UTC587
    /// newest first, at most 50 a page. close the search when its results go, or its media
c9effeac326aatagen2026-10-25 10:32 UTC588
    /// stay registered
c9effeac326aatagen2026-10-25 10:32 UTC589
    pub async fn search_messages(
c9effeac326aatagen2026-10-25 10:32 UTC590
        &self,
c9effeac326aatagen2026-10-25 10:32 UTC591
        query: &str,
c9effeac326aatagen2026-10-25 10:32 UTC592
        scope: SearchScope,
c9effeac326aatagen2026-10-25 10:32 UTC593
        limit: u16,
c9effeac326aatagen2026-10-25 10:32 UTC594
    ) -> Result<SearchSession, Error> {
c9effeac326aatagen2026-10-25 10:32 UTC595
        match self
c9effeac326aatagen2026-10-25 10:32 UTC596
            .execute(Command::Search(SearchCommand::Search {
c9effeac326aatagen2026-10-25 10:32 UTC597
                query: query.to_owned(),
c9effeac326aatagen2026-10-25 10:32 UTC598
                scope,
c9effeac326aatagen2026-10-25 10:32 UTC599
                limit,
c9effeac326aatagen2026-10-25 10:32 UTC600
            }))
c9effeac326aatagen2026-10-25 10:32 UTC601
            .await?
c9effeac326aatagen2026-10-25 10:32 UTC602
        {
c9effeac326aatagen2026-10-25 10:32 UTC603
            CommandOutput::SearchSession(session) => Ok(session),
c9effeac326aatagen2026-10-25 10:32 UTC604
            output => Err(unexpected("search session", &output)),
c9effeac326aatagen2026-10-25 10:32 UTC605
        }
c9effeac326aatagen2026-10-25 10:32 UTC606
    }
c9effeac326aatagen2026-10-25 10:32 UTC607
c9effeac326aatagen2026-10-25 10:32 UTC608
    pub async fn search_more(
c9effeac326aatagen2026-10-25 10:32 UTC609
        &self,
c9effeac326aatagen2026-10-25 10:32 UTC610
        search_id: &str,
c9effeac326aatagen2026-10-25 10:32 UTC611
        cursor: &str,
c9effeac326aatagen2026-10-25 10:32 UTC612
        limit: u16,
c9effeac326aatagen2026-10-25 10:32 UTC613
    ) -> Result<SearchPage, Error> {
c9effeac326aatagen2026-10-25 10:32 UTC614
        match self
c9effeac326aatagen2026-10-25 10:32 UTC615
            .execute(Command::Search(SearchCommand::More {
c9effeac326aatagen2026-10-25 10:32 UTC616
                search_id: search_id.to_owned(),
c9effeac326aatagen2026-10-25 10:32 UTC617
                cursor: cursor.to_owned(),
c9effeac326aatagen2026-10-25 10:32 UTC618
                limit,
c9effeac326aatagen2026-10-25 10:32 UTC619
            }))
c9effeac326aatagen2026-10-25 10:32 UTC620
            .await?
c9effeac326aatagen2026-10-25 10:32 UTC621
        {
c9effeac326aatagen2026-10-25 10:32 UTC622
            CommandOutput::SearchPage(page) => Ok(page),
c9effeac326aatagen2026-10-25 10:32 UTC623
            output => Err(unexpected("search page", &output)),
c9effeac326aatagen2026-10-25 10:32 UTC624
        }
c9effeac326aatagen2026-10-25 10:32 UTC625
    }
c9effeac326aatagen2026-10-25 10:32 UTC626
c9effeac326aatagen2026-10-25 10:32 UTC627
    pub async fn close_search(&self, search_id: &str) -> Result<(), Error> {
c9effeac326aatagen2026-10-25 10:32 UTC628
        self.run(Command::Search(SearchCommand::Close {
c9effeac326aatagen2026-10-25 10:32 UTC629
            search_id: search_id.to_owned(),
c9effeac326aatagen2026-10-25 10:32 UTC630
        }))
c9effeac326aatagen2026-10-25 10:32 UTC631
        .await
c9effeac326aatagen2026-10-25 10:32 UTC632
    }
c9effeac326aatagen2026-10-25 10:32 UTC633
c9effeac326aatagen2026-10-25 10:32 UTC634
    pub async fn search_coverage(&self, scope: SearchScope) -> Result<SearchCoverage, Error> {
c9effeac326aatagen2026-10-25 10:32 UTC635
        match self
c9effeac326aatagen2026-10-25 10:32 UTC636
            .execute(Command::Search(SearchCommand::Coverage(scope)))
c9effeac326aatagen2026-10-25 10:32 UTC637
            .await?
c9effeac326aatagen2026-10-25 10:32 UTC638
        {
c9effeac326aatagen2026-10-25 10:32 UTC639
            CommandOutput::SearchCoverage(coverage) => Ok(coverage),
c9effeac326aatagen2026-10-25 10:32 UTC640
            output => Err(unexpected("search coverage", &output)),
c9effeac326aatagen2026-10-25 10:32 UTC641
        }
c9effeac326aatagen2026-10-25 10:32 UTC642
    }
c9effeac326aatagen2026-10-25 10:32 UTC643
31ce2453c82fatagen2026-09-24 13:07 UTC644
    pub async fn send_message(
96fdf90aacd6atagen2026-09-08 08:24 UTC645
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC646
        timeline_id: TimelineId,
31ce2453c82fatagen2026-09-24 13:07 UTC647
        content: MessageContent,
31ce2453c82fatagen2026-09-24 13:07 UTC648
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC649
        self.run(Command::Timeline(TimelineCommand::Send {
31ce2453c82fatagen2026-09-24 13:07 UTC650
            timeline_id,
31ce2453c82fatagen2026-09-24 13:07 UTC651
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC652
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC653
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC654
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC655
31ce2453c82fatagen2026-09-24 13:07 UTC656
    pub async fn edit_message(
96fdf90aacd6atagen2026-09-08 08:24 UTC657
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC658
        timeline_id: TimelineId,
960ac0721079atagen2026-09-25 00:24 UTC659
        target: impl Into<EventRef>,
31ce2453c82fatagen2026-09-24 13:07 UTC660
        content: MessageEditContent,
31ce2453c82fatagen2026-09-24 13:07 UTC661
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC662
        self.run(Command::Timeline(TimelineCommand::Edit {
31ce2453c82fatagen2026-09-24 13:07 UTC663
            timeline_id,
960ac0721079atagen2026-09-25 00:24 UTC664
            target: target.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC665
            content,
31ce2453c82fatagen2026-09-24 13:07 UTC666
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC667
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC668
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC669
31ce2453c82fatagen2026-09-24 13:07 UTC670
    pub async fn redact(
96fdf90aacd6atagen2026-09-08 08:24 UTC671
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC672
        timeline_id: TimelineId,
960ac0721079atagen2026-09-25 00:24 UTC673
        target: impl Into<EventRef>,
31ce2453c82fatagen2026-09-24 13:07 UTC674
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC675
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC676
        self.run(Command::Timeline(TimelineCommand::Redact {
31ce2453c82fatagen2026-09-24 13:07 UTC677
            timeline_id,
960ac0721079atagen2026-09-25 00:24 UTC678
            target: target.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC679
            reason,
31ce2453c82fatagen2026-09-24 13:07 UTC680
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC681
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC682
    }
31ce2453c82fatagen2026-09-24 13:07 UTC683
31ce2453c82fatagen2026-09-24 13:07 UTC684
    pub async fn toggle_reaction(
31ce2453c82fatagen2026-09-24 13:07 UTC685
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC686
        timeline_id: TimelineId,
960ac0721079atagen2026-09-25 00:24 UTC687
        target: impl Into<EventRef>,
31ce2453c82fatagen2026-09-24 13:07 UTC688
        key: impl Into<String>,
8fa8a7cde89catagen2026-10-08 12:39 UTC689
        shortcode: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC690
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC691
        self.run(Command::Timeline(TimelineCommand::ToggleReaction {
31ce2453c82fatagen2026-09-24 13:07 UTC692
            timeline_id,
960ac0721079atagen2026-09-25 00:24 UTC693
            target: target.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC694
            key: key.into(),
8fa8a7cde89catagen2026-10-08 12:39 UTC695
            shortcode,
31ce2453c82fatagen2026-09-24 13:07 UTC696
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC697
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC698
    }
31ce2453c82fatagen2026-09-24 13:07 UTC699
31ce2453c82fatagen2026-09-24 13:07 UTC700
    pub async fn mark_read(
31ce2453c82fatagen2026-09-24 13:07 UTC701
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC702
        timeline_id: TimelineId,
31ce2453c82fatagen2026-09-24 13:07 UTC703
        event_id: OwnedEventId,
31ce2453c82fatagen2026-09-24 13:07 UTC704
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC705
        self.run(Command::Timeline(TimelineCommand::MarkRead {
31ce2453c82fatagen2026-09-24 13:07 UTC706
            timeline_id,
31ce2453c82fatagen2026-09-24 13:07 UTC707
            event_id,
31ce2453c82fatagen2026-09-24 13:07 UTC708
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC709
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC710
    }
31ce2453c82fatagen2026-09-24 13:07 UTC711
31ce2453c82fatagen2026-09-24 13:07 UTC712
    pub async fn set_typing(&self, room_id: OwnedRoomId, typing: bool) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC713
        self.run(Command::Room(RoomCommand::SetTyping { room_id, typing }))
96fdf90aacd6atagen2026-09-08 08:24 UTC714
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC715
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC716
38c4caecdb3datagen2026-09-26 13:35 UTC717
    pub async fn prepare_to_send(&self, room_id: OwnedRoomId) -> Result<(), Error> {
38c4caecdb3datagen2026-09-26 13:35 UTC718
        self.run(Command::Room(RoomCommand::PrepareToSend(room_id)))
38c4caecdb3datagen2026-09-26 13:35 UTC719
            .await
38c4caecdb3datagen2026-09-26 13:35 UTC720
    }
38c4caecdb3datagen2026-09-26 13:35 UTC721
31ce2453c82fatagen2026-09-24 13:07 UTC722
    pub async fn join_room(
96fdf90aacd6atagen2026-09-08 08:24 UTC723
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC724
        room: OwnedRoomOrAliasId,
31ce2453c82fatagen2026-09-24 13:07 UTC725
        via: Vec<OwnedServerName>,
31ce2453c82fatagen2026-09-24 13:07 UTC726
    ) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC727
        self.run_for_room(RoomCommand::Join { room, via }).await
31ce2453c82fatagen2026-09-24 13:07 UTC728
    }
31ce2453c82fatagen2026-09-24 13:07 UTC729
31ce2453c82fatagen2026-09-24 13:07 UTC730
    pub async fn leave_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC731
        self.run(Command::Room(RoomCommand::Leave(room_id))).await
31ce2453c82fatagen2026-09-24 13:07 UTC732
    }
31ce2453c82fatagen2026-09-24 13:07 UTC733
31ce2453c82fatagen2026-09-24 13:07 UTC734
    pub async fn forget_room(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC735
        self.run(Command::Room(RoomCommand::Forget(room_id))).await
31ce2453c82fatagen2026-09-24 13:07 UTC736
    }
31ce2453c82fatagen2026-09-24 13:07 UTC737
31ce2453c82fatagen2026-09-24 13:07 UTC738
    pub async fn accept_invite(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC739
        self.run(Command::Room(RoomCommand::AcceptInvite(room_id)))
31ce2453c82fatagen2026-09-24 13:07 UTC740
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC741
    }
31ce2453c82fatagen2026-09-24 13:07 UTC742
31ce2453c82fatagen2026-09-24 13:07 UTC743
    pub async fn reject_invite(&self, room_id: OwnedRoomId) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC744
        self.run(Command::Room(RoomCommand::RejectInvite(room_id)))
96fdf90aacd6atagen2026-09-08 08:24 UTC745
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC746
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC747
96fdf90aacd6atagen2026-09-08 08:24 UTC748
    pub async fn invite_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC749
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC750
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC751
        user_id: OwnedUserId,
31ce2453c82fatagen2026-09-24 13:07 UTC752
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC753
        self.run(Command::Room(RoomCommand::InviteUser { room_id, user_id }))
31ce2453c82fatagen2026-09-24 13:07 UTC754
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC755
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC756
96fdf90aacd6atagen2026-09-08 08:24 UTC757
    pub async fn kick_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC758
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC759
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC760
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC761
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC762
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC763
        self.run(Command::Room(RoomCommand::KickUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC764
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC765
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC766
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC767
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC768
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC769
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC770
96fdf90aacd6atagen2026-09-08 08:24 UTC771
    pub async fn ban_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC772
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC773
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC774
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC775
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC776
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC777
        self.run(Command::Room(RoomCommand::BanUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC778
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC779
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC780
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC781
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC782
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC783
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC784
96fdf90aacd6atagen2026-09-08 08:24 UTC785
    pub async fn unban_user(
96fdf90aacd6atagen2026-09-08 08:24 UTC786
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC787
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC788
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC789
        reason: Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC790
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC791
        self.run(Command::Room(RoomCommand::UnbanUser {
96fdf90aacd6atagen2026-09-08 08:24 UTC792
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC793
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC794
            reason,
96fdf90aacd6atagen2026-09-08 08:24 UTC795
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC796
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC797
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC798
96fdf90aacd6atagen2026-09-08 08:24 UTC799
    pub async fn set_power_levels(
96fdf90aacd6atagen2026-09-08 08:24 UTC800
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC801
        room_id: OwnedRoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC802
        changes: PowerLevelChanges,
31ce2453c82fatagen2026-09-24 13:07 UTC803
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC804
        self.run(Command::Room(RoomCommand::SetPowerLevels {
96fdf90aacd6atagen2026-09-08 08:24 UTC805
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC806
            changes,
96fdf90aacd6atagen2026-09-08 08:24 UTC807
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC808
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC809
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC810
96fdf90aacd6atagen2026-09-08 08:24 UTC811
    pub async fn set_user_power_level(
96fdf90aacd6atagen2026-09-08 08:24 UTC812
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC813
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC814
        user_id: OwnedUserId,
96fdf90aacd6atagen2026-09-08 08:24 UTC815
        level: i64,
31ce2453c82fatagen2026-09-24 13:07 UTC816
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC817
        self.run(Command::Room(RoomCommand::SetUserPowerLevel {
96fdf90aacd6atagen2026-09-08 08:24 UTC818
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC819
            user_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC820
            level,
96fdf90aacd6atagen2026-09-08 08:24 UTC821
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC822
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC823
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC824
31ce2453c82fatagen2026-09-24 13:07 UTC825
    pub async fn create_room(&self, options: CreateRoomOptions) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC826
        self.run_for_room(RoomCommand::Create(options)).await
96fdf90aacd6atagen2026-09-08 08:24 UTC827
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC828
31ce2453c82fatagen2026-09-24 13:07 UTC829
    /// hands back the existing dm with them if there is one
31ce2453c82fatagen2026-09-24 13:07 UTC830
    pub async fn create_direct(&self, user_id: OwnedUserId) -> Result<OwnedRoomId, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC831
        self.run_for_room(RoomCommand::CreateDirect(user_id)).await
96fdf90aacd6atagen2026-09-08 08:24 UTC832
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC833
96fdf90aacd6atagen2026-09-08 08:24 UTC834
    pub async fn cancel_send(
96fdf90aacd6atagen2026-09-08 08:24 UTC835
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC836
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC837
        transaction_id: OwnedTransactionId,
31ce2453c82fatagen2026-09-24 13:07 UTC838
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC839
        self.run(Command::Room(RoomCommand::CancelSend {
96fdf90aacd6atagen2026-09-08 08:24 UTC840
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC841
            transaction_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC842
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC843
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC844
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC845
96fdf90aacd6atagen2026-09-08 08:24 UTC846
    pub async fn retry_send(
96fdf90aacd6atagen2026-09-08 08:24 UTC847
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC848
        room_id: OwnedRoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC849
        transaction_id: OwnedTransactionId,
31ce2453c82fatagen2026-09-24 13:07 UTC850
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC851
        self.run(Command::Room(RoomCommand::RetrySend {
96fdf90aacd6atagen2026-09-08 08:24 UTC852
            room_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC853
            transaction_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC854
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC855
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC856
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC857
31ce2453c82fatagen2026-09-24 13:07 UTC858
    pub async fn upload(&self, upload: AttachmentUpload) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC859
        self.run(Command::Media(MediaCommand::Upload(upload))).await
96fdf90aacd6atagen2026-09-08 08:24 UTC860
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC861
31ce2453c82fatagen2026-09-24 13:07 UTC862
    pub async fn recover(&self, recovery_key: impl Into<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC863
        self.run(Command::Encryption(EncryptionCommand::Recover(
31ce2453c82fatagen2026-09-24 13:07 UTC864
            recovery_key.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC865
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC866
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC867
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC868
743123167e29atagen2026-10-26 04:02 UTC869
    /// the key is in the answer and nowhere else, so show it before dropping it
743123167e29atagen2026-10-26 04:02 UTC870
    pub async fn enable_recovery(&self, passphrase: Option<String>) -> Result<RecoveryKey, Error> {
743123167e29atagen2026-10-26 04:02 UTC871
        self.recovery_key(EncryptionCommand::EnableRecovery { passphrase })
743123167e29atagen2026-10-26 04:02 UTC872
            .await
743123167e29atagen2026-10-26 04:02 UTC873
    }
743123167e29atagen2026-10-26 04:02 UTC874
743123167e29atagen2026-10-26 04:02 UTC875
    pub async fn reset_recovery_key(
743123167e29atagen2026-10-26 04:02 UTC876
        &self,
743123167e29atagen2026-10-26 04:02 UTC877
        passphrase: Option<String>,
743123167e29atagen2026-10-26 04:02 UTC878
    ) -> Result<RecoveryKey, Error> {
743123167e29atagen2026-10-26 04:02 UTC879
        self.recovery_key(EncryptionCommand::ResetRecoveryKey { passphrase })
743123167e29atagen2026-10-26 04:02 UTC880
            .await
743123167e29atagen2026-10-26 04:02 UTC881
    }
743123167e29atagen2026-10-26 04:02 UTC882
743123167e29atagen2026-10-26 04:02 UTC883
    async fn recovery_key(&self, command: EncryptionCommand) -> Result<RecoveryKey, Error> {
743123167e29atagen2026-10-26 04:02 UTC884
        match self.execute(Command::Encryption(command)).await? {
743123167e29atagen2026-10-26 04:02 UTC885
            CommandOutput::RecoveryKey(key) => Ok(key),
743123167e29atagen2026-10-26 04:02 UTC886
            output => Err(unexpected("recovery key", &output)),
743123167e29atagen2026-10-26 04:02 UTC887
        }
743123167e29atagen2026-10-26 04:02 UTC888
    }
743123167e29atagen2026-10-26 04:02 UTC889
743123167e29atagen2026-10-26 04:02 UTC890
    pub async fn disable_recovery(&self) -> Result<(), Error> {
743123167e29atagen2026-10-26 04:02 UTC891
        self.run(Command::Encryption(EncryptionCommand::DisableRecovery))
743123167e29atagen2026-10-26 04:02 UTC892
            .await
743123167e29atagen2026-10-26 04:02 UTC893
    }
743123167e29atagen2026-10-26 04:02 UTC894
743123167e29atagen2026-10-26 04:02 UTC895
    /// checks a typed key or passphrase against secret storage without importing anything
743123167e29atagen2026-10-26 04:02 UTC896
    pub async fn verify_recovery_key(&self, recovery_key: &str) -> Result<bool, Error> {
743123167e29atagen2026-10-26 04:02 UTC897
        use matrix_sdk::encryption::secret_storage::SecretStorageError;
743123167e29atagen2026-10-26 04:02 UTC898
        match self
743123167e29atagen2026-10-26 04:02 UTC899
            .client
743123167e29atagen2026-10-26 04:02 UTC900
            .encryption()
743123167e29atagen2026-10-26 04:02 UTC901
            .secret_storage()
743123167e29atagen2026-10-26 04:02 UTC902
            .open_secret_store(recovery_key)
743123167e29atagen2026-10-26 04:02 UTC903
            .await
743123167e29atagen2026-10-26 04:02 UTC904
        {
743123167e29atagen2026-10-26 04:02 UTC905
            Ok(_) => Ok(true),
743123167e29atagen2026-10-26 04:02 UTC906
            Err(SecretStorageError::SecretStorageKey(_)) => Ok(false),
743123167e29atagen2026-10-26 04:02 UTC907
            Err(SecretStorageError::MissingKeyInfo { .. }) => {
743123167e29atagen2026-10-26 04:02 UTC908
                Err(Error::new(ErrorKind::Invalid, "recovery is not set up"))
743123167e29atagen2026-10-26 04:02 UTC909
            }
743123167e29atagen2026-10-26 04:02 UTC910
            Err(source) => Err(Error::from_recovery(
743123167e29atagen2026-10-26 04:02 UTC911
                "checking the recovery key failed",
743123167e29atagen2026-10-26 04:02 UTC912
                source.into(),
743123167e29atagen2026-10-26 04:02 UTC913
            )),
743123167e29atagen2026-10-26 04:02 UTC914
        }
743123167e29atagen2026-10-26 04:02 UTC915
    }
743123167e29atagen2026-10-26 04:02 UTC916
31ce2453c82fatagen2026-09-24 13:07 UTC917
    pub async fn create_key_backup(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC918
        self.run(Command::Encryption(EncryptionCommand::CreateKeyBackup))
31ce2453c82fatagen2026-09-24 13:07 UTC919
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC920
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC921
31ce2453c82fatagen2026-09-24 13:07 UTC922
    pub async fn enable_key_backup(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC923
        self.run(Command::Encryption(EncryptionCommand::EnableKeyBackup))
31ce2453c82fatagen2026-09-24 13:07 UTC924
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC925
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC926
31ce2453c82fatagen2026-09-24 13:07 UTC927
    pub async fn disable_key_backup(&self, delete_from_server: bool) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC928
        self.run(Command::Encryption(EncryptionCommand::DisableKeyBackup {
31ce2453c82fatagen2026-09-24 13:07 UTC929
            delete_from_server,
31ce2453c82fatagen2026-09-24 13:07 UTC930
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC931
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC932
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC933
31ce2453c82fatagen2026-09-24 13:07 UTC934
    pub async fn recover_key_backup(&self, recovery_key: impl Into<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC935
        self.run(Command::Encryption(EncryptionCommand::RecoverKeyBackup(
31ce2453c82fatagen2026-09-24 13:07 UTC936
            recovery_key.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC937
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC938
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC939
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC940
31ce2453c82fatagen2026-09-24 13:07 UTC941
    pub async fn start_verification(&self, target: VerificationTarget) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC942
        self.run(Command::Encryption(EncryptionCommand::StartVerification(
31ce2453c82fatagen2026-09-24 13:07 UTC943
            target,
31ce2453c82fatagen2026-09-24 13:07 UTC944
        )))
96fdf90aacd6atagen2026-09-08 08:24 UTC945
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC946
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC947
31ce2453c82fatagen2026-09-24 13:07 UTC948
    pub async fn verify(&self, action: VerificationAction) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC949
        self.run(Command::Encryption(EncryptionCommand::Verify(action)))
31ce2453c82fatagen2026-09-24 13:07 UTC950
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC951
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC952
5d2974de5826atagen2026-10-08 11:29 UTC953
    /// bytes for an avatar, or for media a retained timeline showed you. concurrent asks share
5d2974de5826atagen2026-10-08 11:29 UTC954
    /// one download
31ce2453c82fatagen2026-09-24 13:07 UTC955
    pub async fn media(&self, media_id: &MediaId, size: MediaSize) -> Result<Media, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC956
        self.media.timeline_media(media_id, size).await
31ce2453c82fatagen2026-09-24 13:07 UTC957
    }
31ce2453c82fatagen2026-09-24 13:07 UTC958
5b21b919d1e6atagen2026-09-27 11:47 UTC959
    /// where `media` would fetch from, for a host streaming big files itself. the byte cap
5b21b919d1e6atagen2026-09-27 11:47 UTC960
    /// doesn't apply since nothing is buffered
5b21b919d1e6atagen2026-09-27 11:47 UTC961
    pub async fn media_source(
5b21b919d1e6atagen2026-09-27 11:47 UTC962
        &self,
5b21b919d1e6atagen2026-09-27 11:47 UTC963
        media_id: &MediaId,
5b21b919d1e6atagen2026-09-27 11:47 UTC964
        size: MediaSize,
5b21b919d1e6atagen2026-09-27 11:47 UTC965
    ) -> Result<MediaLocation, Error> {
5b21b919d1e6atagen2026-09-27 11:47 UTC966
        self.media.media_location(media_id, size).await
5b21b919d1e6atagen2026-09-27 11:47 UTC967
    }
5b21b919d1e6atagen2026-09-27 11:47 UTC968
31ce2453c82fatagen2026-09-24 13:07 UTC969
    /// the space graph builds on first use and then keeps itself current
31ce2453c82fatagen2026-09-24 13:07 UTC970
    async fn spaces(&self) -> &SpaceService {
31ce2453c82fatagen2026-09-24 13:07 UTC971
        self.spaces
31ce2453c82fatagen2026-09-24 13:07 UTC972
            .get_or_init(|| SpaceService::new(self.client.clone()))
31ce2453c82fatagen2026-09-24 13:07 UTC973
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC974
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC975
96fdf90aacd6atagen2026-09-08 08:24 UTC976
    pub async fn rooms(&self) -> Vec<RoomSummary> {
31ce2453c82fatagen2026-09-24 13:07 UTC977
        room_summaries(&self.client, self.spaces().await).await
96fdf90aacd6atagen2026-09-08 08:24 UTC978
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC979
17e042fbc331atagen2026-10-08 12:39 UTC980
    pub async fn image_packs(&self) -> Result<ImagePacks, Error> {
17e042fbc331atagen2026-10-08 12:39 UTC981
        image_packs(&self.client).await
17e042fbc331atagen2026-10-08 12:39 UTC982
    }
17e042fbc331atagen2026-10-08 12:39 UTC983
0291516d40b5atagen2026-10-22 08:31 UTC984
    /// the homeserver's preview of a page, `None` when it has none. the homeserver sees every
0291516d40b5atagen2026-10-22 08:31 UTC985
    /// url asked about, so a host decides whether encrypted rooms ask at all
0291516d40b5atagen2026-10-22 08:31 UTC986
    pub async fn url_preview(&self, url: &str) -> Result<Option<LinkPreview>, Error> {
0291516d40b5atagen2026-10-22 08:31 UTC987
        self.media.url_preview(url).await
0291516d40b5atagen2026-10-22 08:31 UTC988
    }
0291516d40b5atagen2026-10-22 08:31 UTC989
0291516d40b5atagen2026-10-22 08:31 UTC990
    /// whether the room and the user's settings let link previews show here
0291516d40b5atagen2026-10-22 08:31 UTC991
    pub async fn url_previews_allowed(&self, room_id: &RoomId) -> Result<bool, Error> {
0291516d40b5atagen2026-10-22 08:31 UTC992
        url_previews_allowed(&self.room(room_id)?).await
0291516d40b5atagen2026-10-22 08:31 UTC993
    }
0291516d40b5atagen2026-10-22 08:31 UTC994
31ce2453c82fatagen2026-09-24 13:07 UTC995
    /// browse a space the way the server sees it, rooms you haven't joined included
31ce2453c82fatagen2026-09-24 13:07 UTC996
    pub async fn space_hierarchy(&self, space_id: OwnedRoomId) -> SpaceHierarchy {
31ce2453c82fatagen2026-09-24 13:07 UTC997
        SpaceHierarchy(SpaceRoomList::new(self.client.clone(), space_id).await)
31ce2453c82fatagen2026-09-24 13:07 UTC998
    }
31ce2453c82fatagen2026-09-24 13:07 UTC999
31ce2453c82fatagen2026-09-24 13:07 UTC1000
    pub async fn own_profile(&self) -> Result<Profile, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1001
        let user_id = self
31ce2453c82fatagen2026-09-24 13:07 UTC1002
            .client
31ce2453c82fatagen2026-09-24 13:07 UTC1003
            .user_id()
31ce2453c82fatagen2026-09-24 13:07 UTC1004
            .ok_or_else(|| Error::new(ErrorKind::Unauthenticated, "the client is not logged in"))?
31ce2453c82fatagen2026-09-24 13:07 UTC1005
            .to_owned();
31ce2453c82fatagen2026-09-24 13:07 UTC1006
        let response = self
31ce2453c82fatagen2026-09-24 13:07 UTC1007
            .client
31ce2453c82fatagen2026-09-24 13:07 UTC1008
            .account()
31ce2453c82fatagen2026-09-24 13:07 UTC1009
            .fetch_user_profile()
31ce2453c82fatagen2026-09-24 13:07 UTC1010
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1011
            .map_err(|source| Error::from_sdk("fetching the profile failed", source))?;
31ce2453c82fatagen2026-09-24 13:07 UTC1012
        profile(user_id, &response)
31ce2453c82fatagen2026-09-24 13:07 UTC1013
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1014
31ce2453c82fatagen2026-09-24 13:07 UTC1015
    pub async fn user_profile(&self, user_id: &UserId) -> Result<Profile, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1016
        let response = self
31ce2453c82fatagen2026-09-24 13:07 UTC1017
            .client
31ce2453c82fatagen2026-09-24 13:07 UTC1018
            .account()
31ce2453c82fatagen2026-09-24 13:07 UTC1019
            .fetch_user_profile_of(user_id)
31ce2453c82fatagen2026-09-24 13:07 UTC1020
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1021
            .map_err(|source| Error::from_sdk("fetching the profile failed", source))?;
31ce2453c82fatagen2026-09-24 13:07 UTC1022
        profile(user_id.to_owned(), &response)
31ce2453c82fatagen2026-09-24 13:07 UTC1023
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1024
31ce2453c82fatagen2026-09-24 13:07 UTC1025
    pub async fn set_display_name(&self, name: Option<String>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1026
        self.run(Command::Account(AccountCommand::SetDisplayName(name)))
31ce2453c82fatagen2026-09-24 13:07 UTC1027
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1028
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1029
31ce2453c82fatagen2026-09-24 13:07 UTC1030
    pub async fn set_avatar(&self, avatar: Option<OwnedMxcUri>) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1031
        self.run(Command::Account(AccountCommand::SetAvatar(avatar)))
31ce2453c82fatagen2026-09-24 13:07 UTC1032
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1033
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1034
31ce2453c82fatagen2026-09-24 13:07 UTC1035
    pub async fn upload_avatar(
31ce2453c82fatagen2026-09-24 13:07 UTC1036
        &self,
31ce2453c82fatagen2026-09-24 13:07 UTC1037
        mimetype: impl Into<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC1038
        bytes: Vec<u8>,
31ce2453c82fatagen2026-09-24 13:07 UTC1039
    ) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1040
        self.run(Command::Account(AccountCommand::UploadAvatar {
31ce2453c82fatagen2026-09-24 13:07 UTC1041
            mimetype: mimetype.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC1042
            bytes,
31ce2453c82fatagen2026-09-24 13:07 UTC1043
        }))
31ce2453c82fatagen2026-09-24 13:07 UTC1044
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC1045
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1046
9bd34e25bb86atagen2026-10-24 07:23 UTC1047
    /// unencrypted, for room avatars and anything else that only needs the uri
9bd34e25bb86atagen2026-10-24 07:23 UTC1048
    pub async fn upload_media(
9bd34e25bb86atagen2026-10-24 07:23 UTC1049
        &self,
9bd34e25bb86atagen2026-10-24 07:23 UTC1050
        mimetype: impl Into<String>,
9bd34e25bb86atagen2026-10-24 07:23 UTC1051
        bytes: Vec<u8>,
9bd34e25bb86atagen2026-10-24 07:23 UTC1052
    ) -> Result<OwnedMxcUri, Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1053
        let command = Command::Account(AccountCommand::UploadMedia {
9bd34e25bb86atagen2026-10-24 07:23 UTC1054
            mimetype: mimetype.into(),
9bd34e25bb86atagen2026-10-24 07:23 UTC1055
            bytes,
9bd34e25bb86atagen2026-10-24 07:23 UTC1056
        });
9bd34e25bb86atagen2026-10-24 07:23 UTC1057
        match self.execute(command).await? {
9bd34e25bb86atagen2026-10-24 07:23 UTC1058
            CommandOutput::Mxc(uri) => Ok(uri),
9bd34e25bb86atagen2026-10-24 07:23 UTC1059
            output => Err(Error::new(
9bd34e25bb86atagen2026-10-24 07:23 UTC1060
                ErrorKind::Other,
9bd34e25bb86atagen2026-10-24 07:23 UTC1061
                format!("expected an mxc but got {output:?}"),
9bd34e25bb86atagen2026-10-24 07:23 UTC1062
            )),
9bd34e25bb86atagen2026-10-24 07:23 UTC1063
        }
9bd34e25bb86atagen2026-10-24 07:23 UTC1064
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1065
9bd34e25bb86atagen2026-10-24 07:23 UTC1066
    pub async fn ignore_user(&self, user_id: OwnedUserId) -> Result<(), Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1067
        self.run(Command::Account(AccountCommand::IgnoreUser(user_id)))
9bd34e25bb86atagen2026-10-24 07:23 UTC1068
            .await
9bd34e25bb86atagen2026-10-24 07:23 UTC1069
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1070
9bd34e25bb86atagen2026-10-24 07:23 UTC1071
    pub async fn unignore_user(&self, user_id: OwnedUserId) -> Result<(), Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1072
        self.run(Command::Account(AccountCommand::UnignoreUser(user_id)))
9bd34e25bb86atagen2026-10-24 07:23 UTC1073
            .await
9bd34e25bb86atagen2026-10-24 07:23 UTC1074
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1075
9bd34e25bb86atagen2026-10-24 07:23 UTC1076
    /// writes msc3230 orders so these spaces sort in exactly this sequence, touching as few as it can
9bd34e25bb86atagen2026-10-24 07:23 UTC1077
    pub async fn reorder_spaces(&self, order: Vec<OwnedRoomId>) -> Result<(), Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1078
        self.run(Command::Account(AccountCommand::ReorderSpaces(order)))
9bd34e25bb86atagen2026-10-24 07:23 UTC1079
            .await
9bd34e25bb86atagen2026-10-24 07:23 UTC1080
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1081
9bd34e25bb86atagen2026-10-24 07:23 UTC1082
    /// adding m.favourite drops m.lowpriority, the way Element does
9bd34e25bb86atagen2026-10-24 07:23 UTC1083
    pub async fn set_favourite(&self, room_id: OwnedRoomId, favourite: bool) -> Result<(), Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1084
        self.run(Command::Room(RoomCommand::SetFavourite {
9bd34e25bb86atagen2026-10-24 07:23 UTC1085
            room_id,
9bd34e25bb86atagen2026-10-24 07:23 UTC1086
            favourite,
9bd34e25bb86atagen2026-10-24 07:23 UTC1087
        }))
9bd34e25bb86atagen2026-10-24 07:23 UTC1088
        .await
9bd34e25bb86atagen2026-10-24 07:23 UTC1089
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1090
9bd34e25bb86atagen2026-10-24 07:23 UTC1091
    /// None goes back to your global name
9bd34e25bb86atagen2026-10-24 07:23 UTC1092
    pub async fn set_room_display_name(
9bd34e25bb86atagen2026-10-24 07:23 UTC1093
        &self,
9bd34e25bb86atagen2026-10-24 07:23 UTC1094
        room_id: OwnedRoomId,
9bd34e25bb86atagen2026-10-24 07:23 UTC1095
        name: Option<String>,
9bd34e25bb86atagen2026-10-24 07:23 UTC1096
    ) -> Result<(), Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1097
        self.run(Command::Room(RoomCommand::SetOwnDisplayName {
9bd34e25bb86atagen2026-10-24 07:23 UTC1098
            room_id,
9bd34e25bb86atagen2026-10-24 07:23 UTC1099
            name,
9bd34e25bb86atagen2026-10-24 07:23 UTC1100
        }))
9bd34e25bb86atagen2026-10-24 07:23 UTC1101
        .await
9bd34e25bb86atagen2026-10-24 07:23 UTC1102
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1103
9bd34e25bb86atagen2026-10-24 07:23 UTC1104
    /// None goes back to your global avatar
9bd34e25bb86atagen2026-10-24 07:23 UTC1105
    pub async fn set_room_avatar(
9bd34e25bb86atagen2026-10-24 07:23 UTC1106
        &self,
9bd34e25bb86atagen2026-10-24 07:23 UTC1107
        room_id: OwnedRoomId,
9bd34e25bb86atagen2026-10-24 07:23 UTC1108
        avatar: Option<OwnedMxcUri>,
9bd34e25bb86atagen2026-10-24 07:23 UTC1109
    ) -> Result<(), Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1110
        self.run(Command::Room(RoomCommand::SetOwnAvatar { room_id, avatar }))
9bd34e25bb86atagen2026-10-24 07:23 UTC1111
            .await
9bd34e25bb86atagen2026-10-24 07:23 UTC1112
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1113
9bd34e25bb86atagen2026-10-24 07:23 UTC1114
    /// muting drops them below what sending a message takes, unmuting puts a muted user back
9bd34e25bb86atagen2026-10-24 07:23 UTC1115
    /// at users_default and leaves anyone else alone. `ErrorKind::Forbidden` if you can't
9bd34e25bb86atagen2026-10-24 07:23 UTC1116
    pub async fn mute_user(
9bd34e25bb86atagen2026-10-24 07:23 UTC1117
        &self,
9bd34e25bb86atagen2026-10-24 07:23 UTC1118
        room_id: OwnedRoomId,
9bd34e25bb86atagen2026-10-24 07:23 UTC1119
        user_id: OwnedUserId,
9bd34e25bb86atagen2026-10-24 07:23 UTC1120
        muted: bool,
9bd34e25bb86atagen2026-10-24 07:23 UTC1121
    ) -> Result<(), Error> {
9bd34e25bb86atagen2026-10-24 07:23 UTC1122
        self.run(Command::Room(RoomCommand::MuteUser {
9bd34e25bb86atagen2026-10-24 07:23 UTC1123
            room_id,
9bd34e25bb86atagen2026-10-24 07:23 UTC1124
            user_id,
9bd34e25bb86atagen2026-10-24 07:23 UTC1125
            muted,
9bd34e25bb86atagen2026-10-24 07:23 UTC1126
        }))
9bd34e25bb86atagen2026-10-24 07:23 UTC1127
        .await
9bd34e25bb86atagen2026-10-24 07:23 UTC1128
    }
9bd34e25bb86atagen2026-10-24 07:23 UTC1129
fa51490b6ae9atagen2026-10-24 08:41 UTC1130
    /// body defaults to the shortcode
fa51490b6ae9atagen2026-10-24 08:41 UTC1131
    pub async fn send_sticker(
fa51490b6ae9atagen2026-10-24 08:41 UTC1132
        &self,
924b7c011591atagen2026-10-25 10:28 UTC1133
        timeline_id: TimelineId,
fa51490b6ae9atagen2026-10-24 08:41 UTC1134
        pack_id: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1135
        shortcode: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1136
    ) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1137
        self.run(Command::Pack(PackCommand::SendSticker {
924b7c011591atagen2026-10-25 10:28 UTC1138
            timeline_id,
fa51490b6ae9atagen2026-10-24 08:41 UTC1139
            pack_id,
fa51490b6ae9atagen2026-10-24 08:41 UTC1140
            shortcode,
fa51490b6ae9atagen2026-10-24 08:41 UTC1141
        }))
fa51490b6ae9atagen2026-10-24 08:41 UTC1142
        .await
fa51490b6ae9atagen2026-10-24 08:41 UTC1143
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1144
fa51490b6ae9atagen2026-10-24 08:41 UTC1145
    /// fails if the state key already holds a pack
fa51490b6ae9atagen2026-10-24 08:41 UTC1146
    pub async fn create_room_pack(
fa51490b6ae9atagen2026-10-24 08:41 UTC1147
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1148
        room_id: OwnedRoomId,
fa51490b6ae9atagen2026-10-24 08:41 UTC1149
        state_key: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1150
        display_name: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1151
    ) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1152
        self.run(Command::Pack(PackCommand::CreateRoomPack {
fa51490b6ae9atagen2026-10-24 08:41 UTC1153
            room_id,
fa51490b6ae9atagen2026-10-24 08:41 UTC1154
            state_key,
fa51490b6ae9atagen2026-10-24 08:41 UTC1155
            display_name,
fa51490b6ae9atagen2026-10-24 08:41 UTC1156
        }))
fa51490b6ae9atagen2026-10-24 08:41 UTC1157
        .await
fa51490b6ae9atagen2026-10-24 08:41 UTC1158
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1159
fa51490b6ae9atagen2026-10-24 08:41 UTC1160
    pub async fn delete_pack(&self, pack: ImagePackSource) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1161
        self.run(Command::Pack(PackCommand::Delete(pack))).await
fa51490b6ae9atagen2026-10-24 08:41 UTC1162
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1163
fa51490b6ae9atagen2026-10-24 08:41 UTC1164
    pub async fn set_pack_meta(
fa51490b6ae9atagen2026-10-24 08:41 UTC1165
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1166
        pack: ImagePackSource,
fa51490b6ae9atagen2026-10-24 08:41 UTC1167
        display_name: Patch<String>,
fa51490b6ae9atagen2026-10-24 08:41 UTC1168
        avatar: Patch<OwnedMxcUri>,
fa51490b6ae9atagen2026-10-24 08:41 UTC1169
        usage: Patch<Vec<PackUsage>>,
fa51490b6ae9atagen2026-10-24 08:41 UTC1170
    ) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1171
        self.run(Command::Pack(PackCommand::SetMeta {
fa51490b6ae9atagen2026-10-24 08:41 UTC1172
            pack,
fa51490b6ae9atagen2026-10-24 08:41 UTC1173
            display_name,
fa51490b6ae9atagen2026-10-24 08:41 UTC1174
            avatar,
fa51490b6ae9atagen2026-10-24 08:41 UTC1175
            usage,
fa51490b6ae9atagen2026-10-24 08:41 UTC1176
        }))
fa51490b6ae9atagen2026-10-24 08:41 UTC1177
        .await
fa51490b6ae9atagen2026-10-24 08:41 UTC1178
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1179
fa51490b6ae9atagen2026-10-24 08:41 UTC1180
    /// adds or replaces by shortcode. a replaced image keeps its info unless the url changed
fa51490b6ae9atagen2026-10-24 08:41 UTC1181
    pub async fn put_pack_image(
fa51490b6ae9atagen2026-10-24 08:41 UTC1182
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1183
        pack: ImagePackSource,
fa51490b6ae9atagen2026-10-24 08:41 UTC1184
        shortcode: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1185
        mxc: OwnedMxcUri,
fa51490b6ae9atagen2026-10-24 08:41 UTC1186
        body: Option<String>,
fa51490b6ae9atagen2026-10-24 08:41 UTC1187
        usage: Option<Vec<PackUsage>>,
fa51490b6ae9atagen2026-10-24 08:41 UTC1188
        info: Option<PackImageInfo>,
fa51490b6ae9atagen2026-10-24 08:41 UTC1189
    ) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1190
        self.run(Command::Pack(PackCommand::PutImage {
fa51490b6ae9atagen2026-10-24 08:41 UTC1191
            pack,
fa51490b6ae9atagen2026-10-24 08:41 UTC1192
            shortcode,
fa51490b6ae9atagen2026-10-24 08:41 UTC1193
            mxc,
fa51490b6ae9atagen2026-10-24 08:41 UTC1194
            body,
fa51490b6ae9atagen2026-10-24 08:41 UTC1195
            usage,
fa51490b6ae9atagen2026-10-24 08:41 UTC1196
            info,
fa51490b6ae9atagen2026-10-24 08:41 UTC1197
        }))
fa51490b6ae9atagen2026-10-24 08:41 UTC1198
        .await
fa51490b6ae9atagen2026-10-24 08:41 UTC1199
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1200
fa51490b6ae9atagen2026-10-24 08:41 UTC1201
    pub async fn rename_pack_image(
fa51490b6ae9atagen2026-10-24 08:41 UTC1202
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1203
        pack: ImagePackSource,
fa51490b6ae9atagen2026-10-24 08:41 UTC1204
        from: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1205
        to: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1206
    ) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1207
        self.run(Command::Pack(PackCommand::RenameImage { pack, from, to }))
fa51490b6ae9atagen2026-10-24 08:41 UTC1208
            .await
fa51490b6ae9atagen2026-10-24 08:41 UTC1209
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1210
fa51490b6ae9atagen2026-10-24 08:41 UTC1211
    pub async fn remove_pack_image(
fa51490b6ae9atagen2026-10-24 08:41 UTC1212
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1213
        pack: ImagePackSource,
fa51490b6ae9atagen2026-10-24 08:41 UTC1214
        shortcode: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1215
    ) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1216
        self.run(Command::Pack(PackCommand::RemoveImage { pack, shortcode }))
fa51490b6ae9atagen2026-10-24 08:41 UTC1217
            .await
fa51490b6ae9atagen2026-10-24 08:41 UTC1218
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1219
fa51490b6ae9atagen2026-10-24 08:41 UTC1220
    pub async fn set_pack_enabled_everywhere(
fa51490b6ae9atagen2026-10-24 08:41 UTC1221
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1222
        room_id: OwnedRoomId,
fa51490b6ae9atagen2026-10-24 08:41 UTC1223
        state_key: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1224
        enabled: bool,
fa51490b6ae9atagen2026-10-24 08:41 UTC1225
    ) -> Result<(), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1226
        self.run(Command::Pack(PackCommand::SetEnabledEverywhere {
fa51490b6ae9atagen2026-10-24 08:41 UTC1227
            room_id,
fa51490b6ae9atagen2026-10-24 08:41 UTC1228
            state_key,
fa51490b6ae9atagen2026-10-24 08:41 UTC1229
            enabled,
fa51490b6ae9atagen2026-10-24 08:41 UTC1230
        }))
fa51490b6ae9atagen2026-10-24 08:41 UTC1231
        .await
fa51490b6ae9atagen2026-10-24 08:41 UTC1232
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1233
fa51490b6ae9atagen2026-10-24 08:41 UTC1234
    /// the same uri when it already lives on your homeserver
fa51490b6ae9atagen2026-10-24 08:41 UTC1235
    pub async fn rehost_media(&self, mxc: OwnedMxcUri) -> Result<OwnedMxcUri, Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1236
        match self
fa51490b6ae9atagen2026-10-24 08:41 UTC1237
            .execute(Command::Pack(PackCommand::Rehost(mxc)))
fa51490b6ae9atagen2026-10-24 08:41 UTC1238
            .await?
fa51490b6ae9atagen2026-10-24 08:41 UTC1239
        {
fa51490b6ae9atagen2026-10-24 08:41 UTC1240
            CommandOutput::Mxc(uri) => Ok(uri),
fa51490b6ae9atagen2026-10-24 08:41 UTC1241
            output => Err(unexpected("an mxc", &output)),
fa51490b6ae9atagen2026-10-24 08:41 UTC1242
        }
fa51490b6ae9atagen2026-10-24 08:41 UTC1243
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1244
d8e76b56867catagen2026-10-25 09:08 UTC1245
    /// hands back the shortcode it ended up under. `usage` overrides what the image had
fa51490b6ae9atagen2026-10-24 08:41 UTC1246
    pub async fn clone_pack_image(
fa51490b6ae9atagen2026-10-24 08:41 UTC1247
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1248
        from_pack: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1249
        shortcode: String,
fa51490b6ae9atagen2026-10-24 08:41 UTC1250
        to: ImagePackSource,
2656c1d26d6batagen2026-10-25 05:44 UTC1251
        usage: Option<Vec<PackUsage>>,
2656c1d26d6batagen2026-10-25 05:44 UTC1252
    ) -> Result<String, Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1253
        let (mut shortcodes, _) = self
fa51490b6ae9atagen2026-10-24 08:41 UTC1254
            .run_clone(PackCommand::CloneImage {
fa51490b6ae9atagen2026-10-24 08:41 UTC1255
                from_pack,
fa51490b6ae9atagen2026-10-24 08:41 UTC1256
                shortcode,
fa51490b6ae9atagen2026-10-24 08:41 UTC1257
                to,
2656c1d26d6batagen2026-10-25 05:44 UTC1258
                usage,
fa51490b6ae9atagen2026-10-24 08:41 UTC1259
            })
fa51490b6ae9atagen2026-10-24 08:41 UTC1260
            .await?;
fa51490b6ae9atagen2026-10-24 08:41 UTC1261
        shortcodes
fa51490b6ae9atagen2026-10-24 08:41 UTC1262
            .pop()
fa51490b6ae9atagen2026-10-24 08:41 UTC1263
            .ok_or_else(|| unexpected("a shortcode", &CommandOutput::Done))
fa51490b6ae9atagen2026-10-24 08:41 UTC1264
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1265
fa51490b6ae9atagen2026-10-24 08:41 UTC1266
    /// hands back the shortcode it ended up under
fa51490b6ae9atagen2026-10-24 08:41 UTC1267
    pub async fn clone_sticker(
fa51490b6ae9atagen2026-10-24 08:41 UTC1268
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1269
        room_id: OwnedRoomId,
fa51490b6ae9atagen2026-10-24 08:41 UTC1270
        event_id: OwnedEventId,
fa51490b6ae9atagen2026-10-24 08:41 UTC1271
        to: ImagePackSource,
fa51490b6ae9atagen2026-10-24 08:41 UTC1272
        shortcode: String,
2656c1d26d6batagen2026-10-25 05:44 UTC1273
        usage: Option<Vec<PackUsage>>,
2656c1d26d6batagen2026-10-25 05:44 UTC1274
    ) -> Result<String, Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1275
        let (mut shortcodes, _) = self
fa51490b6ae9atagen2026-10-24 08:41 UTC1276
            .run_clone(PackCommand::CloneSticker {
fa51490b6ae9atagen2026-10-24 08:41 UTC1277
                room_id,
fa51490b6ae9atagen2026-10-24 08:41 UTC1278
                event_id,
fa51490b6ae9atagen2026-10-24 08:41 UTC1279
                to,
fa51490b6ae9atagen2026-10-24 08:41 UTC1280
                shortcode,
2656c1d26d6batagen2026-10-25 05:44 UTC1281
                usage,
fa51490b6ae9atagen2026-10-24 08:41 UTC1282
            })
fa51490b6ae9atagen2026-10-24 08:41 UTC1283
            .await?;
fa51490b6ae9atagen2026-10-24 08:41 UTC1284
        shortcodes
fa51490b6ae9atagen2026-10-24 08:41 UTC1285
            .pop()
fa51490b6ae9atagen2026-10-24 08:41 UTC1286
            .ok_or_else(|| unexpected("a shortcode", &CommandOutput::Done))
fa51490b6ae9atagen2026-10-24 08:41 UTC1287
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1288
fa51490b6ae9atagen2026-10-24 08:41 UTC1289
    /// hands back the shortcodes that couldn't be fetched, everything else is written
fa51490b6ae9atagen2026-10-24 08:41 UTC1290
    pub async fn clone_pack(
fa51490b6ae9atagen2026-10-24 08:41 UTC1291
        &self,
fa51490b6ae9atagen2026-10-24 08:41 UTC1292
        from_pack: String,
2656c1d26d6batagen2026-10-25 05:44 UTC1293
        to: ImagePackSource,
2656c1d26d6batagen2026-10-25 05:44 UTC1294
        display_name: Option<String>,
2656c1d26d6batagen2026-10-25 05:44 UTC1295
        usage: Option<Vec<PackUsage>>,
2656c1d26d6batagen2026-10-25 05:44 UTC1296
    ) -> Result<Vec<String>, Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1297
        let (_, skipped) = self
fa51490b6ae9atagen2026-10-24 08:41 UTC1298
            .run_clone(PackCommand::ClonePack {
fa51490b6ae9atagen2026-10-24 08:41 UTC1299
                from_pack,
fa51490b6ae9atagen2026-10-24 08:41 UTC1300
                to,
fa51490b6ae9atagen2026-10-24 08:41 UTC1301
                display_name,
2656c1d26d6batagen2026-10-25 05:44 UTC1302
                usage,
fa51490b6ae9atagen2026-10-24 08:41 UTC1303
            })
fa51490b6ae9atagen2026-10-24 08:41 UTC1304
            .await?;
fa51490b6ae9atagen2026-10-24 08:41 UTC1305
        Ok(skipped)
fa51490b6ae9atagen2026-10-24 08:41 UTC1306
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1307
fa51490b6ae9atagen2026-10-24 08:41 UTC1308
    async fn run_clone(&self, command: PackCommand) -> Result<(Vec<String>, Vec<String>), Error> {
fa51490b6ae9atagen2026-10-24 08:41 UTC1309
        match self.execute(Command::Pack(command)).await? {
fa51490b6ae9atagen2026-10-24 08:41 UTC1310
            CommandOutput::Cloned {
fa51490b6ae9atagen2026-10-24 08:41 UTC1311
                shortcodes,
fa51490b6ae9atagen2026-10-24 08:41 UTC1312
                skipped,
fa51490b6ae9atagen2026-10-24 08:41 UTC1313
            } => Ok((shortcodes, skipped)),
fa51490b6ae9atagen2026-10-24 08:41 UTC1314
            output => Err(unexpected("a clone", &output)),
fa51490b6ae9atagen2026-10-24 08:41 UTC1315
        }
fa51490b6ae9atagen2026-10-24 08:41 UTC1316
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1317
31ce2453c82fatagen2026-09-24 13:07 UTC1318
    pub async fn rooms_filtered(&self, filter: &RoomListFilter) -> Vec<RoomSummary> {
31ce2453c82fatagen2026-09-24 13:07 UTC1319
        let matcher = filter.matcher();
96fdf90aacd6atagen2026-09-08 08:24 UTC1320
        self.rooms()
96fdf90aacd6atagen2026-09-08 08:24 UTC1321
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC1322
            .into_iter()
31ce2453c82fatagen2026-09-24 13:07 UTC1323
            .filter(|room| matcher.matches(room))
96fdf90aacd6atagen2026-09-08 08:24 UTC1324
            .collect()
96fdf90aacd6atagen2026-09-08 08:24 UTC1325
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1326
31ce2453c82fatagen2026-09-24 13:07 UTC1327
    pub async fn devices(&self) -> Result<Vec<OwnDevice>, Error> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1328
        let current_device_id = self.client.device_id();
96fdf90aacd6atagen2026-09-08 08:24 UTC1329
        Ok(self
96fdf90aacd6atagen2026-09-08 08:24 UTC1330
            .client
96fdf90aacd6atagen2026-09-08 08:24 UTC1331
            .devices()
96fdf90aacd6atagen2026-09-08 08:24 UTC1332
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1333
            .map_err(|source| Error::from_http("listing devices failed", source))?
96fdf90aacd6atagen2026-09-08 08:24 UTC1334
            .devices
96fdf90aacd6atagen2026-09-08 08:24 UTC1335
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC1336
            .map(|device| OwnDevice {
96fdf90aacd6atagen2026-09-08 08:24 UTC1337
                current: current_device_id == Some(device.device_id.as_ref()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1338
                device_id: device.device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC1339
                display_name: device.display_name,
96fdf90aacd6atagen2026-09-08 08:24 UTC1340
                last_seen_ip: device.last_seen_ip,
96fdf90aacd6atagen2026-09-08 08:24 UTC1341
                last_seen_timestamp_ms: device.last_seen_ts.map(|timestamp| timestamp.get().into()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1342
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC1343
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC1344
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1345
31ce2453c82fatagen2026-09-24 13:07 UTC1346
    fn room(&self, room_id: &RoomId) -> Result<matrix_sdk::Room, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1347
        self.client
31ce2453c82fatagen2026-09-24 13:07 UTC1348
            .get_room(room_id)
31ce2453c82fatagen2026-09-24 13:07 UTC1349
            .ok_or_else(Error::room_unknown)
31ce2453c82fatagen2026-09-24 13:07 UTC1350
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1351
96fdf90aacd6atagen2026-09-08 08:24 UTC1352
    pub async fn room_notification_settings(
96fdf90aacd6atagen2026-09-08 08:24 UTC1353
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC1354
        room_id: &RoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC1355
    ) -> Result<Option<RoomNotificationSettings>, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1356
        let room = self.room(room_id)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC1357
        let custom = room.user_defined_notification_mode().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC1358
        let mode = match custom {
96fdf90aacd6atagen2026-09-08 08:24 UTC1359
            Some(mode) => mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC1360
            None => match room.notification_mode().await {
96fdf90aacd6atagen2026-09-08 08:24 UTC1361
                Some(mode) => mode,
96fdf90aacd6atagen2026-09-08 08:24 UTC1362
                None => return Ok(None),
96fdf90aacd6atagen2026-09-08 08:24 UTC1363
            },
96fdf90aacd6atagen2026-09-08 08:24 UTC1364
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC1365
        Ok(Some(RoomNotificationSettings {
96fdf90aacd6atagen2026-09-08 08:24 UTC1366
            mode: crate::normalise::notification_mode(mode),
96fdf90aacd6atagen2026-09-08 08:24 UTC1367
            custom: custom.is_some(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1368
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC1369
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1370
96fdf90aacd6atagen2026-09-08 08:24 UTC1371
    pub async fn notification_keywords(&self) -> Vec<String> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1372
        self.client
96fdf90aacd6atagen2026-09-08 08:24 UTC1373
            .notification_settings()
96fdf90aacd6atagen2026-09-08 08:24 UTC1374
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC1375
            .enabled_keywords()
96fdf90aacd6atagen2026-09-08 08:24 UTC1376
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC1377
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC1378
            .collect()
96fdf90aacd6atagen2026-09-08 08:24 UTC1379
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1380
96fdf90aacd6atagen2026-09-08 08:24 UTC1381
    pub async fn resolve_push_notification(
96fdf90aacd6atagen2026-09-08 08:24 UTC1382
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC1383
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC1384
        event_id: &EventId,
31ce2453c82fatagen2026-09-24 13:07 UTC1385
    ) -> Result<PushNotificationStatus, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1386
        let notification_failed = |source| {
31ce2453c82fatagen2026-09-24 13:07 UTC1387
            Error::with_source(
31ce2453c82fatagen2026-09-24 13:07 UTC1388
                ErrorKind::Other,
31ce2453c82fatagen2026-09-24 13:07 UTC1389
                "resolving the push notification failed",
31ce2453c82fatagen2026-09-24 13:07 UTC1390
                source,
31ce2453c82fatagen2026-09-24 13:07 UTC1391
            )
31ce2453c82fatagen2026-09-24 13:07 UTC1392
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC1393
        let client = self
96fdf90aacd6atagen2026-09-08 08:24 UTC1394
            .notification_client
96fdf90aacd6atagen2026-09-08 08:24 UTC1395
            .get_or_try_init(|| async {
96fdf90aacd6atagen2026-09-08 08:24 UTC1396
                NotificationClient::new(
96fdf90aacd6atagen2026-09-08 08:24 UTC1397
                    self.client.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1398
                    NotificationProcessSetup::SingleProcess {
96fdf90aacd6atagen2026-09-08 08:24 UTC1399
                        sync_service: self.sync_service.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1400
                    },
96fdf90aacd6atagen2026-09-08 08:24 UTC1401
                )
96fdf90aacd6atagen2026-09-08 08:24 UTC1402
                .await
96fdf90aacd6atagen2026-09-08 08:24 UTC1403
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC1404
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1405
            .map_err(notification_failed)?;
96fdf90aacd6atagen2026-09-08 08:24 UTC1406
        let status = client
96fdf90aacd6atagen2026-09-08 08:24 UTC1407
            .get_notification(room_id, event_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC1408
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1409
            .map_err(notification_failed)?;
2006a11ce142atagen2026-10-26 04:02 UTC1410
        let unread = self
2006a11ce142atagen2026-10-26 04:02 UTC1411
            .client
2006a11ce142atagen2026-10-26 04:02 UTC1412
            .get_room(room_id)
2006a11ce142atagen2026-10-26 04:02 UTC1413
            .map(|room| (room.num_unread_notifications(), room.num_unread_mentions()));
2006a11ce142atagen2026-10-26 04:02 UTC1414
        Ok(normalise_push_notification(
2006a11ce142atagen2026-10-26 04:02 UTC1415
            room_id, event_id, status, unread,
2006a11ce142atagen2026-10-26 04:02 UTC1416
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC1417
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1418
96fdf90aacd6atagen2026-09-08 08:24 UTC1419
    pub async fn members(
96fdf90aacd6atagen2026-09-08 08:24 UTC1420
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC1421
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC1422
        filter: MemberFilter,
31ce2453c82fatagen2026-09-24 13:07 UTC1423
    ) -> Result<Vec<MemberSummary>, Error> {
121a56ce119datagen2026-10-24 06:42 UTC1424
        let room = self.room(room_id)?;
121a56ce119datagen2026-10-24 06:42 UTC1425
        // stores have been seen with members_synced persisted over a partial
121a56ce119datagen2026-10-24 06:42 UTC1426
        // roster, and the sdk never asks /members again once it's set
9bd34e25bb86atagen2026-10-24 07:23 UTC1427
        if self
9bd34e25bb86atagen2026-10-24 07:23 UTC1428
            .members_checked
9bd34e25bb86atagen2026-10-24 07:23 UTC1429
            .lock()
9bd34e25bb86atagen2026-10-24 07:23 UTC1430
            .unwrap()
9bd34e25bb86atagen2026-10-24 07:23 UTC1431
            .insert(room_id.to_owned())
9bd34e25bb86atagen2026-10-24 07:23 UTC1432
        {
121a56ce119datagen2026-10-24 06:42 UTC1433
            room.mark_members_missing();
121a56ce119datagen2026-10-24 06:42 UTC1434
        }
121a56ce119datagen2026-10-24 06:42 UTC1435
        list_members(&room, filter).await
121a56ce119datagen2026-10-24 06:42 UTC1436
    }
121a56ce119datagen2026-10-24 06:42 UTC1437
121a56ce119datagen2026-10-24 06:42 UTC1438
    /// drop the cached roster for a room and fetch /members again
121a56ce119datagen2026-10-24 06:42 UTC1439
    pub async fn refresh_members(
121a56ce119datagen2026-10-24 06:42 UTC1440
        &self,
121a56ce119datagen2026-10-24 06:42 UTC1441
        room_id: &RoomId,
121a56ce119datagen2026-10-24 06:42 UTC1442
        filter: MemberFilter,
121a56ce119datagen2026-10-24 06:42 UTC1443
    ) -> Result<Vec<MemberSummary>, Error> {
121a56ce119datagen2026-10-24 06:42 UTC1444
        let room = self.room(room_id)?;
121a56ce119datagen2026-10-24 06:42 UTC1445
        room.mark_members_missing();
9bd34e25bb86atagen2026-10-24 07:23 UTC1446
        self.members_checked
9bd34e25bb86atagen2026-10-24 07:23 UTC1447
            .lock()
9bd34e25bb86atagen2026-10-24 07:23 UTC1448
            .unwrap()
9bd34e25bb86atagen2026-10-24 07:23 UTC1449
            .insert(room_id.to_owned());
121a56ce119datagen2026-10-24 06:42 UTC1450
        list_members(&room, filter).await
96fdf90aacd6atagen2026-09-08 08:24 UTC1451
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1452
31ce2453c82fatagen2026-09-24 13:07 UTC1453
    pub async fn room_power_levels(&self, room_id: &RoomId) -> Result<RoomPowerLevels, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1454
        let levels = self
31ce2453c82fatagen2026-09-24 13:07 UTC1455
            .room(room_id)?
96fdf90aacd6atagen2026-09-08 08:24 UTC1456
            .power_levels()
96fdf90aacd6atagen2026-09-08 08:24 UTC1457
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1458
            .map_err(|source| Error::from_sdk("reading power levels failed", source.into()))?;
96fdf90aacd6atagen2026-09-08 08:24 UTC1459
        Ok(RoomPowerLevels {
96fdf90aacd6atagen2026-09-08 08:24 UTC1460
            ban: levels.ban.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1461
            invite: levels.invite.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1462
            kick: levels.kick.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1463
            redact: levels.redact.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1464
            events_default: levels.events_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1465
            state_default: levels.state_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1466
            users_default: levels.users_default.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1467
            room_notification: levels.notifications.room.into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1468
            users: levels
96fdf90aacd6atagen2026-09-08 08:24 UTC1469
                .users
96fdf90aacd6atagen2026-09-08 08:24 UTC1470
                .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC1471
                .map(|(user_id, level)| (user_id, level.into()))
96fdf90aacd6atagen2026-09-08 08:24 UTC1472
                .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1473
            events: levels
96fdf90aacd6atagen2026-09-08 08:24 UTC1474
                .events
96fdf90aacd6atagen2026-09-08 08:24 UTC1475
                .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC1476
                .map(|(event_type, level)| (event_type.to_string(), level.into()))
96fdf90aacd6atagen2026-09-08 08:24 UTC1477
                .collect(),
5a52012c9b1datagen2026-09-24 23:45 UTC1478
            creators: levels
5a52012c9b1datagen2026-09-24 23:45 UTC1479
                .rules
5a52012c9b1datagen2026-09-24 23:45 UTC1480
                .privileged_creators
5a52012c9b1datagen2026-09-24 23:45 UTC1481
                .into_iter()
5a52012c9b1datagen2026-09-24 23:45 UTC1482
                .flatten()
5a52012c9b1datagen2026-09-24 23:45 UTC1483
                .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1484
        })
96fdf90aacd6atagen2026-09-08 08:24 UTC1485
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1486
96fdf90aacd6atagen2026-09-08 08:24 UTC1487
    pub async fn pending_send_ids(
96fdf90aacd6atagen2026-09-08 08:24 UTC1488
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC1489
        room_id: &RoomId,
31ce2453c82fatagen2026-09-24 13:07 UTC1490
    ) -> Result<Vec<OwnedTransactionId>, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1491
        let (echoes, _) = self
31ce2453c82fatagen2026-09-24 13:07 UTC1492
            .room(room_id)?
96fdf90aacd6atagen2026-09-08 08:24 UTC1493
            .send_queue()
96fdf90aacd6atagen2026-09-08 08:24 UTC1494
            .subscribe()
96fdf90aacd6atagen2026-09-08 08:24 UTC1495
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1496
            .map_err(|source| {
31ce2453c82fatagen2026-09-24 13:07 UTC1497
                Error::with_source(ErrorKind::Store, "reading the send queue failed", source)
31ce2453c82fatagen2026-09-24 13:07 UTC1498
            })?;
96fdf90aacd6atagen2026-09-08 08:24 UTC1499
        Ok(echoes
96fdf90aacd6atagen2026-09-08 08:24 UTC1500
            .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC1501
            .filter(|echo| {
96fdf90aacd6atagen2026-09-08 08:24 UTC1502
                matches!(
96fdf90aacd6atagen2026-09-08 08:24 UTC1503
                    echo.content,
96fdf90aacd6atagen2026-09-08 08:24 UTC1504
                    matrix_sdk::send_queue::LocalEchoContent::Event { .. }
96fdf90aacd6atagen2026-09-08 08:24 UTC1505
                )
96fdf90aacd6atagen2026-09-08 08:24 UTC1506
            })
96fdf90aacd6atagen2026-09-08 08:24 UTC1507
            .map(|echo| echo.transaction_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC1508
            .collect())
96fdf90aacd6atagen2026-09-08 08:24 UTC1509
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1510
96fdf90aacd6atagen2026-09-08 08:24 UTC1511
    pub async fn global_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC1512
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC1513
        event_type: GlobalAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC1514
    ) -> Result<Option<Raw<AnyGlobalAccountDataEventContent>>, Error> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1515
        self.client
96fdf90aacd6atagen2026-09-08 08:24 UTC1516
            .account()
96fdf90aacd6atagen2026-09-08 08:24 UTC1517
            .account_data_raw(event_type)
96fdf90aacd6atagen2026-09-08 08:24 UTC1518
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1519
            .map_err(|source| Error::from_sdk("reading account data failed", source))
96fdf90aacd6atagen2026-09-08 08:24 UTC1520
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1521
96fdf90aacd6atagen2026-09-08 08:24 UTC1522
    pub async fn room_account_data(
96fdf90aacd6atagen2026-09-08 08:24 UTC1523
        &self,
96fdf90aacd6atagen2026-09-08 08:24 UTC1524
        room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC1525
        event_type: RoomAccountDataEventType,
31ce2453c82fatagen2026-09-24 13:07 UTC1526
    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1527
        self.room(room_id)?
31ce2453c82fatagen2026-09-24 13:07 UTC1528
            .account_data(event_type)
96fdf90aacd6atagen2026-09-08 08:24 UTC1529
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC1530
            .map_err(|source| Error::from_sdk("reading room account data failed", source))
96fdf90aacd6atagen2026-09-08 08:24 UTC1531
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1532
96fdf90aacd6atagen2026-09-08 08:24 UTC1533
    #[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC1534
    pub fn connection_state(&self) -> watch::Receiver<ConnectionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1535
        self.connection.clone()
96fdf90aacd6atagen2026-09-08 08:24 UTC1536
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1537
96fdf90aacd6atagen2026-09-08 08:24 UTC1538
    #[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC1539
    pub fn encryption_state(&self) -> Option<EncryptionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1540
        let device_id = self.client.device_id()?.to_owned();
96fdf90aacd6atagen2026-09-08 08:24 UTC1541
        let encryption = self.client.encryption();
96fdf90aacd6atagen2026-09-08 08:24 UTC1542
        Some(encryption_state(
96fdf90aacd6atagen2026-09-08 08:24 UTC1543
            device_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC1544
            encryption.recovery().state(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1545
            encryption.verification_state().get(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1546
            encryption.backups().state(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1547
        ))
96fdf90aacd6atagen2026-09-08 08:24 UTC1548
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1549
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1550
31ce2453c82fatagen2026-09-24 13:07 UTC1551
/// 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 UTC1552
pub struct SpaceHierarchy(SpaceRoomList);
31ce2453c82fatagen2026-09-24 13:07 UTC1553
31ce2453c82fatagen2026-09-24 13:07 UTC1554
impl fmt::Debug for SpaceHierarchy {
31ce2453c82fatagen2026-09-24 13:07 UTC1555
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31ce2453c82fatagen2026-09-24 13:07 UTC1556
        formatter
31ce2453c82fatagen2026-09-24 13:07 UTC1557
            .debug_struct("SpaceHierarchy")
31ce2453c82fatagen2026-09-24 13:07 UTC1558
            .finish_non_exhaustive()
31ce2453c82fatagen2026-09-24 13:07 UTC1559
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1560
}
31ce2453c82fatagen2026-09-24 13:07 UTC1561
31ce2453c82fatagen2026-09-24 13:07 UTC1562
impl SpaceHierarchy {
31ce2453c82fatagen2026-09-24 13:07 UTC1563
    /// fetches the next page. a no-op once the end is reached or while a page is in flight
31ce2453c82fatagen2026-09-24 13:07 UTC1564
    pub async fn paginate(&self) -> Result<(), Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1565
        self.0.paginate().await.map_err(|source| {
31ce2453c82fatagen2026-09-24 13:07 UTC1566
            Error::with_source(
31ce2453c82fatagen2026-09-24 13:07 UTC1567
                ErrorKind::Server,
31ce2453c82fatagen2026-09-24 13:07 UTC1568
                "fetching the space hierarchy failed",
31ce2453c82fatagen2026-09-24 13:07 UTC1569
                source,
31ce2453c82fatagen2026-09-24 13:07 UTC1570
            )
31ce2453c82fatagen2026-09-24 13:07 UTC1571
        })
31ce2453c82fatagen2026-09-24 13:07 UTC1572
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1573
31ce2453c82fatagen2026-09-24 13:07 UTC1574
    /// everything fetched so far, the space itself excluded
31ce2453c82fatagen2026-09-24 13:07 UTC1575
    pub async fn rooms(&self) -> Vec<SpaceChild> {
31ce2453c82fatagen2026-09-24 13:07 UTC1576
        self.0.rooms().await.into_iter().map(space_child).collect()
31ce2453c82fatagen2026-09-24 13:07 UTC1577
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1578
31ce2453c82fatagen2026-09-24 13:07 UTC1579
    #[must_use]
31ce2453c82fatagen2026-09-24 13:07 UTC1580
    pub fn end_reached(&self) -> bool {
31ce2453c82fatagen2026-09-24 13:07 UTC1581
        matches!(
31ce2453c82fatagen2026-09-24 13:07 UTC1582
            self.0.pagination_state(),
31ce2453c82fatagen2026-09-24 13:07 UTC1583
            SpaceRoomListPaginationState::Idle { end_reached: true }
31ce2453c82fatagen2026-09-24 13:07 UTC1584
        )
31ce2453c82fatagen2026-09-24 13:07 UTC1585
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1586
}
31ce2453c82fatagen2026-09-24 13:07 UTC1587
31ce2453c82fatagen2026-09-24 13:07 UTC1588
fn profile(
31ce2453c82fatagen2026-09-24 13:07 UTC1589
    user_id: OwnedUserId,
31ce2453c82fatagen2026-09-24 13:07 UTC1590
    response: &ruma::api::client::profile::get_profile::v3::Response,
31ce2453c82fatagen2026-09-24 13:07 UTC1591
) -> Result<Profile, Error> {
31ce2453c82fatagen2026-09-24 13:07 UTC1592
    use ruma::api::client::profile::{AvatarUrl, DisplayName};
31ce2453c82fatagen2026-09-24 13:07 UTC1593
    let malformed = |source| {
31ce2453c82fatagen2026-09-24 13:07 UTC1594
        Error::with_source(
31ce2453c82fatagen2026-09-24 13:07 UTC1595
            ErrorKind::Server,
31ce2453c82fatagen2026-09-24 13:07 UTC1596
            "the server sent a malformed profile",
31ce2453c82fatagen2026-09-24 13:07 UTC1597
            source,
31ce2453c82fatagen2026-09-24 13:07 UTC1598
        )
31ce2453c82fatagen2026-09-24 13:07 UTC1599
    };
31ce2453c82fatagen2026-09-24 13:07 UTC1600
    Ok(Profile {
31ce2453c82fatagen2026-09-24 13:07 UTC1601
        user_id,
31ce2453c82fatagen2026-09-24 13:07 UTC1602
        display_name: response.get_static::<DisplayName>().map_err(malformed)?,
5d2974de5826atagen2026-10-08 11:29 UTC1603
        avatar: response
5d2974de5826atagen2026-10-08 11:29 UTC1604
            .get_static::<AvatarUrl>()
5d2974de5826atagen2026-10-08 11:29 UTC1605
            .map_err(malformed)?
5d2974de5826atagen2026-10-08 11:29 UTC1606
            .as_deref()
5d2974de5826atagen2026-10-08 11:29 UTC1607
            .map(MediaId::plain),
31ce2453c82fatagen2026-09-24 13:07 UTC1608
    })
31ce2453c82fatagen2026-09-24 13:07 UTC1609
}
31ce2453c82fatagen2026-09-24 13:07 UTC1610
31ce2453c82fatagen2026-09-24 13:07 UTC1611
#[derive(Debug)]
31ce2453c82fatagen2026-09-24 13:07 UTC1612
pub(crate) struct Request {
96fdf90aacd6atagen2026-09-08 08:24 UTC1613
    pub(crate) command: Command,
31ce2453c82fatagen2026-09-24 13:07 UTC1614
    pub(crate) reply: Responder,
31ce2453c82fatagen2026-09-24 13:07 UTC1615
}
31ce2453c82fatagen2026-09-24 13:07 UTC1616
31ce2453c82fatagen2026-09-24 13:07 UTC1617
impl Request {
31ce2453c82fatagen2026-09-24 13:07 UTC1618
    fn new(command: Command) -> (Self, Pending) {
31ce2453c82fatagen2026-09-24 13:07 UTC1619
        let (reply, pending) = oneshot::channel();
31ce2453c82fatagen2026-09-24 13:07 UTC1620
        (
31ce2453c82fatagen2026-09-24 13:07 UTC1621
            Self {
31ce2453c82fatagen2026-09-24 13:07 UTC1622
                command,
31ce2453c82fatagen2026-09-24 13:07 UTC1623
                reply: Responder(reply),
31ce2453c82fatagen2026-09-24 13:07 UTC1624
            },
31ce2453c82fatagen2026-09-24 13:07 UTC1625
            Pending(pending),
31ce2453c82fatagen2026-09-24 13:07 UTC1626
        )
31ce2453c82fatagen2026-09-24 13:07 UTC1627
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1628
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1629
31ce2453c82fatagen2026-09-24 13:07 UTC1630
/// whoever holds this owes the caller an answer. dropping it answers `Interrupted`
96fdf90aacd6atagen2026-09-08 08:24 UTC1631
#[derive(Debug)]
31ce2453c82fatagen2026-09-24 13:07 UTC1632
pub(crate) struct Responder(oneshot::Sender<Result<CommandOutput, Error>>);
31ce2453c82fatagen2026-09-24 13:07 UTC1633
31ce2453c82fatagen2026-09-24 13:07 UTC1634
impl Responder {
fa51490b6ae9atagen2026-10-24 08:41 UTC1635
    pub(crate) fn channel() -> (Self, Pending) {
fa51490b6ae9atagen2026-10-24 08:41 UTC1636
        let (reply, pending) = oneshot::channel();
fa51490b6ae9atagen2026-10-24 08:41 UTC1637
        (Self(reply), Pending(pending))
fa51490b6ae9atagen2026-10-24 08:41 UTC1638
    }
fa51490b6ae9atagen2026-10-24 08:41 UTC1639
31ce2453c82fatagen2026-09-24 13:07 UTC1640
    pub(crate) fn send(self, result: Result<CommandOutput, Error>) {
31ce2453c82fatagen2026-09-24 13:07 UTC1641
        if let Err(error) = &result {
31ce2453c82fatagen2026-09-24 13:07 UTC1642
            tracing::debug!(%error, kind = ?error.kind, "command failed");
31ce2453c82fatagen2026-09-24 13:07 UTC1643
        }
31ce2453c82fatagen2026-09-24 13:07 UTC1644
        let _ = self.0.send(result);
31ce2453c82fatagen2026-09-24 13:07 UTC1645
    }
31ce2453c82fatagen2026-09-24 13:07 UTC1646
31ce2453c82fatagen2026-09-24 13:07 UTC1647
    pub(crate) fn done(self, result: Result<(), Error>) {
31ce2453c82fatagen2026-09-24 13:07 UTC1648
        self.send(result.map(|()| CommandOutput::Done));
31ce2453c82fatagen2026-09-24 13:07 UTC1649
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1650
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1651
96fdf90aacd6atagen2026-09-08 08:24 UTC1652
#[derive(Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC1653
pub struct EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC1654
    events: mpsc::Receiver<Event>,
96fdf90aacd6atagen2026-09-08 08:24 UTC1655
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1656
96fdf90aacd6atagen2026-09-08 08:24 UTC1657
impl EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC1658
    pub async fn recv(&mut self) -> Option<Event> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1659
        self.events.recv().await
96fdf90aacd6atagen2026-09-08 08:24 UTC1660
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1661
96fdf90aacd6atagen2026-09-08 08:24 UTC1662
    pub fn try_recv(&mut self) -> Result<Event, mpsc::error::TryRecvError> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1663
        self.events.try_recv()
96fdf90aacd6atagen2026-09-08 08:24 UTC1664
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1665
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1666
96fdf90aacd6atagen2026-09-08 08:24 UTC1667
impl futures_util::Stream for EventStream {
96fdf90aacd6atagen2026-09-08 08:24 UTC1668
    type Item = Event;
96fdf90aacd6atagen2026-09-08 08:24 UTC1669
96fdf90aacd6atagen2026-09-08 08:24 UTC1670
    fn poll_next(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1671
        self.events.poll_recv(context)
96fdf90aacd6atagen2026-09-08 08:24 UTC1672
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1673
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1674
96fdf90aacd6atagen2026-09-08 08:24 UTC1675
#[derive(Debug)]
96fdf90aacd6atagen2026-09-08 08:24 UTC1676
pub(crate) struct DriverPort {
31ce2453c82fatagen2026-09-24 13:07 UTC1677
    requests: mpsc::Receiver<Request>,
96fdf90aacd6atagen2026-09-08 08:24 UTC1678
    events: mpsc::Sender<Event>,
96fdf90aacd6atagen2026-09-08 08:24 UTC1679
    connection: watch::Sender<ConnectionState>,
80381e06a573atagen2026-10-25 03:02 UTC1680
    publication: Arc<PublicationRegistry>,
80381e06a573atagen2026-10-25 03:02 UTC1681
}
80381e06a573atagen2026-10-25 03:02 UTC1682
80381e06a573atagen2026-10-25 03:02 UTC1683
#[doc(hidden)]
80381e06a573atagen2026-10-25 03:02 UTC1684
#[derive(Clone, Debug)]
80381e06a573atagen2026-10-25 03:02 UTC1685
pub struct PublicationAck(Arc<PublicationAckInner>);
80381e06a573atagen2026-10-25 03:02 UTC1686
80381e06a573atagen2026-10-25 03:02 UTC1687
#[derive(Debug)]
80381e06a573atagen2026-10-25 03:02 UTC1688
struct PublicationAckInner {
80381e06a573atagen2026-10-25 03:02 UTC1689
    sender: Mutex<Option<oneshot::Sender<bool>>>,
80381e06a573atagen2026-10-25 03:02 UTC1690
}
80381e06a573atagen2026-10-25 03:02 UTC1691
80381e06a573atagen2026-10-25 03:02 UTC1692
impl PartialEq for PublicationAck {
80381e06a573atagen2026-10-25 03:02 UTC1693
    fn eq(&self, other: &Self) -> bool {
80381e06a573atagen2026-10-25 03:02 UTC1694
        Arc::ptr_eq(&self.0, &other.0)
80381e06a573atagen2026-10-25 03:02 UTC1695
    }
80381e06a573atagen2026-10-25 03:02 UTC1696
}
80381e06a573atagen2026-10-25 03:02 UTC1697
80381e06a573atagen2026-10-25 03:02 UTC1698
impl Eq for PublicationAck {}
80381e06a573atagen2026-10-25 03:02 UTC1699
80381e06a573atagen2026-10-25 03:02 UTC1700
impl PublicationAck {
80381e06a573atagen2026-10-25 03:02 UTC1701
    pub(crate) fn complete(&self, published: bool) {
80381e06a573atagen2026-10-25 03:02 UTC1702
        let sender = self
80381e06a573atagen2026-10-25 03:02 UTC1703
            .0
80381e06a573atagen2026-10-25 03:02 UTC1704
            .sender
80381e06a573atagen2026-10-25 03:02 UTC1705
            .lock()
80381e06a573atagen2026-10-25 03:02 UTC1706
            .unwrap_or_else(|error| error.into_inner())
80381e06a573atagen2026-10-25 03:02 UTC1707
            .take();
80381e06a573atagen2026-10-25 03:02 UTC1708
        if let Some(sender) = sender {
80381e06a573atagen2026-10-25 03:02 UTC1709
            let _ = sender.send(published);
80381e06a573atagen2026-10-25 03:02 UTC1710
        }
80381e06a573atagen2026-10-25 03:02 UTC1711
    }
80381e06a573atagen2026-10-25 03:02 UTC1712
}
80381e06a573atagen2026-10-25 03:02 UTC1713
80381e06a573atagen2026-10-25 03:02 UTC1714
#[derive(Debug, Default)]
80381e06a573atagen2026-10-25 03:02 UTC1715
struct PublicationRegistry {
80381e06a573atagen2026-10-25 03:02 UTC1716
    state: Mutex<PublicationRegistryState>,
80381e06a573atagen2026-10-25 03:02 UTC1717
}
80381e06a573atagen2026-10-25 03:02 UTC1718
80381e06a573atagen2026-10-25 03:02 UTC1719
#[derive(Debug, Default)]
80381e06a573atagen2026-10-25 03:02 UTC1720
struct PublicationRegistryState {
80381e06a573atagen2026-10-25 03:02 UTC1721
    mirrors: usize,
80381e06a573atagen2026-10-25 03:02 UTC1722
    pending: Vec<Weak<PublicationAckInner>>,
80381e06a573atagen2026-10-25 03:02 UTC1723
}
80381e06a573atagen2026-10-25 03:02 UTC1724
80381e06a573atagen2026-10-25 03:02 UTC1725
impl PublicationRegistry {
80381e06a573atagen2026-10-25 03:02 UTC1726
    fn register_mirror(self: &Arc<Self>) -> PublicationRegistration {
80381e06a573atagen2026-10-25 03:02 UTC1727
        self.state
80381e06a573atagen2026-10-25 03:02 UTC1728
            .lock()
80381e06a573atagen2026-10-25 03:02 UTC1729
            .unwrap_or_else(|error| error.into_inner())
80381e06a573atagen2026-10-25 03:02 UTC1730
            .mirrors += 1;
80381e06a573atagen2026-10-25 03:02 UTC1731
        PublicationRegistration {
80381e06a573atagen2026-10-25 03:02 UTC1732
            registry: self.clone(),
80381e06a573atagen2026-10-25 03:02 UTC1733
        }
80381e06a573atagen2026-10-25 03:02 UTC1734
    }
80381e06a573atagen2026-10-25 03:02 UTC1735
80381e06a573atagen2026-10-25 03:02 UTC1736
    fn acknowledgement(&self) -> Option<(PublicationAck, oneshot::Receiver<bool>)> {
80381e06a573atagen2026-10-25 03:02 UTC1737
        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
80381e06a573atagen2026-10-25 03:02 UTC1738
        if state.mirrors == 0 {
80381e06a573atagen2026-10-25 03:02 UTC1739
            return None;
80381e06a573atagen2026-10-25 03:02 UTC1740
        }
80381e06a573atagen2026-10-25 03:02 UTC1741
        state.pending.retain(|pending| pending.strong_count() > 0);
80381e06a573atagen2026-10-25 03:02 UTC1742
        let (sender, receiver) = oneshot::channel();
80381e06a573atagen2026-10-25 03:02 UTC1743
        let acknowledgement = PublicationAck(Arc::new(PublicationAckInner {
80381e06a573atagen2026-10-25 03:02 UTC1744
            sender: Mutex::new(Some(sender)),
80381e06a573atagen2026-10-25 03:02 UTC1745
        }));
80381e06a573atagen2026-10-25 03:02 UTC1746
        state.pending.push(Arc::downgrade(&acknowledgement.0));
80381e06a573atagen2026-10-25 03:02 UTC1747
        Some((acknowledgement, receiver))
80381e06a573atagen2026-10-25 03:02 UTC1748
    }
80381e06a573atagen2026-10-25 03:02 UTC1749
}
80381e06a573atagen2026-10-25 03:02 UTC1750
80381e06a573atagen2026-10-25 03:02 UTC1751
pub(crate) struct PublicationRegistration {
80381e06a573atagen2026-10-25 03:02 UTC1752
    registry: Arc<PublicationRegistry>,
80381e06a573atagen2026-10-25 03:02 UTC1753
}
80381e06a573atagen2026-10-25 03:02 UTC1754
80381e06a573atagen2026-10-25 03:02 UTC1755
impl Drop for PublicationRegistration {
80381e06a573atagen2026-10-25 03:02 UTC1756
    fn drop(&mut self) {
80381e06a573atagen2026-10-25 03:02 UTC1757
        let pending = {
80381e06a573atagen2026-10-25 03:02 UTC1758
            let mut state = self
80381e06a573atagen2026-10-25 03:02 UTC1759
                .registry
80381e06a573atagen2026-10-25 03:02 UTC1760
                .state
80381e06a573atagen2026-10-25 03:02 UTC1761
                .lock()
80381e06a573atagen2026-10-25 03:02 UTC1762
                .unwrap_or_else(|error| error.into_inner());
80381e06a573atagen2026-10-25 03:02 UTC1763
            state.mirrors -= 1;
80381e06a573atagen2026-10-25 03:02 UTC1764
            if state.mirrors == 0 {
80381e06a573atagen2026-10-25 03:02 UTC1765
                std::mem::take(&mut state.pending)
80381e06a573atagen2026-10-25 03:02 UTC1766
            } else {
80381e06a573atagen2026-10-25 03:02 UTC1767
                Vec::new()
80381e06a573atagen2026-10-25 03:02 UTC1768
            }
80381e06a573atagen2026-10-25 03:02 UTC1769
        };
80381e06a573atagen2026-10-25 03:02 UTC1770
        for acknowledgement in pending.into_iter().filter_map(|ack| ack.upgrade()) {
80381e06a573atagen2026-10-25 03:02 UTC1771
            PublicationAck(acknowledgement).complete(false);
80381e06a573atagen2026-10-25 03:02 UTC1772
        }
80381e06a573atagen2026-10-25 03:02 UTC1773
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1774
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1775
96fdf90aacd6atagen2026-09-08 08:24 UTC1776
#[derive(Clone, Debug)]
80381e06a573atagen2026-10-25 03:02 UTC1777
pub(crate) struct EventSender {
80381e06a573atagen2026-10-25 03:02 UTC1778
    events: mpsc::Sender<Event>,
80381e06a573atagen2026-10-25 03:02 UTC1779
    publication: Arc<PublicationRegistry>,
80381e06a573atagen2026-10-25 03:02 UTC1780
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1781
96fdf90aacd6atagen2026-09-08 08:24 UTC1782
impl EventSender {
74befbc72bafatagen2026-10-25 11:18 UTC1783
    #[cfg(all(test, feature = "sqlite"))]
74befbc72bafatagen2026-10-25 11:18 UTC1784
    pub(crate) fn detached(capacity: usize) -> (Self, mpsc::Receiver<Event>) {
74befbc72bafatagen2026-10-25 11:18 UTC1785
        let (events, receiver) = mpsc::channel(capacity);
74befbc72bafatagen2026-10-25 11:18 UTC1786
        let sender = Self {
74befbc72bafatagen2026-10-25 11:18 UTC1787
            events,
74befbc72bafatagen2026-10-25 11:18 UTC1788
            publication: Arc::new(PublicationRegistry::default()),
74befbc72bafatagen2026-10-25 11:18 UTC1789
        };
74befbc72bafatagen2026-10-25 11:18 UTC1790
        (sender, receiver)
74befbc72bafatagen2026-10-25 11:18 UTC1791
    }
74befbc72bafatagen2026-10-25 11:18 UTC1792
96fdf90aacd6atagen2026-09-08 08:24 UTC1793
    pub(crate) async fn send(&self, event: Event) -> Result<(), SendEventError> {
80381e06a573atagen2026-10-25 03:02 UTC1794
        self.events.send(event).await.map_err(|_| SendEventError)
80381e06a573atagen2026-10-25 03:02 UTC1795
    }
80381e06a573atagen2026-10-25 03:02 UTC1796
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1797
    pub(crate) async fn publish_barrier(&self) -> Result<(), SendEventError> {
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1798
        let Some((acknowledgement, published)) = self.publication.acknowledgement() else {
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1799
            return Ok(());
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1800
        };
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1801
        if let Err(error) = self
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1802
            .send(Event::PublicationBarrier {
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1803
                acknowledgement: Some(acknowledgement.clone()),
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1804
            })
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1805
            .await
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1806
        {
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1807
            acknowledgement.complete(false);
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1808
            return Err(error);
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1809
        }
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1810
        drop(acknowledgement);
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1811
        match published.await {
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1812
            Ok(true) => Ok(()),
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1813
            Ok(false) | Err(_) => Err(SendEventError),
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1814
        }
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1815
    }
c9f0fd0ee1ccatagen2026-10-25 06:16 UTC1816
411bc1c78b65atagen2026-10-22 07:39 UTC1817
    pub(crate) async fn reserve(&self) -> Result<mpsc::Permit<'_, Event>, SendEventError> {
80381e06a573atagen2026-10-25 03:02 UTC1818
        self.events.reserve().await.map_err(|_| SendEventError)
411bc1c78b65atagen2026-10-22 07:39 UTC1819
    }
411bc1c78b65atagen2026-10-22 07:39 UTC1820
31ce2453c82fatagen2026-09-24 13:07 UTC1821
    /// resolves once every `EventStream` is gone
96fdf90aacd6atagen2026-09-08 08:24 UTC1822
    pub(crate) async fn closed(&self) {
80381e06a573atagen2026-10-25 03:02 UTC1823
        self.events.closed().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC1824
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1825
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1826
96fdf90aacd6atagen2026-09-08 08:24 UTC1827
impl DriverPort {
96fdf90aacd6atagen2026-09-08 08:24 UTC1828
    pub(crate) fn event_sender(&self) -> EventSender {
80381e06a573atagen2026-10-25 03:02 UTC1829
        EventSender {
80381e06a573atagen2026-10-25 03:02 UTC1830
            events: self.events.clone(),
80381e06a573atagen2026-10-25 03:02 UTC1831
            publication: self.publication.clone(),
80381e06a573atagen2026-10-25 03:02 UTC1832
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC1833
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1834
96fdf90aacd6atagen2026-09-08 08:24 UTC1835
    pub(crate) fn connection_sender(&self) -> watch::Sender<ConnectionState> {
96fdf90aacd6atagen2026-09-08 08:24 UTC1836
        self.connection.clone()
96fdf90aacd6atagen2026-09-08 08:24 UTC1837
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1838
31ce2453c82fatagen2026-09-24 13:07 UTC1839
    pub(crate) async fn recv(&mut self) -> Option<Request> {
31ce2453c82fatagen2026-09-24 13:07 UTC1840
        self.requests.recv().await
96fdf90aacd6atagen2026-09-08 08:24 UTC1841
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1842
5a52012c9b1datagen2026-09-24 23:45 UTC1843
    pub(crate) fn try_recv(&mut self) -> Option<Request> {
5a52012c9b1datagen2026-09-24 23:45 UTC1844
        self.requests.try_recv().ok()
5a52012c9b1datagen2026-09-24 23:45 UTC1845
    }
5a52012c9b1datagen2026-09-24 23:45 UTC1846
31ce2453c82fatagen2026-09-24 13:07 UTC1847
    pub(crate) fn close(&mut self) {
31ce2453c82fatagen2026-09-24 13:07 UTC1848
        self.requests.close();
96fdf90aacd6atagen2026-09-08 08:24 UTC1849
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1850
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1851
31ce2453c82fatagen2026-09-24 13:07 UTC1852
#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
31ce2453c82fatagen2026-09-24 13:07 UTC1853
#[error("the event receiver has closed")]
31ce2453c82fatagen2026-09-24 13:07 UTC1854
pub(crate) struct SendEventError;
96fdf90aacd6atagen2026-09-08 08:24 UTC1855
96fdf90aacd6atagen2026-09-08 08:24 UTC1856
#[must_use]
96fdf90aacd6atagen2026-09-08 08:24 UTC1857
pub(crate) fn transport_pair(
96fdf90aacd6atagen2026-09-08 08:24 UTC1858
    client: Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC1859
    sync_service: Arc<SyncService>,
31ce2453c82fatagen2026-09-24 13:07 UTC1860
    media: Arc<MediaService>,
a250c7fa43fbatagen2026-09-26 13:35 UTC1861
    store_lock: Option<Arc<StoreLock>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC1862
    command_capacity: usize,
96fdf90aacd6atagen2026-09-08 08:24 UTC1863
    event_capacity: usize,
96fdf90aacd6atagen2026-09-08 08:24 UTC1864
) -> (ClientHandle, DriverPort, EventStream) {
31ce2453c82fatagen2026-09-24 13:07 UTC1865
    let (request_tx, request_rx) = mpsc::channel(command_capacity);
96fdf90aacd6atagen2026-09-08 08:24 UTC1866
    let (event_tx, event_rx) = mpsc::channel(event_capacity);
96fdf90aacd6atagen2026-09-08 08:24 UTC1867
    let (connection_tx, connection_rx) = watch::channel(ConnectionState::Idle);
80381e06a573atagen2026-10-25 03:02 UTC1868
    let publication = Arc::new(PublicationRegistry::default());
96fdf90aacd6atagen2026-09-08 08:24 UTC1869
    (
96fdf90aacd6atagen2026-09-08 08:24 UTC1870
        ClientHandle {
31ce2453c82fatagen2026-09-24 13:07 UTC1871
            requests: request_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1872
            client,
96fdf90aacd6atagen2026-09-08 08:24 UTC1873
            connection: connection_rx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1874
            notification_client: Arc::new(OnceCell::new()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1875
            sync_service,
31ce2453c82fatagen2026-09-24 13:07 UTC1876
            media,
31ce2453c82fatagen2026-09-24 13:07 UTC1877
            spaces: Arc::new(OnceCell::new()),
121a56ce119datagen2026-10-24 06:42 UTC1878
            members_checked: Arc::default(),
80381e06a573atagen2026-10-25 03:02 UTC1879
            publication: publication.clone(),
a250c7fa43fbatagen2026-09-26 13:35 UTC1880
            _store_lock: store_lock,
96fdf90aacd6atagen2026-09-08 08:24 UTC1881
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC1882
        DriverPort {
31ce2453c82fatagen2026-09-24 13:07 UTC1883
            requests: request_rx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1884
            events: event_tx,
96fdf90aacd6atagen2026-09-08 08:24 UTC1885
            connection: connection_tx,
80381e06a573atagen2026-10-25 03:02 UTC1886
            publication,
96fdf90aacd6atagen2026-09-08 08:24 UTC1887
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC1888
        EventStream { events: event_rx },
96fdf90aacd6atagen2026-09-08 08:24 UTC1889
    )
96fdf90aacd6atagen2026-09-08 08:24 UTC1890
}
96fdf90aacd6atagen2026-09-08 08:24 UTC1891
121a56ce119datagen2026-10-24 06:42 UTC1892
async fn list_members(
121a56ce119datagen2026-10-24 06:42 UTC1893
    room: &matrix_sdk::Room,
121a56ce119datagen2026-10-24 06:42 UTC1894
    filter: MemberFilter,
121a56ce119datagen2026-10-24 06:42 UTC1895
) -> Result<Vec<MemberSummary>, Error> {
121a56ce119datagen2026-10-24 06:42 UTC1896
    let memberships = match filter {
121a56ce119datagen2026-10-24 06:42 UTC1897
        MemberFilter::Active => RoomMemberships::ACTIVE,
121a56ce119datagen2026-10-24 06:42 UTC1898
        MemberFilter::Joined => RoomMemberships::JOIN,
121a56ce119datagen2026-10-24 06:42 UTC1899
        MemberFilter::Invited => RoomMemberships::INVITE,
121a56ce119datagen2026-10-24 06:42 UTC1900
        MemberFilter::Banned => RoomMemberships::BAN,
121a56ce119datagen2026-10-24 06:42 UTC1901
        MemberFilter::Left => RoomMemberships::LEAVE,
121a56ce119datagen2026-10-24 06:42 UTC1902
        // An empty mask is the SDK's unfiltered wildcard: it matches every
121a56ce119datagen2026-10-24 06:42 UTC1903
        // membership, including custom states that `all()` would exclude.
121a56ce119datagen2026-10-24 06:42 UTC1904
        MemberFilter::All => RoomMemberships::empty(),
121a56ce119datagen2026-10-24 06:42 UTC1905
    };
121a56ce119datagen2026-10-24 06:42 UTC1906
    Ok(room
121a56ce119datagen2026-10-24 06:42 UTC1907
        .members(memberships)
121a56ce119datagen2026-10-24 06:42 UTC1908
        .await
121a56ce119datagen2026-10-24 06:42 UTC1909
        .map_err(|source| Error::from_sdk("listing members failed", source))?
121a56ce119datagen2026-10-24 06:42 UTC1910
        .into_iter()
121a56ce119datagen2026-10-24 06:42 UTC1911
        .map(member_summary)
121a56ce119datagen2026-10-24 06:42 UTC1912
        .collect())
121a56ce119datagen2026-10-24 06:42 UTC1913
}
121a56ce119datagen2026-10-24 06:42 UTC1914
96fdf90aacd6atagen2026-09-08 08:24 UTC1915
fn normalise_push_notification(
96fdf90aacd6atagen2026-09-08 08:24 UTC1916
    room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC1917
    event_id: &EventId,
96fdf90aacd6atagen2026-09-08 08:24 UTC1918
    status: NotificationStatus,
2006a11ce142atagen2026-10-26 04:02 UTC1919
    unread: Option<(u64, u64)>,
96fdf90aacd6atagen2026-09-08 08:24 UTC1920
) -> PushNotificationStatus {
96fdf90aacd6atagen2026-09-08 08:24 UTC1921
    match status {
96fdf90aacd6atagen2026-09-08 08:24 UTC1922
        NotificationStatus::Event(item) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC1923
            let event = match &item.raw_event {
96fdf90aacd6atagen2026-09-08 08:24 UTC1924
                RawNotificationEvent::Timeline(event) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC1925
                    PushNotificationEvent::Timeline(event.clone())
96fdf90aacd6atagen2026-09-08 08:24 UTC1926
                }
96fdf90aacd6atagen2026-09-08 08:24 UTC1927
                RawNotificationEvent::Invite(event) => PushNotificationEvent::Invite(event.clone()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1928
            };
96fdf90aacd6atagen2026-09-08 08:24 UTC1929
            PushNotificationStatus::Event(Box::new(PushNotification {
96fdf90aacd6atagen2026-09-08 08:24 UTC1930
                event_id: event_id.to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1931
                event,
96fdf90aacd6atagen2026-09-08 08:24 UTC1932
                sender: PushNotificationSender {
96fdf90aacd6atagen2026-09-08 08:24 UTC1933
                    user_id: item.event.sender().to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1934
                    display_name: item.sender_display_name,
5d2974de5826atagen2026-10-08 11:29 UTC1935
                    avatar_url: item.sender_avatar_url.as_deref().map(MediaId::plain),
96fdf90aacd6atagen2026-09-08 08:24 UTC1936
                    name_ambiguous: item.is_sender_name_ambiguous,
96fdf90aacd6atagen2026-09-08 08:24 UTC1937
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC1938
                room: PushNotificationRoom {
96fdf90aacd6atagen2026-09-08 08:24 UTC1939
                    room_id: room_id.to_owned(),
2006a11ce142atagen2026-10-26 04:02 UTC1940
                    unread_notifications: unread.map(|(notifications, _)| notifications),
2006a11ce142atagen2026-10-26 04:02 UTC1941
                    unread_mentions: unread.map(|(_, mentions)| mentions),
96fdf90aacd6atagen2026-09-08 08:24 UTC1942
                    name: item.room_computed_display_name,
5d2974de5826atagen2026-10-08 11:29 UTC1943
                    avatar_url: item.room_avatar_url.as_deref().map(MediaId::plain),
96fdf90aacd6atagen2026-09-08 08:24 UTC1944
                    canonical_alias: item
96fdf90aacd6atagen2026-09-08 08:24 UTC1945
                        .room_canonical_alias
96fdf90aacd6atagen2026-09-08 08:24 UTC1946
                        .as_deref()
96fdf90aacd6atagen2026-09-08 08:24 UTC1947
                        .and_then(|alias| alias.parse().ok()),
96fdf90aacd6atagen2026-09-08 08:24 UTC1948
                    topic: item.room_topic,
96fdf90aacd6atagen2026-09-08 08:24 UTC1949
                    encrypted: item.is_room_encrypted,
96fdf90aacd6atagen2026-09-08 08:24 UTC1950
                    direct: item.room_is_dm,
96fdf90aacd6atagen2026-09-08 08:24 UTC1951
                    joined_members_count: item.joined_members_count,
96fdf90aacd6atagen2026-09-08 08:24 UTC1952
                    service_members: item
96fdf90aacd6atagen2026-09-08 08:24 UTC1953
                        .service_members
96fdf90aacd6atagen2026-09-08 08:24 UTC1954
                        .into_iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC1955
                        .filter_map(|user_id| user_id.parse().ok())
96fdf90aacd6atagen2026-09-08 08:24 UTC1956
                        .collect(),
96fdf90aacd6atagen2026-09-08 08:24 UTC1957
                    active_service_members_count: item.active_service_members_count,
96fdf90aacd6atagen2026-09-08 08:24 UTC1958
                    space: item.is_space,
96fdf90aacd6atagen2026-09-08 08:24 UTC1959
                },
96fdf90aacd6atagen2026-09-08 08:24 UTC1960
                noisy: item.is_noisy,
96fdf90aacd6atagen2026-09-08 08:24 UTC1961
                has_mention: item.has_mention,
96fdf90aacd6atagen2026-09-08 08:24 UTC1962
                thread_id: item.thread_id,
96fdf90aacd6atagen2026-09-08 08:24 UTC1963
            }))
96fdf90aacd6atagen2026-09-08 08:24 UTC1964
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC1965
        NotificationStatus::EventNotFound => PushNotificationStatus::NotFound,
96fdf90aacd6atagen2026-09-08 08:24 UTC1966
        NotificationStatus::EventFilteredOut => PushNotificationStatus::FilteredOut,
96fdf90aacd6atagen2026-09-08 08:24 UTC1967
        NotificationStatus::EventRedacted => PushNotificationStatus::Redacted,
96fdf90aacd6atagen2026-09-08 08:24 UTC1968
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC1969
}
fa51490b6ae9atagen2026-10-24 08:41 UTC1970
2006a11ce142atagen2026-10-26 04:02 UTC1971
pub(crate) async fn remove_pusher(client: &Client, pusher: PusherKey) -> Result<(), Error> {
2006a11ce142atagen2026-10-26 04:02 UTC1972
    use ruma::api::client::push::PusherIds;
2006a11ce142atagen2026-10-26 04:02 UTC1973
    client
2006a11ce142atagen2026-10-26 04:02 UTC1974
        .pusher()
2006a11ce142atagen2026-10-26 04:02 UTC1975
        .delete(PusherIds::new(pusher.pushkey, pusher.app_id))
2006a11ce142atagen2026-10-26 04:02 UTC1976
        .await
2006a11ce142atagen2026-10-26 04:02 UTC1977
        .map_err(|source| Error::from_sdk("removing the pusher failed", source))
2006a11ce142atagen2026-10-26 04:02 UTC1978
}
2006a11ce142atagen2026-10-26 04:02 UTC1979
fa51490b6ae9atagen2026-10-24 08:41 UTC1980
fn unexpected(wanted: &str, output: &CommandOutput) -> Error {
fa51490b6ae9atagen2026-10-24 08:41 UTC1981
    Error::new(
fa51490b6ae9atagen2026-10-24 08:41 UTC1982
        ErrorKind::Other,
fa51490b6ae9atagen2026-10-24 08:41 UTC1983
        format!("expected {wanted} but got {output:?}"),
fa51490b6ae9atagen2026-10-24 08:41 UTC1984
    )
fa51490b6ae9atagen2026-10-24 08:41 UTC1985
}
80381e06a573atagen2026-10-25 03:02 UTC1986
80381e06a573atagen2026-10-25 03:02 UTC1987
#[cfg(test)]
80381e06a573atagen2026-10-25 03:02 UTC1988
mod tests {
80381e06a573atagen2026-10-25 03:02 UTC1989
    use super::*;
80381e06a573atagen2026-10-25 03:02 UTC1990
80381e06a573atagen2026-10-25 03:02 UTC1991
    #[tokio::test]
d9b96952ec60atagen2026-10-25 09:07 UTC1992
    async fn publish_barrier_waits_for_mirror_publication() {
80381e06a573atagen2026-10-25 03:02 UTC1993
        let publication = Arc::new(PublicationRegistry::default());
80381e06a573atagen2026-10-25 03:02 UTC1994
        let _registration = publication.register_mirror();
80381e06a573atagen2026-10-25 03:02 UTC1995
        let (events, mut received) = mpsc::channel(1);
80381e06a573atagen2026-10-25 03:02 UTC1996
        let sender = EventSender {
80381e06a573atagen2026-10-25 03:02 UTC1997
            events,
80381e06a573atagen2026-10-25 03:02 UTC1998
            publication,
80381e06a573atagen2026-10-25 03:02 UTC1999
        };
d9b96952ec60atagen2026-10-25 09:07 UTC2000
        let publisher = tokio::spawn(async move { sender.publish_barrier().await });
80381e06a573atagen2026-10-25 03:02 UTC2001
d9b96952ec60atagen2026-10-25 09:07 UTC2002
        let Some(Event::PublicationBarrier {
80381e06a573atagen2026-10-25 03:02 UTC2003
            acknowledgement: Some(acknowledgement),
80381e06a573atagen2026-10-25 03:02 UTC2004
        }) = received.recv().await
80381e06a573atagen2026-10-25 03:02 UTC2005
        else {
d9b96952ec60atagen2026-10-25 09:07 UTC2006
            panic!("barrier was not published");
80381e06a573atagen2026-10-25 03:02 UTC2007
        };
80381e06a573atagen2026-10-25 03:02 UTC2008
        tokio::task::yield_now().await;
80381e06a573atagen2026-10-25 03:02 UTC2009
        assert!(!publisher.is_finished());
80381e06a573atagen2026-10-25 03:02 UTC2010
80381e06a573atagen2026-10-25 03:02 UTC2011
        acknowledgement.complete(true);
80381e06a573atagen2026-10-25 03:02 UTC2012
        assert!(matches!(publisher.await.unwrap(), Ok(())));
80381e06a573atagen2026-10-25 03:02 UTC2013
    }
80381e06a573atagen2026-10-25 03:02 UTC2014
80381e06a573atagen2026-10-25 03:02 UTC2015
    #[tokio::test]
d9b96952ec60atagen2026-10-25 09:07 UTC2016
    async fn publish_barrier_fails_when_last_mirror_drops() {
80381e06a573atagen2026-10-25 03:02 UTC2017
        let publication = Arc::new(PublicationRegistry::default());
80381e06a573atagen2026-10-25 03:02 UTC2018
        let registration = publication.register_mirror();
80381e06a573atagen2026-10-25 03:02 UTC2019
        let (events, mut received) = mpsc::channel(1);
80381e06a573atagen2026-10-25 03:02 UTC2020
        let sender = EventSender {
80381e06a573atagen2026-10-25 03:02 UTC2021
            events,
80381e06a573atagen2026-10-25 03:02 UTC2022
            publication,
80381e06a573atagen2026-10-25 03:02 UTC2023
        };
d9b96952ec60atagen2026-10-25 09:07 UTC2024
        let publisher = tokio::spawn(async move { sender.publish_barrier().await });
80381e06a573atagen2026-10-25 03:02 UTC2025
80381e06a573atagen2026-10-25 03:02 UTC2026
        assert!(matches!(
80381e06a573atagen2026-10-25 03:02 UTC2027
            received.recv().await,
d9b96952ec60atagen2026-10-25 09:07 UTC2028
            Some(Event::PublicationBarrier {
80381e06a573atagen2026-10-25 03:02 UTC2029
                acknowledgement: Some(_),
80381e06a573atagen2026-10-25 03:02 UTC2030
            })
80381e06a573atagen2026-10-25 03:02 UTC2031
        ));
80381e06a573atagen2026-10-25 03:02 UTC2032
        drop(registration);
80381e06a573atagen2026-10-25 03:02 UTC2033
80381e06a573atagen2026-10-25 03:02 UTC2034
        assert!(matches!(publisher.await.unwrap(), Err(SendEventError)));
80381e06a573atagen2026-10-25 03:02 UTC2035
    }
80381e06a573atagen2026-10-25 03:02 UTC2036
}