1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(deny_unknown_fields)]
10pub struct HttpPublicErrorEnvelope {
11 pub ok: bool,
12 pub error: HttpPublicError,
13}
14
15impl HttpPublicErrorEnvelope {
16 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
17 Self {
18 ok: false,
19 error: HttpPublicError {
20 code: code.into(),
21 message: message.into(),
22 issues: Vec::new(),
23 },
24 }
25 }
26
27 pub fn validation(
28 code: impl Into<String>,
29 message: impl Into<String>,
30 issues: Vec<ValidationIssue>,
31 ) -> Self {
32 Self {
33 ok: false,
34 error: HttpPublicError {
35 code: code.into(),
36 message: message.into(),
37 issues,
38 },
39 }
40 }
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44#[serde(deny_unknown_fields)]
45pub struct HttpPublicError {
46 pub code: String,
47 pub message: String,
48 #[serde(default, skip_serializing_if = "Vec::is_empty")]
49 pub issues: Vec<ValidationIssue>,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
53#[serde(rename_all = "snake_case")]
54pub enum ProtocolErrorCode {
55 ValidationFailed,
56 NotFound,
57 Conflict,
58 Unauthorized,
59 Forbidden,
60 PreconditionFailed,
61 UnsupportedProtocolVersion,
62 UnsupportedOperation,
63 OperationFailed,
64 OperationNotReady,
65 OperationResultUnavailable,
66 RateLimited,
67 Internal,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub struct ProtocolError {
72 #[serde(default, skip_serializing_if = "Vec::is_empty")]
73 pub adapter_observations: Vec<crate::diagnostics::DiagnosticFinding>,
74 pub code: ProtocolErrorCode,
75 pub message: String,
76 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub target: Option<String>,
78 #[serde(default, skip_serializing_if = "Vec::is_empty")]
79 pub issues: Vec<ValidationIssue>,
80 #[serde(default, skip_serializing_if = "Option::is_none")]
81 pub details: Option<ProtocolErrorDetails>,
82}
83
84impl ProtocolError {
85 pub fn new(code: ProtocolErrorCode, message: impl Into<String>) -> Self {
86 Self {
87 adapter_observations: Vec::new(),
88 code,
89 message: message.into(),
90 target: None,
91 issues: Vec::new(),
92 details: None,
93 }
94 }
95
96 pub fn validation(message: impl Into<String>, issues: Vec<ValidationIssue>) -> Self {
97 Self {
98 adapter_observations: Vec::new(),
99 code: ProtocolErrorCode::ValidationFailed,
100 message: message.into(),
101 target: None,
102 issues,
103 details: None,
104 }
105 }
106
107 pub fn with_target(mut self, target: impl Into<String>) -> Self {
108 self.target = Some(target.into());
109 self
110 }
111
112 pub fn with_details(mut self, details: ProtocolErrorDetails) -> Self {
113 self.details = Some(details);
114 self
115 }
116}
117
118impl std::fmt::Display for ProtocolError {
119 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 formatter.write_str(&self.message)
121 }
122}
123
124impl std::error::Error for ProtocolError {}
125
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
127pub struct ValidationIssue {
128 pub path: String,
129 pub code: ValidationIssueCode,
130 pub message: String,
131 #[serde(default, skip_serializing_if = "Option::is_none")]
132 pub details: Option<ValidationIssueDetails>,
133}
134
135impl ValidationIssue {
136 pub fn new(
137 path: impl Into<String>,
138 code: ValidationIssueCode,
139 message: impl Into<String>,
140 ) -> Self {
141 Self {
142 path: path.into(),
143 code,
144 message: message.into(),
145 details: None,
146 }
147 }
148}
149
150#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
151#[serde(rename_all = "snake_case")]
152pub enum ValidationIssueCode {
153 Required,
154 InvalidFormat,
155 InvalidValue,
156 OutOfRange,
157 TooLong,
158 TooShort,
159 TooManyItems,
160 TooFewItems,
161 Duplicate,
162 Conflict,
163 Unsupported,
164}
165
166#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
167#[serde(tag = "kind", rename_all = "snake_case")]
168pub enum ValidationIssueDetails {
169 Limit { limit: u64 },
170 Range { min: Option<i64>, max: Option<i64> },
171 AllowedValues { values: Vec<String> },
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175#[serde(tag = "kind", rename_all = "snake_case")]
176pub enum ProtocolErrorDetails {
177 ClientInventory {
178 observations: Vec<crate::session::SessionStatusPayload>,
179 },
180 ClientContext {
181 remote_session: Box<crate::session::SessionStatusPayload>,
182 reference: crate::refs::SessionRef,
183 },
184 IdempotencyConflict,
185 PreconditionFailed {
186 precondition: String,
187 },
188 UnsupportedProtocolVersion {
189 requested: String,
190 supported: String,
191 },
192 OperationResultUnavailable {
193 availability: String,
194 },
195 RetryAfter {
196 seconds: u64,
197 },
198}