use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ErrorCode {
FormatViolation,
GenericError,
InternalError,
MessageTypeNotSupported,
NotImplemented,
NotSupported,
OccurrenceConstraintViolation,
PropertyConstraintViolation,
ProtocolError,
RpcFrameworkError,
SecurityError,
TypeConstraintViolation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ErrorDialect {
Ocpp16,
Ocpp2,
}
impl ErrorCode {
pub fn as_wire(self, dialect: ErrorDialect) -> &'static str {
use ErrorCode::*;
match (self, dialect) {
(FormatViolation, ErrorDialect::Ocpp16) => "FormationViolation",
(FormatViolation, ErrorDialect::Ocpp2) => "FormatViolation",
(OccurrenceConstraintViolation, ErrorDialect::Ocpp16) => "OccurenceConstraintViolation",
(OccurrenceConstraintViolation, ErrorDialect::Ocpp2) => "OccurrenceConstraintViolation",
(MessageTypeNotSupported, ErrorDialect::Ocpp16) => "NotSupported",
(RpcFrameworkError, ErrorDialect::Ocpp16) => "ProtocolError",
(MessageTypeNotSupported, _) => "MessageTypeNotSupported",
(RpcFrameworkError, _) => "RpcFrameworkError",
(GenericError, _) => "GenericError",
(InternalError, _) => "InternalError",
(NotImplemented, _) => "NotImplemented",
(NotSupported, _) => "NotSupported",
(PropertyConstraintViolation, _) => "PropertyConstraintViolation",
(ProtocolError, _) => "ProtocolError",
(SecurityError, _) => "SecurityError",
(TypeConstraintViolation, _) => "TypeConstraintViolation",
}
}
pub fn from_wire(s: &str) -> ErrorCode {
use ErrorCode::*;
match s {
"FormatViolation" | "FormationViolation" => FormatViolation,
"OccurrenceConstraintViolation" | "OccurenceConstraintViolation" => {
OccurrenceConstraintViolation
}
"InternalError" => InternalError,
"MessageTypeNotSupported" => MessageTypeNotSupported,
"NotImplemented" => NotImplemented,
"NotSupported" => NotSupported,
"PropertyConstraintViolation" => PropertyConstraintViolation,
"ProtocolError" => ProtocolError,
"RpcFrameworkError" => RpcFrameworkError,
"SecurityError" => SecurityError,
"TypeConstraintViolation" => TypeConstraintViolation,
_ => GenericError,
}
}
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_wire(ErrorDialect::Ocpp2))
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RpcError {
pub code: ErrorCode,
pub description: String,
pub details: serde_json::Value,
}
impl RpcError {
pub fn new(code: ErrorCode, description: impl Into<String>) -> Self {
RpcError {
code,
description: description.into(),
details: serde_json::Value::Object(Default::default()),
}
}
pub fn with_details(mut self, details: serde_json::Value) -> Self {
self.details = details;
self
}
pub fn not_implemented(action: &str) -> Self {
RpcError::new(
ErrorCode::NotImplemented,
format!("Action '{action}' is not known by this CSMS"),
)
}
pub fn not_supported(action: &str) -> Self {
RpcError::new(
ErrorCode::NotSupported,
format!("Action '{action}' is not supported by this CSMS"),
)
}
pub fn internal(msg: impl Into<String>) -> Self {
RpcError::new(ErrorCode::InternalError, msg)
}
}
impl fmt::Display for RpcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.code, self.description)
}
}
impl std::error::Error for RpcError {}
impl From<crate::Violation> for RpcError {
fn from(v: crate::Violation) -> Self {
RpcError::new(v.kind.error_code(), v.to_string())
}
}