1use crate::service_protocol::MessageType;
2use crate::CommandType;
3use std::borrow::Cow;
4use std::fmt;
5use std::time::Duration;
6
7pub use crate::vm::errors::{codes, InvocationErrorCode};
9
10#[derive(Debug, Clone, Eq, PartialEq)]
13pub(crate) struct CommandMetadata {
14 pub(crate) index: u32,
15 pub(crate) ty: MessageType,
16 pub(crate) name: Option<Cow<'static, str>>,
17}
18
19impl fmt::Display for CommandMetadata {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 write!(f, "{} ", self.ty)?;
22 if let Some(name) = &self.name {
23 write!(f, "[{name}]")?;
24 } else {
25 write!(f, "[{}]", self.index)?;
26 }
27 Ok(())
28 }
29}
30
31impl CommandMetadata {
32 pub(crate) fn new_named(
33 name: impl Into<Cow<'static, str>>,
34 index: u32,
35 ty: MessageType,
36 ) -> Self {
37 Self {
38 name: Some(name.into()),
39 index,
40 ty,
41 }
42 }
43
44 #[allow(unused)]
45 pub(crate) fn new(index: u32, ty: MessageType) -> Self {
46 Self {
47 name: None,
48 index,
49 ty,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Eq, PartialEq)]
55pub struct Error {
56 pub(crate) code: u16,
57 pub(crate) message: Cow<'static, str>,
58 pub(crate) stacktrace: String,
59 pub(crate) related_command: Option<CommandMetadata>,
60 pub(crate) next_retry_delay: Option<Duration>,
61}
62
63impl fmt::Display for Error {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write!(f, "({}) {}", self.code, self.message)?;
66 if !self.stacktrace.is_empty() {
67 write!(f, "\nStacktrace: {}", self.stacktrace)?;
68 }
69 if let Some(related_command) = &self.related_command {
70 write!(f, "\nRelated command: {related_command}")?;
71 }
72
73 Ok(())
74 }
75}
76
77impl std::error::Error for Error {}
78
79impl Error {
80 pub fn new(code: impl Into<u16>, message: impl Into<Cow<'static, str>>) -> Self {
81 Error {
82 code: code.into(),
83 message: message.into(),
84 stacktrace: Default::default(),
85 related_command: None,
86 next_retry_delay: None,
87 }
88 }
89
90 pub fn internal(message: impl Into<Cow<'static, str>>) -> Self {
91 Self::new(codes::INTERNAL, message)
92 }
93
94 pub fn code(&self) -> u16 {
95 self.code
96 }
97
98 pub fn message(&self) -> &str {
99 &self.message
100 }
101
102 pub fn description(&self) -> &str {
103 &self.stacktrace
104 }
105
106 pub fn with_stacktrace(mut self, stacktrace: impl ToString) -> Self {
107 self.stacktrace = stacktrace.to_string();
108 self
109 }
110
111 pub fn with_next_retry_delay_override(mut self, delay: Duration) -> Self {
112 self.next_retry_delay = Some(delay);
113 self
114 }
115
116 pub fn is_suspended_error(&self) -> bool {
117 self == &crate::vm::errors::SUSPENDED
118 }
119
120 pub(crate) fn with_related_command_metadata(
121 mut self,
122 related_command: CommandMetadata,
123 ) -> Self {
124 self.related_command = Some(related_command);
125 self
126 }
127}
128
129impl From<CommandType> for MessageType {
130 fn from(value: CommandType) -> Self {
131 match value {
132 CommandType::Input => MessageType::InputCommand,
133 CommandType::Output => MessageType::OutputCommand,
134 CommandType::GetState => MessageType::GetLazyStateCommand,
135 CommandType::GetStateKeys => MessageType::GetLazyStateKeysCommand,
136 CommandType::SetState => MessageType::SetStateCommand,
137 CommandType::ClearState => MessageType::ClearStateCommand,
138 CommandType::ClearAllState => MessageType::ClearAllStateCommand,
139 CommandType::GetPromise => MessageType::GetPromiseCommand,
140 CommandType::PeekPromise => MessageType::PeekPromiseCommand,
141 CommandType::CompletePromise => MessageType::CompletePromiseCommand,
142 CommandType::Sleep => MessageType::SleepCommand,
143 CommandType::Call => MessageType::CallCommand,
144 CommandType::OneWayCall => MessageType::OneWayCallCommand,
145 CommandType::SendSignal => MessageType::SendSignalCommand,
146 CommandType::Run => MessageType::RunCommand,
147 CommandType::AttachInvocation => MessageType::AttachInvocationCommand,
148 CommandType::GetInvocationOutput => MessageType::GetInvocationOutputCommand,
149 CommandType::CompleteAwakeable => MessageType::CompleteAwakeableCommand,
150 CommandType::CancelInvocation => MessageType::SendSignalCommand,
151 }
152 }
153}
154
155impl TryFrom<MessageType> for CommandType {
156 type Error = MessageType;
157
158 fn try_from(value: MessageType) -> Result<Self, Self::Error> {
159 match value {
160 MessageType::InputCommand => Ok(CommandType::Input),
161 MessageType::OutputCommand => Ok(CommandType::Output),
162 MessageType::GetLazyStateCommand | MessageType::GetEagerStateCommand => {
163 Ok(CommandType::GetState)
164 }
165 MessageType::GetLazyStateKeysCommand | MessageType::GetEagerStateKeysCommand => {
166 Ok(CommandType::GetStateKeys)
167 }
168 MessageType::SetStateCommand => Ok(CommandType::SetState),
169 MessageType::ClearStateCommand => Ok(CommandType::ClearState),
170 MessageType::ClearAllStateCommand => Ok(CommandType::ClearAllState),
171 MessageType::GetPromiseCommand => Ok(CommandType::GetPromise),
172 MessageType::PeekPromiseCommand => Ok(CommandType::PeekPromise),
173 MessageType::CompletePromiseCommand => Ok(CommandType::CompletePromise),
174 MessageType::SleepCommand => Ok(CommandType::Sleep),
175 MessageType::CallCommand => Ok(CommandType::Call),
176 MessageType::OneWayCallCommand => Ok(CommandType::OneWayCall),
177 MessageType::SendSignalCommand => Ok(CommandType::SendSignal),
178 MessageType::RunCommand => Ok(CommandType::Run),
179 MessageType::AttachInvocationCommand => Ok(CommandType::AttachInvocation),
180 MessageType::GetInvocationOutputCommand => Ok(CommandType::GetInvocationOutput),
181 MessageType::CompleteAwakeableCommand => Ok(CommandType::CompleteAwakeable),
182 _ => Err(value),
183 }
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_message_type_to_command_type_conversion() {
193 assert_eq!(
195 CommandType::try_from(MessageType::InputCommand).unwrap(),
196 CommandType::Input
197 );
198 assert_eq!(
199 CommandType::try_from(MessageType::OutputCommand).unwrap(),
200 CommandType::Output
201 );
202 assert_eq!(
203 CommandType::try_from(MessageType::GetLazyStateCommand).unwrap(),
204 CommandType::GetState
205 );
206 assert_eq!(
207 CommandType::try_from(MessageType::GetLazyStateKeysCommand).unwrap(),
208 CommandType::GetStateKeys
209 );
210 assert_eq!(
211 CommandType::try_from(MessageType::SetStateCommand).unwrap(),
212 CommandType::SetState
213 );
214 assert_eq!(
215 CommandType::try_from(MessageType::ClearStateCommand).unwrap(),
216 CommandType::ClearState
217 );
218 assert_eq!(
219 CommandType::try_from(MessageType::ClearAllStateCommand).unwrap(),
220 CommandType::ClearAllState
221 );
222 assert_eq!(
223 CommandType::try_from(MessageType::GetPromiseCommand).unwrap(),
224 CommandType::GetPromise
225 );
226 assert_eq!(
227 CommandType::try_from(MessageType::PeekPromiseCommand).unwrap(),
228 CommandType::PeekPromise
229 );
230 assert_eq!(
231 CommandType::try_from(MessageType::CompletePromiseCommand).unwrap(),
232 CommandType::CompletePromise
233 );
234 assert_eq!(
235 CommandType::try_from(MessageType::SleepCommand).unwrap(),
236 CommandType::Sleep
237 );
238 assert_eq!(
239 CommandType::try_from(MessageType::CallCommand).unwrap(),
240 CommandType::Call
241 );
242 assert_eq!(
243 CommandType::try_from(MessageType::OneWayCallCommand).unwrap(),
244 CommandType::OneWayCall
245 );
246 assert_eq!(
247 CommandType::try_from(MessageType::SendSignalCommand).unwrap(),
248 CommandType::SendSignal
249 );
250 assert_eq!(
251 CommandType::try_from(MessageType::RunCommand).unwrap(),
252 CommandType::Run
253 );
254 assert_eq!(
255 CommandType::try_from(MessageType::AttachInvocationCommand).unwrap(),
256 CommandType::AttachInvocation
257 );
258 assert_eq!(
259 CommandType::try_from(MessageType::GetInvocationOutputCommand).unwrap(),
260 CommandType::GetInvocationOutput
261 );
262 assert_eq!(
263 CommandType::try_from(MessageType::CompleteAwakeableCommand).unwrap(),
264 CommandType::CompleteAwakeable
265 );
266
267 assert_eq!(
269 CommandType::try_from(MessageType::Start).err().unwrap(),
270 MessageType::Start
271 );
272 assert_eq!(
273 CommandType::try_from(MessageType::End).err().unwrap(),
274 MessageType::End
275 );
276 assert_eq!(
277 CommandType::try_from(MessageType::GetLazyStateCompletionNotification)
278 .err()
279 .unwrap(),
280 MessageType::GetLazyStateCompletionNotification
281 );
282 }
283}