Skip to main content

matrixcode_core/matrixrpc/protocol/
error.rs

1//! JSON-RPC 2.0 Error Codes and Types
2//!
3//! Defines standard and custom error codes per JSON-RPC 2.0 specification.
4
5use serde::{Deserialize, Serialize};
6
7/// JSON-RPC 2.0 standard error codes
8///
9/// Reference: https://www.jsonrpc.org/specification#error_object
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(transparent)]
12pub struct ErrorCode(pub i64);
13
14impl ErrorCode {
15    // ============== Standard JSON-RPC 2.0 Error Codes ==============
16
17    /// Invalid JSON was received by the server.
18    /// An error occurred on the server while parsing the JSON text.
19    pub const PARSE_ERROR: Self = ErrorCode(-32700);
20
21    /// The JSON sent is not a valid Request object.
22    pub const INVALID_REQUEST: Self = ErrorCode(-32600);
23
24    /// The method does not exist / is not available.
25    pub const METHOD_NOT_FOUND: Self = ErrorCode(-32601);
26
27    /// Invalid method parameter(s).
28    pub const INVALID_PARAMS: Self = ErrorCode(-32602);
29
30    /// Internal JSON-RPC error.
31    pub const INTERNAL_ERROR: Self = ErrorCode(-32603);
32
33    // ============== MatrixRPC Custom Error Codes ==============
34
35    /// Server is shutting down
36    pub const SERVER_SHUTDOWN: Self = ErrorCode(-32000);
37
38    /// Transport error
39    pub const TRANSPORT_ERROR: Self = ErrorCode(-32001);
40
41    /// Timeout error
42    pub const TIMEOUT_ERROR: Self = ErrorCode(-32002);
43
44    /// Capability not supported
45    pub const CAPABILITY_NOT_SUPPORTED: Self = ErrorCode(-32003);
46
47    /// Resource not found
48    pub const RESOURCE_NOT_FOUND: Self = ErrorCode(-32004);
49
50    /// Resource already exists
51    pub const RESOURCE_EXISTS: Self = ErrorCode(-32005);
52
53    /// Permission denied
54    pub const PERMISSION_DENIED: Self = ErrorCode(-32006);
55
56    /// Invalid state for operation
57    pub const INVALID_STATE: Self = ErrorCode(-32007);
58
59    /// Callback registration failed
60    pub const CALLBACK_ERROR: Self = ErrorCode(-32008);
61
62    /// Get the error message for this code
63    pub fn message(&self) -> &'static str {
64        match self.0 {
65            -32700 => "Parse error",
66            -32600 => "Invalid request",
67            -32601 => "Method not found",
68            -32602 => "Invalid params",
69            -32603 => "Internal error",
70            -32000 => "Server shutdown",
71            -32001 => "Transport error",
72            -32002 => "Timeout",
73            -32003 => "Capability not supported",
74            -32004 => "Resource not found",
75            -32005 => "Resource already exists",
76            -32006 => "Permission denied",
77            -32007 => "Invalid state",
78            -32008 => "Callback error",
79            _ => "Unknown error",
80        }
81    }
82
83    /// Check if this is a standard JSON-RPC error code
84    pub fn is_standard(&self) -> bool {
85        (-32700..=-32603).contains(&self.0)
86    }
87
88    /// Check if this is a custom MatrixRPC error code
89    pub fn is_custom(&self) -> bool {
90        (-32099..=-32000).contains(&self.0)
91    }
92}
93
94impl std::fmt::Display for ErrorCode {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        write!(f, "{}", self.0)
97    }
98}
99
100impl From<i64> for ErrorCode {
101    fn from(code: i64) -> Self {
102        ErrorCode(code)
103    }
104}
105
106impl From<ErrorCode> for i64 {
107    fn from(code: ErrorCode) -> Self {
108        code.0
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn test_standard_error_codes() {
118        assert_eq!(ErrorCode::PARSE_ERROR.0, -32700);
119        assert_eq!(ErrorCode::INVALID_REQUEST.0, -32600);
120        assert_eq!(ErrorCode::METHOD_NOT_FOUND.0, -32601);
121        assert_eq!(ErrorCode::INVALID_PARAMS.0, -32602);
122        assert_eq!(ErrorCode::INTERNAL_ERROR.0, -32603);
123    }
124
125    #[test]
126    fn test_custom_error_codes() {
127        assert_eq!(ErrorCode::SERVER_SHUTDOWN.0, -32000);
128        assert_eq!(ErrorCode::TRANSPORT_ERROR.0, -32001);
129        assert_eq!(ErrorCode::TIMEOUT_ERROR.0, -32002);
130    }
131
132    #[test]
133    fn test_error_messages() {
134        assert_eq!(ErrorCode::PARSE_ERROR.message(), "Parse error");
135        assert_eq!(ErrorCode::METHOD_NOT_FOUND.message(), "Method not found");
136        assert_eq!(ErrorCode::SERVER_SHUTDOWN.message(), "Server shutdown");
137    }
138
139    #[test]
140    fn test_is_standard() {
141        assert!(ErrorCode::PARSE_ERROR.is_standard());
142        assert!(ErrorCode::INTERNAL_ERROR.is_standard());
143        assert!(!ErrorCode::SERVER_SHUTDOWN.is_standard());
144    }
145
146    #[test]
147    fn test_is_custom() {
148        assert!(ErrorCode::SERVER_SHUTDOWN.is_custom());
149        assert!(!ErrorCode::PARSE_ERROR.is_custom());
150    }
151
152    #[test]
153    fn test_error_code_serde() {
154        let code = ErrorCode::INVALID_PARAMS;
155        let json = serde_json::to_string(&code).unwrap();
156        assert_eq!(json, "-32602");
157
158        let decoded: ErrorCode = serde_json::from_str(&json).unwrap();
159        assert_eq!(decoded, code);
160    }
161}