1use alloc::string::{String, ToString};
7use alloc::vec::Vec;
8
9use crate::error::{ProtocolError, Result};
10use crate::header::MessageHeader;
11use crate::magic::MAX_PAYLOAD_SIZE;
12use crate::types::{ModuleId, RequestId};
13
14#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
15pub struct ErrorMessage {
16 pub header: MessageHeader,
17 pub error_code: u32,
18 pub error_message: String,
19 pub retry_after_ms: Option<u64>,
20}
21
22impl ErrorMessage {
23 pub fn new(request_id: RequestId, error_code: u32, error_message: String) -> Self {
24 let header = MessageHeader::new(
25 crate::types::MessageType::Error,
26 request_id,
27 0,
28 0,
29 0,
30 );
31
32 Self {
33 header,
34 error_code,
35 error_message,
36 retry_after_ms: None,
37 }
38 }
39
40 pub fn with_retry_after_ms(mut self, retry_after_ms: Option<u64>) -> Self {
41 self.retry_after_ms = retry_after_ms;
42 self
43 }
44
45 pub fn with_module_id(mut self, module_id: ModuleId) -> Self {
46 self.header = MessageHeader::new(
47 crate::types::MessageType::Error,
48 self.header.request_id(),
49 module_id,
50 self.header.method_hash(),
51 0,
52 );
53 self
54 }
55
56 pub fn request_id(&self) -> RequestId {
57 self.header.request_id()
58 }
59
60 pub fn error_code(&self) -> u32 {
61 self.error_code
62 }
63
64 pub fn error_message(&self) -> &str {
65 &self.error_message
66 }
67
68 pub fn retry_after_ms(&self) -> Option<u64> {
69 self.retry_after_ms
70 }
71
72 pub fn into_bytes(self) -> Result<Vec<u8>> {
73 let mut bytes = Vec::new();
74
75 bytes.extend_from_slice(&self.error_code.to_le_bytes());
76
77 let message_bytes = self.error_message.as_bytes();
78 bytes.extend_from_slice(&(message_bytes.len() as u32).to_le_bytes());
79 bytes.extend_from_slice(message_bytes);
80
81 let retry = self.retry_after_ms.unwrap_or(0);
82 bytes.extend_from_slice(&retry.to_le_bytes());
83
84 if bytes.len() > MAX_PAYLOAD_SIZE {
85 return Err(ProtocolError::PayloadTooLarge(bytes.len(), MAX_PAYLOAD_SIZE));
86 }
87
88 Ok(bytes)
89 }
90
91 pub fn from_bytes(payload: &[u8], header: MessageHeader) -> Result<Self> {
92 let mut offset = 0;
93
94 if offset + 4 > payload.len() {
95 return Err(ProtocolError::InvalidHeader(
96 "insufficient data for error_code".to_string(),
97 ));
98 }
99 let error_code =
100 u32::from_le_bytes([payload[offset], payload[offset + 1], payload[offset + 2], payload[offset + 3]]);
101 offset += 4;
102
103 if offset + 4 > payload.len() {
104 return Err(ProtocolError::InvalidHeader(
105 "insufficient data for error_message length".to_string(),
106 ));
107 }
108 let message_len =
109 u32::from_le_bytes([payload[offset], payload[offset + 1], payload[offset + 2], payload[offset + 3]])
110 as usize;
111 offset += 4;
112
113 if offset + message_len > payload.len() {
114 return Err(ProtocolError::InvalidHeader(
115 "insufficient data for error_message".to_string(),
116 ));
117 }
118 let message_bytes = &payload[offset..offset + message_len];
119 let error_message = String::from_utf8(message_bytes.to_vec()).map_err(|_| {
120 ProtocolError::InvalidHeader("error_message is not valid UTF-8".to_string())
121 })?;
122 offset += message_len;
123
124 if offset + 8 > payload.len() {
125 return Err(ProtocolError::InvalidHeader(
126 "insufficient data for retry_after_ms".to_string(),
127 ));
128 }
129 let retry = u64::from_le_bytes([
130 payload[offset],
131 payload[offset + 1],
132 payload[offset + 2],
133 payload[offset + 3],
134 payload[offset + 4],
135 payload[offset + 5],
136 payload[offset + 6],
137 payload[offset + 7],
138 ]);
139 let retry_after_ms = if retry == 0 { None } else { Some(retry) };
140
141 Ok(Self {
142 header,
143 error_code,
144 error_message,
145 retry_after_ms,
146 })
147 }
148}