1use std::fmt;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum ErrorCode {
15 FormatViolation,
16 GenericError,
17 InternalError,
18 MessageTypeNotSupported,
20 NotImplemented,
21 NotSupported,
22 OccurrenceConstraintViolation,
23 PropertyConstraintViolation,
24 ProtocolError,
25 RpcFrameworkError,
27 SecurityError,
28 TypeConstraintViolation,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum ErrorDialect {
33 Ocpp16,
35 Ocpp2,
37}
38
39impl ErrorCode {
40 pub fn as_wire(self, dialect: ErrorDialect) -> &'static str {
41 use ErrorCode::*;
42 match (self, dialect) {
43 (FormatViolation, ErrorDialect::Ocpp16) => "FormationViolation",
44 (FormatViolation, ErrorDialect::Ocpp2) => "FormatViolation",
45 (OccurrenceConstraintViolation, ErrorDialect::Ocpp16) => "OccurenceConstraintViolation",
46 (OccurrenceConstraintViolation, ErrorDialect::Ocpp2) => "OccurrenceConstraintViolation",
47 (MessageTypeNotSupported, ErrorDialect::Ocpp16) => "NotSupported",
49 (RpcFrameworkError, ErrorDialect::Ocpp16) => "ProtocolError",
50 (MessageTypeNotSupported, _) => "MessageTypeNotSupported",
51 (RpcFrameworkError, _) => "RpcFrameworkError",
52 (GenericError, _) => "GenericError",
53 (InternalError, _) => "InternalError",
54 (NotImplemented, _) => "NotImplemented",
55 (NotSupported, _) => "NotSupported",
56 (PropertyConstraintViolation, _) => "PropertyConstraintViolation",
57 (ProtocolError, _) => "ProtocolError",
58 (SecurityError, _) => "SecurityError",
59 (TypeConstraintViolation, _) => "TypeConstraintViolation",
60 }
61 }
62
63 pub fn from_wire(s: &str) -> ErrorCode {
65 use ErrorCode::*;
66 match s {
67 "FormatViolation" | "FormationViolation" => FormatViolation,
68 "OccurrenceConstraintViolation" | "OccurenceConstraintViolation" => {
69 OccurrenceConstraintViolation
70 }
71 "InternalError" => InternalError,
72 "MessageTypeNotSupported" => MessageTypeNotSupported,
73 "NotImplemented" => NotImplemented,
74 "NotSupported" => NotSupported,
75 "PropertyConstraintViolation" => PropertyConstraintViolation,
76 "ProtocolError" => ProtocolError,
77 "RpcFrameworkError" => RpcFrameworkError,
78 "SecurityError" => SecurityError,
79 "TypeConstraintViolation" => TypeConstraintViolation,
80 _ => GenericError,
81 }
82 }
83}
84
85impl fmt::Display for ErrorCode {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.write_str(self.as_wire(ErrorDialect::Ocpp2))
88 }
89}
90
91#[derive(Debug, Clone, PartialEq)]
93pub struct RpcError {
94 pub code: ErrorCode,
95 pub description: String,
97 pub details: serde_json::Value,
98}
99
100impl RpcError {
101 pub fn new(code: ErrorCode, description: impl Into<String>) -> Self {
102 RpcError {
103 code,
104 description: description.into(),
105 details: serde_json::Value::Object(Default::default()),
106 }
107 }
108
109 pub fn with_details(mut self, details: serde_json::Value) -> Self {
110 self.details = details;
111 self
112 }
113
114 pub fn not_implemented(action: &str) -> Self {
115 RpcError::new(
116 ErrorCode::NotImplemented,
117 format!("Action '{action}' is not known by this CSMS"),
118 )
119 }
120
121 pub fn not_supported(action: &str) -> Self {
122 RpcError::new(
123 ErrorCode::NotSupported,
124 format!("Action '{action}' is not supported by this CSMS"),
125 )
126 }
127
128 pub fn internal(msg: impl Into<String>) -> Self {
129 RpcError::new(ErrorCode::InternalError, msg)
130 }
131}
132
133impl fmt::Display for RpcError {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 write!(f, "{}: {}", self.code, self.description)
136 }
137}
138
139impl std::error::Error for RpcError {}
140
141impl From<crate::Violation> for RpcError {
142 fn from(v: crate::Violation) -> Self {
143 RpcError::new(v.kind.error_code(), v.to_string())
144 }
145}