atagen

macltok

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

Blame: src/error.rs

31ce2453c82fatagen2026-09-24 13:07 UTC1
use std::sync::Arc;
96fdf90aacd6atagen2026-09-08 08:24 UTC2
96fdf90aacd6atagen2026-09-08 08:24 UTC3
use matrix_sdk::{
1fe480c16a3catagen2026-09-26 08:44 UTC4
    HttpError, RefreshTokenError, SendOutsideWasm, SyncOutsideWasm,
96fdf90aacd6atagen2026-09-08 08:24 UTC5
    authentication::oauth::error::{
96fdf90aacd6atagen2026-09-08 08:24 UTC6
        OAuthAuthorizationCodeError, OAuthDiscoveryError, OAuthError, OAuthTokenRevocationError,
96fdf90aacd6atagen2026-09-08 08:24 UTC7
        RequestTokenError,
96fdf90aacd6atagen2026-09-08 08:24 UTC8
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC9
    encryption::{
96fdf90aacd6atagen2026-09-08 08:24 UTC10
        identities::{ManualVerifyError, RequestVerificationError},
96fdf90aacd6atagen2026-09-08 08:24 UTC11
        recovery::RecoveryError,
96fdf90aacd6atagen2026-09-08 08:24 UTC12
        secret_storage::{ImportError, SecretStorageError},
96fdf90aacd6atagen2026-09-08 08:24 UTC13
    },
96fdf90aacd6atagen2026-09-08 08:24 UTC14
};
31ce2453c82fatagen2026-09-24 13:07 UTC15
#[cfg(feature = "serde")]
31ce2453c82fatagen2026-09-24 13:07 UTC16
use serde::{Deserialize, Serialize};
96fdf90aacd6atagen2026-09-08 08:24 UTC17
31ce2453c82fatagen2026-09-24 13:07 UTC18
use crate::InteractiveAuthChallenge;
96fdf90aacd6atagen2026-09-08 08:24 UTC19
1fe480c16a3catagen2026-09-26 08:44 UTC20
/// the sdk's `SendOutsideWasm` isn't an auto trait, so it can't go in a trait object
1fe480c16a3catagen2026-09-26 08:44 UTC21
#[cfg(not(target_family = "wasm"))]
62fe32759529atagen2026-09-26 08:50 UTC22
pub(crate) type SourceError = dyn std::error::Error + Send + Sync;
1fe480c16a3catagen2026-09-26 08:44 UTC23
#[cfg(target_family = "wasm")]
62fe32759529atagen2026-09-26 08:50 UTC24
pub(crate) type SourceError = dyn std::error::Error;
1fe480c16a3catagen2026-09-26 08:44 UTC25
31ce2453c82fatagen2026-09-24 13:07 UTC26
/// the one thing that goes wrong, for commands and queries alike. match on `kind`, show `message`
31ce2453c82fatagen2026-09-24 13:07 UTC27
#[derive(Clone, Debug, thiserror::Error)]
31ce2453c82fatagen2026-09-24 13:07 UTC28
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
96fdf90aacd6atagen2026-09-08 08:24 UTC29
#[error("{message}")]
31ce2453c82fatagen2026-09-24 13:07 UTC30
#[non_exhaustive]
31ce2453c82fatagen2026-09-24 13:07 UTC31
pub struct Error {
31ce2453c82fatagen2026-09-24 13:07 UTC32
    pub kind: ErrorKind,
31ce2453c82fatagen2026-09-24 13:07 UTC33
    pub message: String,
31ce2453c82fatagen2026-09-24 13:07 UTC34
    /// set when the server wants interactive auth before it'll do the thing
31ce2453c82fatagen2026-09-24 13:07 UTC35
    pub challenge: Option<Box<InteractiveAuthChallenge>>,
9a25b6ce66f4atagen2026-10-08 11:15 UTC36
    /// set when the homeserver refused with a matrix error
9a25b6ce66f4atagen2026-10-08 11:15 UTC37
    pub server: Option<ServerError>,
96fdf90aacd6atagen2026-09-08 08:24 UTC38
    #[source]
31ce2453c82fatagen2026-09-24 13:07 UTC39
    #[cfg_attr(feature = "serde", serde(skip))]
1fe480c16a3catagen2026-09-26 08:44 UTC40
    source: Option<Arc<SourceError>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC41
}
96fdf90aacd6atagen2026-09-08 08:24 UTC42
31ce2453c82fatagen2026-09-24 13:07 UTC43
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
31ce2453c82fatagen2026-09-24 13:07 UTC44
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31ce2453c82fatagen2026-09-24 13:07 UTC45
pub enum ErrorKind {
31ce2453c82fatagen2026-09-24 13:07 UTC46
    /// the engine stopped, or the task doing the work died, before answering
31ce2453c82fatagen2026-09-24 13:07 UTC47
    Interrupted,
31ce2453c82fatagen2026-09-24 13:07 UTC48
    Unauthenticated,
31ce2453c82fatagen2026-09-24 13:07 UTC49
    InteractiveAuthRequired,
31ce2453c82fatagen2026-09-24 13:07 UTC50
    Invalid,
9bd34e25bb86atagen2026-10-24 07:23 UTC51
    /// the room's power levels don't let you
9bd34e25bb86atagen2026-10-24 07:23 UTC52
    Forbidden,
31ce2453c82fatagen2026-09-24 13:07 UTC53
    RoomUnknown,
31ce2453c82fatagen2026-09-24 13:07 UTC54
    RoomNotOpen,
31ce2453c82fatagen2026-09-24 13:07 UTC55
    TimelineNotOpen,
da8896938cf0atagen2026-10-25 10:04 UTC56
    EventContextNotOpen,
c9effeac326aatagen2026-10-25 10:32 UTC57
    SearchNotOpen,
89bc9f8d246datagen2026-10-24 13:40 UTC58
    EventNotFound,
31ce2453c82fatagen2026-09-24 13:07 UTC59
    RoomBusy,
31ce2453c82fatagen2026-09-24 13:07 UTC60
    QueueFull,
31ce2453c82fatagen2026-09-24 13:07 UTC61
    EmptyBody,
31ce2453c82fatagen2026-09-24 13:07 UTC62
    MediaUnknown,
31ce2453c82fatagen2026-09-24 13:07 UTC63
    MediaTooLarge,
31ce2453c82fatagen2026-09-24 13:07 UTC64
    MediaUnavailable,
31ce2453c82fatagen2026-09-24 13:07 UTC65
    VerificationInactive,
31ce2453c82fatagen2026-09-24 13:07 UTC66
    VerificationUnsupported,
31ce2453c82fatagen2026-09-24 13:07 UTC67
    NoCrossSigningIdentity,
31ce2453c82fatagen2026-09-24 13:07 UTC68
    RecoveryRejected,
743123167e29atagen2026-10-26 04:02 UTC69
    /// the server already holds a key backup, which recovery has to open or replace first
743123167e29atagen2026-10-26 04:02 UTC70
    KeyBackupExists,
31ce2453c82fatagen2026-09-24 13:07 UTC71
    Network,
0291516d40b5atagen2026-10-22 08:31 UTC72
    /// the homeserver wants us to slow down. try again later
0291516d40b5atagen2026-10-22 08:31 UTC73
    RateLimited,
31ce2453c82fatagen2026-09-24 13:07 UTC74
    Server,
31ce2453c82fatagen2026-09-24 13:07 UTC75
    Store,
31ce2453c82fatagen2026-09-24 13:07 UTC76
    Timeline,
31ce2453c82fatagen2026-09-24 13:07 UTC77
    Encryption,
31ce2453c82fatagen2026-09-24 13:07 UTC78
    Other,
31ce2453c82fatagen2026-09-24 13:07 UTC79
}
31ce2453c82fatagen2026-09-24 13:07 UTC80
9a25b6ce66f4atagen2026-10-08 11:15 UTC81
/// the homeserver's own answer, worth showing a person as it stands
9a25b6ce66f4atagen2026-10-08 11:15 UTC82
#[derive(Clone, Debug, Eq, PartialEq)]
9a25b6ce66f4atagen2026-10-08 11:15 UTC83
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9a25b6ce66f4atagen2026-10-08 11:15 UTC84
#[non_exhaustive]
9a25b6ce66f4atagen2026-10-08 11:15 UTC85
pub struct ServerError {
9a25b6ce66f4atagen2026-10-08 11:15 UTC86
    pub status: u16,
9a25b6ce66f4atagen2026-10-08 11:15 UTC87
    pub errcode: String,
9a25b6ce66f4atagen2026-10-08 11:15 UTC88
    pub message: String,
9a25b6ce66f4atagen2026-10-08 11:15 UTC89
}
9a25b6ce66f4atagen2026-10-08 11:15 UTC90
9a25b6ce66f4atagen2026-10-08 11:15 UTC91
impl ServerError {
9a25b6ce66f4atagen2026-10-08 11:15 UTC92
    pub(crate) fn find(source: &(dyn std::error::Error + 'static)) -> Option<Self> {
9a25b6ce66f4atagen2026-10-08 11:15 UTC93
        let mut current = Some(source);
9a25b6ce66f4atagen2026-10-08 11:15 UTC94
        while let Some(error) = current {
9a25b6ce66f4atagen2026-10-08 11:15 UTC95
            let api = if let Some(error) = error.downcast_ref::<matrix_sdk::Error>() {
9a25b6ce66f4atagen2026-10-08 11:15 UTC96
                error.as_client_api_error()
9a25b6ce66f4atagen2026-10-08 11:15 UTC97
            } else if let Some(error) = error.downcast_ref::<HttpError>() {
9a25b6ce66f4atagen2026-10-08 11:15 UTC98
                error.as_client_api_error()
9a25b6ce66f4atagen2026-10-08 11:15 UTC99
            } else {
9a25b6ce66f4atagen2026-10-08 11:15 UTC100
                error.downcast_ref::<ruma::api::error::Error>()
9a25b6ce66f4atagen2026-10-08 11:15 UTC101
            };
9a25b6ce66f4atagen2026-10-08 11:15 UTC102
            if let Some(api) = api
9a25b6ce66f4atagen2026-10-08 11:15 UTC103
                && let ruma::api::error::ErrorBody::Standard(body) = &api.body
9a25b6ce66f4atagen2026-10-08 11:15 UTC104
            {
9a25b6ce66f4atagen2026-10-08 11:15 UTC105
                return Some(Self {
9a25b6ce66f4atagen2026-10-08 11:15 UTC106
                    status: api.status_code.as_u16(),
9a25b6ce66f4atagen2026-10-08 11:15 UTC107
                    errcode: body.kind.errcode().to_string(),
9a25b6ce66f4atagen2026-10-08 11:15 UTC108
                    message: body.message.clone(),
9a25b6ce66f4atagen2026-10-08 11:15 UTC109
                });
9a25b6ce66f4atagen2026-10-08 11:15 UTC110
            }
9a25b6ce66f4atagen2026-10-08 11:15 UTC111
            current = error.source();
9a25b6ce66f4atagen2026-10-08 11:15 UTC112
        }
9a25b6ce66f4atagen2026-10-08 11:15 UTC113
        None
9a25b6ce66f4atagen2026-10-08 11:15 UTC114
    }
9a25b6ce66f4atagen2026-10-08 11:15 UTC115
}
9a25b6ce66f4atagen2026-10-08 11:15 UTC116
9a25b6ce66f4atagen2026-10-08 11:15 UTC117
impl std::fmt::Display for ServerError {
9a25b6ce66f4atagen2026-10-08 11:15 UTC118
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9a25b6ce66f4atagen2026-10-08 11:15 UTC119
        write!(formatter, "{} ({})", self.message, self.errcode)
9a25b6ce66f4atagen2026-10-08 11:15 UTC120
    }
9a25b6ce66f4atagen2026-10-08 11:15 UTC121
}
9a25b6ce66f4atagen2026-10-08 11:15 UTC122
9a25b6ce66f4atagen2026-10-08 11:15 UTC123
#[cfg(any(feature = "sqlite", feature = "indexeddb"))]
9a25b6ce66f4atagen2026-10-08 11:15 UTC124
pub(crate) fn classify(source: &(dyn std::error::Error + 'static)) -> ErrorKind {
9a25b6ce66f4atagen2026-10-08 11:15 UTC125
    let mut current = Some(source);
9a25b6ce66f4atagen2026-10-08 11:15 UTC126
    while let Some(error) = current {
9a25b6ce66f4atagen2026-10-08 11:15 UTC127
        if let Some(error) = error.downcast_ref::<matrix_sdk::Error>() {
9a25b6ce66f4atagen2026-10-08 11:15 UTC128
            return classify_sdk_error(error);
9a25b6ce66f4atagen2026-10-08 11:15 UTC129
        }
9a25b6ce66f4atagen2026-10-08 11:15 UTC130
        if let Some(error) = error.downcast_ref::<HttpError>() {
9a25b6ce66f4atagen2026-10-08 11:15 UTC131
            return classify_http_error(error);
9a25b6ce66f4atagen2026-10-08 11:15 UTC132
        }
9a25b6ce66f4atagen2026-10-08 11:15 UTC133
        if let Some(error) = error.downcast_ref::<OAuthError>() {
9a25b6ce66f4atagen2026-10-08 11:15 UTC134
            return classify_oauth_error(error);
9a25b6ce66f4atagen2026-10-08 11:15 UTC135
        }
9a25b6ce66f4atagen2026-10-08 11:15 UTC136
        if let Some(error) = error.downcast_ref::<RefreshTokenError>() {
9a25b6ce66f4atagen2026-10-08 11:15 UTC137
            return classify_refresh_token_error(error);
9a25b6ce66f4atagen2026-10-08 11:15 UTC138
        }
9a25b6ce66f4atagen2026-10-08 11:15 UTC139
        current = error.source();
9a25b6ce66f4atagen2026-10-08 11:15 UTC140
    }
9a25b6ce66f4atagen2026-10-08 11:15 UTC141
    ErrorKind::Other
9a25b6ce66f4atagen2026-10-08 11:15 UTC142
}
9a25b6ce66f4atagen2026-10-08 11:15 UTC143
31ce2453c82fatagen2026-09-24 13:07 UTC144
impl Error {
31ce2453c82fatagen2026-09-24 13:07 UTC145
    pub(crate) fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC146
        Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC147
            kind,
96fdf90aacd6atagen2026-09-08 08:24 UTC148
            message: message.into(),
31ce2453c82fatagen2026-09-24 13:07 UTC149
            challenge: None,
9a25b6ce66f4atagen2026-10-08 11:15 UTC150
            server: None,
96fdf90aacd6atagen2026-09-08 08:24 UTC151
            source: None,
96fdf90aacd6atagen2026-09-08 08:24 UTC152
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC153
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC154
96fdf90aacd6atagen2026-09-08 08:24 UTC155
    pub(crate) fn with_source(
31ce2453c82fatagen2026-09-24 13:07 UTC156
        kind: ErrorKind,
96fdf90aacd6atagen2026-09-08 08:24 UTC157
        message: impl Into<String>,
1fe480c16a3catagen2026-09-26 08:44 UTC158
        source: impl std::error::Error + SendOutsideWasm + SyncOutsideWasm + 'static,
96fdf90aacd6atagen2026-09-08 08:24 UTC159
    ) -> Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC160
        Self {
9a25b6ce66f4atagen2026-10-08 11:15 UTC161
            server: ServerError::find(&source),
31ce2453c82fatagen2026-09-24 13:07 UTC162
            source: Some(Arc::new(source)),
31ce2453c82fatagen2026-09-24 13:07 UTC163
            ..Self::new(kind, message)
31ce2453c82fatagen2026-09-24 13:07 UTC164
        }
31ce2453c82fatagen2026-09-24 13:07 UTC165
    }
31ce2453c82fatagen2026-09-24 13:07 UTC166
31ce2453c82fatagen2026-09-24 13:07 UTC167
    pub(crate) fn interrupted() -> Self {
31ce2453c82fatagen2026-09-24 13:07 UTC168
        Self::new(
31ce2453c82fatagen2026-09-24 13:07 UTC169
            ErrorKind::Interrupted,
31ce2453c82fatagen2026-09-24 13:07 UTC170
            "the engine stopped before the operation finished",
31ce2453c82fatagen2026-09-24 13:07 UTC171
        )
31ce2453c82fatagen2026-09-24 13:07 UTC172
    }
31ce2453c82fatagen2026-09-24 13:07 UTC173
31ce2453c82fatagen2026-09-24 13:07 UTC174
    pub(crate) fn room_unknown() -> Self {
31ce2453c82fatagen2026-09-24 13:07 UTC175
        Self::new(
31ce2453c82fatagen2026-09-24 13:07 UTC176
            ErrorKind::RoomUnknown,
31ce2453c82fatagen2026-09-24 13:07 UTC177
            "room is not available in the local store",
31ce2453c82fatagen2026-09-24 13:07 UTC178
        )
31ce2453c82fatagen2026-09-24 13:07 UTC179
    }
31ce2453c82fatagen2026-09-24 13:07 UTC180
31ce2453c82fatagen2026-09-24 13:07 UTC181
    pub(crate) fn interactive_auth(challenge: InteractiveAuthChallenge) -> Self {
31ce2453c82fatagen2026-09-24 13:07 UTC182
        Self {
31ce2453c82fatagen2026-09-24 13:07 UTC183
            challenge: Some(Box::new(challenge)),
31ce2453c82fatagen2026-09-24 13:07 UTC184
            ..Self::new(
31ce2453c82fatagen2026-09-24 13:07 UTC185
                ErrorKind::InteractiveAuthRequired,
31ce2453c82fatagen2026-09-24 13:07 UTC186
                "interactive authentication is required",
31ce2453c82fatagen2026-09-24 13:07 UTC187
            )
96fdf90aacd6atagen2026-09-08 08:24 UTC188
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC189
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC190
96fdf90aacd6atagen2026-09-08 08:24 UTC191
    pub(crate) fn from_sdk(message: impl Into<String>, source: matrix_sdk::Error) -> Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC192
        Self::with_source(classify_sdk_error(&source), message, source)
96fdf90aacd6atagen2026-09-08 08:24 UTC193
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC194
96fdf90aacd6atagen2026-09-08 08:24 UTC195
    pub(crate) fn from_http(message: impl Into<String>, source: HttpError) -> Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC196
        Self::with_source(classify_http_error(&source), message, source)
96fdf90aacd6atagen2026-09-08 08:24 UTC197
    }
31ce2453c82fatagen2026-09-24 13:07 UTC198
96fdf90aacd6atagen2026-09-08 08:24 UTC199
    pub(crate) fn from_refresh_token(
96fdf90aacd6atagen2026-09-08 08:24 UTC200
        message: impl Into<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC201
        source: RefreshTokenError,
96fdf90aacd6atagen2026-09-08 08:24 UTC202
    ) -> Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC203
        Self::with_source(classify_refresh_token_error(&source), message, source)
96fdf90aacd6atagen2026-09-08 08:24 UTC204
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC205
96fdf90aacd6atagen2026-09-08 08:24 UTC206
    pub(crate) fn from_recovery(message: impl Into<String>, source: RecoveryError) -> Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC207
        let kind = match &source {
96fdf90aacd6atagen2026-09-08 08:24 UTC208
            RecoveryError::Sdk(source) => classify_sdk_error(source),
96fdf90aacd6atagen2026-09-08 08:24 UTC209
            RecoveryError::SecretStorage(SecretStorageError::Sdk(source)) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC210
                classify_sdk_error(source)
96fdf90aacd6atagen2026-09-08 08:24 UTC211
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC212
            RecoveryError::SecretStorage(SecretStorageError::ImportError { error, .. }) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC213
                match error {
96fdf90aacd6atagen2026-09-08 08:24 UTC214
                    ImportError::Sdk(source) => classify_sdk_error(source),
31ce2453c82fatagen2026-09-24 13:07 UTC215
                    _ => ErrorKind::RecoveryRejected,
96fdf90aacd6atagen2026-09-08 08:24 UTC216
                }
96fdf90aacd6atagen2026-09-08 08:24 UTC217
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC218
            RecoveryError::SecretStorage(SecretStorageError::Verification(source)) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC219
                match source {
96fdf90aacd6atagen2026-09-08 08:24 UTC220
                    ManualVerifyError::Http(source) => classify_http_error(source),
31ce2453c82fatagen2026-09-24 13:07 UTC221
                    _ => ErrorKind::RecoveryRejected,
96fdf90aacd6atagen2026-09-08 08:24 UTC222
                }
96fdf90aacd6atagen2026-09-08 08:24 UTC223
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC224
            RecoveryError::SecretStorage(SecretStorageError::SecretStorageKey(_)) => {
31ce2453c82fatagen2026-09-24 13:07 UTC225
                ErrorKind::RecoveryRejected
96fdf90aacd6atagen2026-09-08 08:24 UTC226
            }
31ce2453c82fatagen2026-09-24 13:07 UTC227
            RecoveryError::SecretStorage(SecretStorageError::Storage(_)) => ErrorKind::Store,
743123167e29atagen2026-10-26 04:02 UTC228
            RecoveryError::BackupExistsOnServer => ErrorKind::KeyBackupExists,
743123167e29atagen2026-10-26 04:02 UTC229
            RecoveryError::SecretStorage(_) => ErrorKind::RecoveryRejected,
96fdf90aacd6atagen2026-09-08 08:24 UTC230
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC231
        Self::with_source(kind, message, source)
96fdf90aacd6atagen2026-09-08 08:24 UTC232
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC233
96fdf90aacd6atagen2026-09-08 08:24 UTC234
    pub(crate) fn from_verification_request(
96fdf90aacd6atagen2026-09-08 08:24 UTC235
        message: impl Into<String>,
96fdf90aacd6atagen2026-09-08 08:24 UTC236
        source: RequestVerificationError,
96fdf90aacd6atagen2026-09-08 08:24 UTC237
    ) -> Self {
96fdf90aacd6atagen2026-09-08 08:24 UTC238
        let kind = match &source {
96fdf90aacd6atagen2026-09-08 08:24 UTC239
            RequestVerificationError::Sdk(source) => classify_sdk_error(source),
31ce2453c82fatagen2026-09-24 13:07 UTC240
            RequestVerificationError::RoomCreation(_) => ErrorKind::Encryption,
96fdf90aacd6atagen2026-09-08 08:24 UTC241
        };
96fdf90aacd6atagen2026-09-08 08:24 UTC242
        Self::with_source(kind, message, source)
96fdf90aacd6atagen2026-09-08 08:24 UTC243
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC244
}
96fdf90aacd6atagen2026-09-08 08:24 UTC245
31ce2453c82fatagen2026-09-24 13:07 UTC246
impl PartialEq for Error {
31ce2453c82fatagen2026-09-24 13:07 UTC247
    fn eq(&self, other: &Self) -> bool {
31ce2453c82fatagen2026-09-24 13:07 UTC248
        self.kind == other.kind
31ce2453c82fatagen2026-09-24 13:07 UTC249
            && self.message == other.message
31ce2453c82fatagen2026-09-24 13:07 UTC250
            && self.challenge == other.challenge
9a25b6ce66f4atagen2026-10-08 11:15 UTC251
            && self.server == other.server
31ce2453c82fatagen2026-09-24 13:07 UTC252
    }
31ce2453c82fatagen2026-09-24 13:07 UTC253
}
31ce2453c82fatagen2026-09-24 13:07 UTC254
31ce2453c82fatagen2026-09-24 13:07 UTC255
pub(crate) fn classify_sdk_error(source: &matrix_sdk::Error) -> ErrorKind {
96fdf90aacd6atagen2026-09-08 08:24 UTC256
    match source {
96fdf90aacd6atagen2026-09-08 08:24 UTC257
        matrix_sdk::Error::Http(source) => classify_http_error(source),
96fdf90aacd6atagen2026-09-08 08:24 UTC258
        matrix_sdk::Error::OAuth(source) => classify_oauth_error(source),
31ce2453c82fatagen2026-09-24 13:07 UTC259
        matrix_sdk::Error::AuthenticationRequired => ErrorKind::Unauthenticated,
96fdf90aacd6atagen2026-09-08 08:24 UTC260
        matrix_sdk::Error::BadCryptoStoreState
96fdf90aacd6atagen2026-09-08 08:24 UTC261
        | matrix_sdk::Error::CryptoStoreError(_)
96fdf90aacd6atagen2026-09-08 08:24 UTC262
        | matrix_sdk::Error::CrossProcessLockError(_)
96fdf90aacd6atagen2026-09-08 08:24 UTC263
        | matrix_sdk::Error::StateStore(_)
96fdf90aacd6atagen2026-09-08 08:24 UTC264
        | matrix_sdk::Error::EventCacheStore(_)
31ce2453c82fatagen2026-09-24 13:07 UTC265
        | matrix_sdk::Error::MediaStore(_) => ErrorKind::Store,
96fdf90aacd6atagen2026-09-08 08:24 UTC266
        matrix_sdk::Error::NoOlmMachine
96fdf90aacd6atagen2026-09-08 08:24 UTC267
        | matrix_sdk::Error::OlmError(_)
96fdf90aacd6atagen2026-09-08 08:24 UTC268
        | matrix_sdk::Error::MegolmError(_)
31ce2453c82fatagen2026-09-24 13:07 UTC269
        | matrix_sdk::Error::DecryptorError(_) => ErrorKind::Encryption,
31ce2453c82fatagen2026-09-24 13:07 UTC270
        matrix_sdk::Error::Media(_) => ErrorKind::MediaUnavailable,
31ce2453c82fatagen2026-09-24 13:07 UTC271
        matrix_sdk::Error::Timeout => ErrorKind::Network,
31ce2453c82fatagen2026-09-24 13:07 UTC272
        _ => ErrorKind::Other,
96fdf90aacd6atagen2026-09-08 08:24 UTC273
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC274
}
96fdf90aacd6atagen2026-09-08 08:24 UTC275
31ce2453c82fatagen2026-09-24 13:07 UTC276
fn classify_http_error(source: &HttpError) -> ErrorKind {
96fdf90aacd6atagen2026-09-08 08:24 UTC277
    match source {
31ce2453c82fatagen2026-09-24 13:07 UTC278
        HttpError::Reqwest(_) => ErrorKind::Network,
0291516d40b5atagen2026-10-22 08:31 UTC279
        HttpError::Api(_)
0291516d40b5atagen2026-10-22 08:31 UTC280
            if source
0291516d40b5atagen2026-10-22 08:31 UTC281
                .as_client_api_error()
0291516d40b5atagen2026-10-22 08:31 UTC282
                .is_some_and(|api| api.status_code.as_u16() == 429) =>
0291516d40b5atagen2026-10-22 08:31 UTC283
        {
0291516d40b5atagen2026-10-22 08:31 UTC284
            ErrorKind::RateLimited
0291516d40b5atagen2026-10-22 08:31 UTC285
        }
31ce2453c82fatagen2026-09-24 13:07 UTC286
        HttpError::Api(_) => ErrorKind::Server,
96fdf90aacd6atagen2026-09-08 08:24 UTC287
        HttpError::RefreshToken(source) => classify_refresh_token_error(source),
96fdf90aacd6atagen2026-09-08 08:24 UTC288
        HttpError::Cached(source) => classify_http_error(source),
31ce2453c82fatagen2026-09-24 13:07 UTC289
        _ => ErrorKind::Other,
96fdf90aacd6atagen2026-09-08 08:24 UTC290
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC291
}
96fdf90aacd6atagen2026-09-08 08:24 UTC292
31ce2453c82fatagen2026-09-24 13:07 UTC293
fn classify_refresh_token_error(source: &RefreshTokenError) -> ErrorKind {
96fdf90aacd6atagen2026-09-08 08:24 UTC294
    match source {
31ce2453c82fatagen2026-09-24 13:07 UTC295
        RefreshTokenError::RefreshTokenRequired => ErrorKind::Unauthenticated,
96fdf90aacd6atagen2026-09-08 08:24 UTC296
        RefreshTokenError::MatrixAuth(source) => classify_http_error(source),
96fdf90aacd6atagen2026-09-08 08:24 UTC297
        RefreshTokenError::OAuth(source) => classify_oauth_error(source),
96fdf90aacd6atagen2026-09-08 08:24 UTC298
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC299
}
96fdf90aacd6atagen2026-09-08 08:24 UTC300
31ce2453c82fatagen2026-09-24 13:07 UTC301
fn classify_oauth_error(source: &OAuthError) -> ErrorKind {
96fdf90aacd6atagen2026-09-08 08:24 UTC302
    let classify_token_request_error = |source: &_| match source {
31ce2453c82fatagen2026-09-24 13:07 UTC303
        RequestTokenError::Request(_) => ErrorKind::Network,
31ce2453c82fatagen2026-09-24 13:07 UTC304
        RequestTokenError::ServerResponse(_) => ErrorKind::Unauthenticated,
31ce2453c82fatagen2026-09-24 13:07 UTC305
        _ => ErrorKind::Other,
96fdf90aacd6atagen2026-09-08 08:24 UTC306
    };
96fdf90aacd6atagen2026-09-08 08:24 UTC307
    match source {
96fdf90aacd6atagen2026-09-08 08:24 UTC308
        OAuthError::Discovery(source) => match source {
96fdf90aacd6atagen2026-09-08 08:24 UTC309
            OAuthDiscoveryError::Http(source) => classify_http_error(source),
96fdf90aacd6atagen2026-09-08 08:24 UTC310
            OAuthDiscoveryError::Oidc(source) => classify_token_request_error(source),
31ce2453c82fatagen2026-09-24 13:07 UTC311
            _ => ErrorKind::Unauthenticated,
96fdf90aacd6atagen2026-09-08 08:24 UTC312
        },
96fdf90aacd6atagen2026-09-08 08:24 UTC313
        OAuthError::RefreshToken(source) => classify_token_request_error(source),
96fdf90aacd6atagen2026-09-08 08:24 UTC314
        OAuthError::AuthorizationCode(OAuthAuthorizationCodeError::RequestToken(source)) => {
96fdf90aacd6atagen2026-09-08 08:24 UTC315
            classify_token_request_error(source)
96fdf90aacd6atagen2026-09-08 08:24 UTC316
        }
31ce2453c82fatagen2026-09-24 13:07 UTC317
        OAuthError::AuthorizationCode(_) => ErrorKind::Unauthenticated,
96fdf90aacd6atagen2026-09-08 08:24 UTC318
        OAuthError::Logout(source) => match source {
31ce2453c82fatagen2026-09-24 13:07 UTC319
            OAuthTokenRevocationError::Revoke(RequestTokenError::Request(_)) => ErrorKind::Network,
96fdf90aacd6atagen2026-09-08 08:24 UTC320
            OAuthTokenRevocationError::Revoke(RequestTokenError::ServerResponse(_)) => {
31ce2453c82fatagen2026-09-24 13:07 UTC321
                ErrorKind::Unauthenticated
96fdf90aacd6atagen2026-09-08 08:24 UTC322
            }
31ce2453c82fatagen2026-09-24 13:07 UTC323
            _ => ErrorKind::Other,
96fdf90aacd6atagen2026-09-08 08:24 UTC324
        },
31ce2453c82fatagen2026-09-24 13:07 UTC325
        _ => ErrorKind::Unauthenticated,
96fdf90aacd6atagen2026-09-08 08:24 UTC326
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC327
}