240 lines
6.8 KiB
Rust
240 lines
6.8 KiB
Rust
//! Errors that can be sent from the homeserver.
|
|
|
|
use std::fmt::{self, Display, Formatter};
|
|
|
|
use ruma_api::{error::ResponseDeserializationError, EndpointError};
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::{from_slice as from_json_slice, to_vec as to_json_vec};
|
|
use strum::{AsRefStr, Display, EnumString};
|
|
|
|
/// An enum for the error kind. Items may contain additional information.
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, AsRefStr, Display, EnumString)]
|
|
#[serde(tag = "errcode")]
|
|
#[cfg_attr(test, derive(PartialEq))]
|
|
pub enum ErrorKind {
|
|
/// M_FORBIDDEN
|
|
#[serde(rename = "M_FORBIDDEN")]
|
|
#[strum(to_string = "M_FORBIDDEN")]
|
|
Forbidden,
|
|
|
|
/// M_UNKNOWN_TOKEN
|
|
#[serde(rename = "M_UNKNOWN_TOKEN")]
|
|
#[strum(to_string = "M_UNKNOWN_TOKEN")]
|
|
UnknownToken {
|
|
/// If this is `true`, the client can acquire a new access token by specifying the device ID
|
|
/// it is already using to the login API. For more information, see [the spec].
|
|
///
|
|
/// [the spec]: https://matrix.org/docs/spec/client_server/r0.6.1#soft-logout
|
|
#[serde(default, skip_serializing_if = "ruma_serde::is_default")]
|
|
soft_logout: bool,
|
|
},
|
|
|
|
/// M_MISSING_TOKEN
|
|
#[serde(rename = "M_MISSING_TOKEN")]
|
|
#[strum(to_string = "M_MISSING_TOKEN")]
|
|
MissingToken,
|
|
|
|
/// M_BAD_JSON
|
|
#[serde(rename = "M_BAD_JSON")]
|
|
#[strum(to_string = "M_BAD_JSON")]
|
|
BadJson,
|
|
|
|
/// M_NOT_JSON
|
|
#[serde(rename = "M_NOT_JSON")]
|
|
#[strum(to_string = "M_NOT_JSON")]
|
|
NotJson,
|
|
|
|
/// M_NOT_FOUND
|
|
#[serde(rename = "M_NOT_FOUND")]
|
|
#[strum(to_string = "M_NOT_FOUND")]
|
|
NotFound,
|
|
|
|
/// M_LIMIT_EXCEEDED
|
|
#[serde(rename = "M_LIMIT_EXCEEDED")]
|
|
#[strum(to_string = "M_LIMIT_EXCEEDED")]
|
|
LimitExceeded,
|
|
|
|
/// M_UNKNOWN
|
|
#[serde(rename = "M_UNKNOWN")]
|
|
#[strum(to_string = "M_UNKNOWN")]
|
|
Unknown,
|
|
|
|
/// M_UNRECOGNIZED
|
|
#[serde(rename = "M_UNRECOGNIZED")]
|
|
#[strum(to_string = "M_UNRECOGNIZED")]
|
|
Unrecognized,
|
|
|
|
/// M_UNAUTHORIZED
|
|
#[serde(rename = "M_UNAUTHORIZED")]
|
|
#[strum(to_string = "M_UNAUTHORIZED")]
|
|
Unauthorized,
|
|
|
|
/// M_USER_DEACTIVATED
|
|
#[serde(rename = "M_USER_DEACTIVATED")]
|
|
#[strum(to_string = "M_USER_DEACTIVATED")]
|
|
UserDeactivated,
|
|
|
|
/// M_USER_IN_USE
|
|
#[serde(rename = "M_USER_IN_USE")]
|
|
#[strum(to_string = "M_USER_IN_USE")]
|
|
UserInUse,
|
|
|
|
/// M_INVALID_USERNAME
|
|
#[serde(rename = "M_INVALID_USERNAME")]
|
|
#[strum(to_string = "M_INVALID_USERNAME")]
|
|
InvalidUsername,
|
|
|
|
/// M_ROOM_IN_USE
|
|
#[serde(rename = "M_ROOM_IN_USE")]
|
|
#[strum(to_string = "M_ROOM_IN_USE")]
|
|
RoomInUse,
|
|
|
|
/// M_INVALID_ROOM_STATE
|
|
#[serde(rename = "M_INVALID_ROOM_STATE")]
|
|
#[strum(to_string = "M_INVALID_ROOM_STATE")]
|
|
InvalidRoomState,
|
|
|
|
/// M_THREEPID_IN_USE
|
|
#[serde(rename = "M_THREEPID_IN_USE")]
|
|
#[strum(to_string = "M_THREEPID_IN_USE")]
|
|
ThreepidInUse,
|
|
|
|
/// M_THREEPID_NOT_FOUND
|
|
#[serde(rename = "M_THREEPID_NOT_FOUND")]
|
|
#[strum(to_string = "M_THREEPID_NOT_FOUND")]
|
|
ThreepidNotFound,
|
|
|
|
/// M_THREEPID_AUTH_FAILED
|
|
#[serde(rename = "M_THREEPID_AUTH_FAILED")]
|
|
#[strum(to_string = "M_THREEPID_AUTH_FAILED")]
|
|
ThreepidAuthFailed,
|
|
|
|
/// M_THREEPID_DENIED
|
|
#[serde(rename = "M_THREEPID_DENIED")]
|
|
#[strum(to_string = "M_THREEPID_DENIED")]
|
|
ThreepidDenied,
|
|
|
|
/// M_SERVER_NOT_TRUSTED
|
|
#[serde(rename = "M_SERVER_NOT_TRUSTED")]
|
|
#[strum(to_string = "M_SERVER_NOT_TRUSTED")]
|
|
ServerNotTrusted,
|
|
|
|
/// M_UNSUPPORTED_ROOM_VERSION
|
|
#[serde(rename = "M_UNSUPPORTED_ROOM_VERSION")]
|
|
#[strum(to_string = "M_UNSUPPORTED_ROOM_VERSION")]
|
|
UnsupportedRoomVersion,
|
|
|
|
/// M_INCOMPATIBLE_ROOM_VERSION
|
|
#[serde(rename = "M_INCOMPATIBLE_ROOM_VERSION")]
|
|
#[strum(to_string = "M_INCOMPATIBLE_ROOM_VERSION")]
|
|
IncompatibleRoomVersion,
|
|
|
|
/// M_BAD_STATE
|
|
#[serde(rename = "M_BAD_STATE")]
|
|
#[strum(to_string = "M_BAD_STATE")]
|
|
BadState,
|
|
|
|
/// M_GUEST_ACCESS_FORBIDDEN
|
|
#[serde(rename = "M_GUEST_ACCESS_FORBIDDEN")]
|
|
#[strum(to_string = "M_GUEST_ACCESS_FORBIDDEN")]
|
|
GuestAccessForbidden,
|
|
|
|
/// M_CAPTCHA_NEEDED
|
|
#[serde(rename = "M_CAPTCHA_NEEDED")]
|
|
#[strum(to_string = "M_CAPTCHA_NEEDED")]
|
|
CaptchaNeeded,
|
|
|
|
/// M_CAPTCHA_INVALID
|
|
#[serde(rename = "M_CAPTCHA_INVALID")]
|
|
#[strum(to_string = "M_CAPTCHA_INVALID")]
|
|
CaptchaInvalid,
|
|
|
|
/// M_MISSING_PARAM
|
|
#[serde(rename = "M_MISSING_PARAM")]
|
|
#[strum(to_string = "M_MISSING_PARAM")]
|
|
MissingParam,
|
|
|
|
/// M_INVALID_PARAM
|
|
#[serde(rename = "M_INVALID_PARAM")]
|
|
#[strum(to_string = "M_INVALID_PARAM")]
|
|
InvalidParam,
|
|
|
|
/// M_TOO_LARGE
|
|
#[serde(rename = "M_TOO_LARGE")]
|
|
#[strum(to_string = "M_TOO_LARGE")]
|
|
TooLarge,
|
|
|
|
/// M_EXCLUSIVE
|
|
#[serde(rename = "M_EXCLUSIVE")]
|
|
#[strum(to_string = "M_EXCLUSIVE")]
|
|
Exclusive,
|
|
}
|
|
|
|
/// A Matrix Error without a status code
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[cfg_attr(test, derive(PartialEq))]
|
|
pub struct ErrorBody {
|
|
/// A value which can be used to handle an error message
|
|
#[serde(flatten)]
|
|
pub kind: ErrorKind,
|
|
|
|
/// A human-readable error message, usually a sentence explaining what went wrong.
|
|
#[serde(rename = "error")]
|
|
pub message: String,
|
|
}
|
|
|
|
/// A Matrix Error
|
|
#[derive(Debug, Clone)]
|
|
pub struct Error {
|
|
/// A value which can be used to handle an error message
|
|
pub kind: ErrorKind,
|
|
|
|
/// A human-readable error message, usually a sentence explaining what went wrong.
|
|
pub message: String,
|
|
|
|
/// The http status code
|
|
pub status_code: http::StatusCode,
|
|
}
|
|
|
|
impl EndpointError for Error {
|
|
fn try_from_response(
|
|
response: http::Response<Vec<u8>>,
|
|
) -> Result<Self, ResponseDeserializationError> {
|
|
match from_json_slice::<ErrorBody>(response.body()) {
|
|
Ok(error_body) => Ok(error_body.into_error(response.status())),
|
|
Err(de_error) => Err(ResponseDeserializationError::new(de_error, response)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for Error {
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
write!(f, "[{} / {}] {}", self.status_code.as_u16(), self.kind, self.message)
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for Error {}
|
|
|
|
impl From<Error> for ErrorBody {
|
|
fn from(error: Error) -> Self {
|
|
Self { kind: error.kind, message: error.message }
|
|
}
|
|
}
|
|
|
|
impl ErrorBody {
|
|
/// Convert the ErrorBody into an Error by adding the http status code.
|
|
pub fn into_error(self, status_code: http::StatusCode) -> Error {
|
|
Error { kind: self.kind, message: self.message, status_code }
|
|
}
|
|
}
|
|
|
|
impl From<Error> for http::Response<Vec<u8>> {
|
|
fn from(error: Error) -> http::Response<Vec<u8>> {
|
|
http::Response::builder()
|
|
.header(http::header::CONTENT_TYPE, "application/json")
|
|
.status(error.status_code)
|
|
.body(to_json_vec(&ErrorBody::from(error)).unwrap())
|
|
.unwrap()
|
|
}
|
|
}
|