use serde::Deserialize; use std::collections::HashMap; // Various helper constants for common error codes. pub const FORBIDDEN: &str = "M_FORBIDDEN"; pub const UNKNOWN_TOKEN: &str = "M_UNKNOWN_TOKEN"; pub const MISSING_TOKEN: &str = "M_MISSING_TOKEN"; pub const BAD_JSON: &str = "M_BAD_JSON"; pub const NOT_JSON: &str = "M_NOT_JSON"; pub const NOT_FOUND: &str = "M_NOT_FOUND"; pub const LIMIT_EXCEEDED: &str = "M_LIMIT_EXCEEDED"; pub const UNKNOWN: &str = "M_UNKNOWN"; pub const UNRECOGNIZED: &str = "M_UNRECOGNIZED"; pub const UNAUTHORIZED: &str = "M_UNAUTHORIZED"; pub const USER_IN_USE: &str = "M_USER_IN_USE"; pub const INVALID_USERNAME: &str = "M_INVALID_USERNAME"; pub const IN_USE: &str = "M_ROOM_IN_USE"; pub const STATE: &str = "M_INVALID_ROOM_STATE"; pub const THREEPID_IN_USE: &str = "M_THREEPID_IN_USE"; pub const THREEPID_NOT_FOUND: &str = "M_THREEPID_NOT_FOUND"; pub const THREEPID_AUTH_FAILED: &str = "M_THREEPID_AUTH_FAILED"; pub const THREEPID_DENIED: &str = "M_THREEPID_DENIED"; pub const SERVER_NOT_TRUSTED: &str = "M_SERVER_NOT_TRUSTED"; pub const UNSUPPORTED_ROOM_VERSION: &str = "M_UNSUPPORTED_ROOM_VERSION"; pub const INCOMPATIBLE_ROOM_VERSION: &str = "M_INCOMPATIBLE_ROOM_VERSION"; pub const BAD_STATE: &str = "M_BAD_STATE"; pub const GUEST_ACCESS_FORBIDDEN: &str = "M_GUEST_ACCESS_FORBIDDEN"; pub const CAPTCHA_NEEDED: &str = "M_CAPTCHA_NEEDED"; pub const CAPTCHA_INVALID: &str = "M_CAPTCHA_INVALID"; pub const MISSING_PARAM: &str = "M_MISSING_PARAM"; pub const INVALID_PARAM: &str = "M_INVALID_PARAM"; pub const TOO_LARGE: &str = "M_TOO_LARGE"; pub const EXCLUSIVE: &str = "M_EXCLUSIVE"; pub const RESOURCE_LIMIT_EXCEEDED: &str = "M_RESOURCE_LIMIT_EXCEEDED"; pub const CANNOT_LEAVE_SERVER_NOTICE_ROOM: &str = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM"; /// Implements the standard error response as defined by [Section 2](https://matrix.org/docs/spec/client_server/r0.5.0#api-standards) /// of the Client-Server API standard as a HashMap. We don't have a better way /// of representing this class, since we need to conform to having different /// fields for different errors. #[derive(Deserialize)] pub struct ApiError { #[serde(flatten)] pub data: HashMap, } impl ApiError { /// Helper function for obtaining the error code. Access the `errcode` /// field, which must be present on all valid error messages. pub fn error_code(&self) -> &str { self.data .get("errcode") .expect("Error did not contain required errcode field") } /// Helper function for obtaining the error message, which is a /// human-readable field that explains the issue. This accesses the `error` /// field, which must be present on all valid error messages. pub fn error_message(&self) -> &str { self.data .get("error") .expect("Error did not contain required error field") } } #[cfg(test)] mod tests { use super::*; #[test] fn deserialize_basic_error_msg() { let test_msg = r#"{"errcode": "M_FORBIDDEN", "error": "hello"}"#; let deserialized: ApiError = serde_json::from_str(test_msg).unwrap(); assert_eq!(deserialized.error_code(), FORBIDDEN); assert_eq!(deserialized.error_message(), "hello"); } #[test] fn deserialize_error_with_custom_field() { let test_msg = r#"{"errcode": "M_UNKNOWN", "error": "foo", "a": "b"}"#; let deserialized: ApiError = serde_json::from_str(test_msg).unwrap(); assert_eq!(deserialized.error_code(), UNKNOWN); assert_eq!(deserialized.error_message(), "foo"); assert_eq!(deserialized.data.get("a").unwrap(), "b"); } }