use std::io;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ProtocolError {
#[error("IO error: {0}")]
Io(#[from] io::Error),
#[error("JSON serialization error: {0}")]
JsonSerialization(#[from] serde_json::Error),
#[error("Message too large: {size} bytes (max: {max})")]
MessageTooLarge { size: usize, max: usize },
#[error("Invalid message format: {0}")]
InvalidFormat(String),
#[error("Connection closed")]
ConnectionClosed,
#[error("Timeout after {0:?}")]
Timeout(std::time::Duration),
#[error("Authentication failed: {0}")]
AuthenticationFailed(String),
#[error("Permission denied: {0}")]
PermissionDenied(String),
#[error("Invalid peer credentials")]
InvalidCredentials,
#[error("JSON-RPC error: {code} - {message}")]
JsonRpc { code: i32, message: String },
#[error("Method not found: {0}")]
MethodNotFound(String),
#[error("Invalid parameters: {0}")]
InvalidParams(String),
#[error("Internal error: {0}")]
Internal(String),
#[error("Rate limit exceeded")]
RateLimitExceeded,
#[error("ACL denied: {0}")]
AclDenied(String),
#[error("Plugin error: {0}")]
PluginError(String),
}
pub type ProtocolResult<T> = Result<T, ProtocolError>;
impl ProtocolError {
pub fn to_error_code(&self) -> i32 {
use super::jsonrpc::error_codes;
match self {
ProtocolError::JsonSerialization(_) => error_codes::PARSE_ERROR,
ProtocolError::InvalidFormat(_) => error_codes::INVALID_REQUEST,
ProtocolError::MethodNotFound(_) => error_codes::METHOD_NOT_FOUND,
ProtocolError::InvalidParams(_) => error_codes::INVALID_PARAMS,
ProtocolError::Internal(_) => error_codes::INTERNAL_ERROR,
ProtocolError::AuthenticationFailed(_) => error_codes::UNAUTHORIZED,
ProtocolError::PermissionDenied(_) => error_codes::FORBIDDEN,
ProtocolError::InvalidCredentials => error_codes::UNAUTHORIZED,
ProtocolError::RateLimitExceeded => error_codes::RATE_LIMITED,
ProtocolError::Timeout(_) => error_codes::TIMEOUT,
ProtocolError::PluginError(_) => error_codes::PLUGIN_ERROR,
ProtocolError::AclDenied(_) => error_codes::ACL_DENIED,
ProtocolError::JsonRpc { code, .. } => *code,
_ => error_codes::INTERNAL_ERROR,
}
}
pub fn to_error_message(&self) -> String {
self.to_string()
}
pub fn from_jsonrpc_error(code: i32, message: String) -> Self {
use super::jsonrpc::error_codes;
match code {
error_codes::METHOD_NOT_FOUND => ProtocolError::MethodNotFound(message),
error_codes::INVALID_PARAMS => ProtocolError::InvalidParams(message),
error_codes::UNAUTHORIZED => ProtocolError::AuthenticationFailed(message),
error_codes::FORBIDDEN => ProtocolError::PermissionDenied(message),
error_codes::RATE_LIMITED => ProtocolError::RateLimitExceeded,
error_codes::TIMEOUT => {
ProtocolError::Timeout(std::time::Duration::from_secs(30))
}
error_codes::PLUGIN_ERROR => ProtocolError::PluginError(message),
error_codes::ACL_DENIED => ProtocolError::AclDenied(message),
_ => ProtocolError::JsonRpc { code, message },
}
}
pub fn to_jsonrpc_error(&self) -> super::jsonrpc::JsonRpcError {
super::jsonrpc::JsonRpcError {
code: self.to_error_code(),
message: self.to_error_message(),
data: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_code_mapping() {
use crate::protocol::jsonrpc::error_codes;
let err = ProtocolError::MethodNotFound("test".to_string());
assert_eq!(err.to_error_code(), error_codes::METHOD_NOT_FOUND);
let err = ProtocolError::InvalidParams("bad params".to_string());
assert_eq!(err.to_error_code(), error_codes::INVALID_PARAMS);
let err = ProtocolError::RateLimitExceeded;
assert_eq!(err.to_error_code(), error_codes::RATE_LIMITED);
}
#[test]
fn test_from_jsonrpc_error() {
use crate::protocol::jsonrpc::error_codes;
let err = ProtocolError::from_jsonrpc_error(
error_codes::METHOD_NOT_FOUND,
"method not found".to_string(),
);
assert!(matches!(err, ProtocolError::MethodNotFound(_)));
let err = ProtocolError::from_jsonrpc_error(
error_codes::ACL_DENIED,
"access denied".to_string(),
);
assert!(matches!(err, ProtocolError::AclDenied(_)));
}
#[test]
fn test_to_jsonrpc_error() {
let err = ProtocolError::PermissionDenied("not allowed".to_string());
let jsonrpc_err = err.to_jsonrpc_error();
assert_eq!(jsonrpc_err.code, -32001); assert_eq!(jsonrpc_err.message, "Permission denied: not allowed");
}
}