memlink_protocol/
request.rs1use 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::{Priority, RequestId, TraceId};
13
14#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
15pub struct Request {
16 pub header: MessageHeader,
17 pub module_name: String,
18 pub method_name: String,
19 pub args: Vec<u8>,
20 pub trace_id: TraceId,
21 pub deadline_ns: Option<u64>,
22}
23
24impl Request {
25 pub fn new(
26 request_id: RequestId,
27 _priority: Priority,
28 module: &str,
29 method: &str,
30 args: Vec<u8>,
31 ) -> Self {
32 let module_name = module.to_string();
33 let method_name = method.to_string();
34
35 let method_hash = compute_fnv1a_hash(method.as_bytes());
36 let module_id = compute_fnv1a_hash(module.as_bytes()) as u64;
37
38 let header = MessageHeader::new(
39 crate::types::MessageType::Request,
40 request_id,
41 module_id,
42 method_hash,
43 args.len() as u32,
44 );
45
46 Self {
47 header,
48 module_name,
49 method_name,
50 args,
51 trace_id: 0,
52 deadline_ns: None,
53 }
54 }
55
56 pub fn with_trace_id(mut self, trace_id: TraceId) -> Self {
57 self.trace_id = trace_id;
58 self
59 }
60
61 pub fn with_deadline_ns(mut self, deadline_ns: Option<u64>) -> Self {
62 self.deadline_ns = deadline_ns;
63 self
64 }
65
66 pub fn request_id(&self) -> RequestId {
67 self.header.request_id()
68 }
69
70 pub fn priority(&self) -> Priority {
71 Priority::Normal
72 }
73
74 pub fn module_name(&self) -> &str {
75 &self.module_name
76 }
77
78 pub fn method_name(&self) -> &str {
79 &self.method_name
80 }
81
82 pub fn args(&self) -> &[u8] {
83 &self.args
84 }
85
86 pub fn trace_id(&self) -> TraceId {
87 self.trace_id
88 }
89
90 pub fn deadline_ns(&self) -> Option<u64> {
91 self.deadline_ns
92 }
93
94 pub fn into_bytes(self) -> Result<Vec<u8>> {
95 let mut bytes = Vec::new();
96
97 let module_bytes = self.module_name.as_bytes();
98 bytes.extend_from_slice(&(module_bytes.len() as u32).to_le_bytes());
99 bytes.extend_from_slice(module_bytes);
100
101 let method_bytes = self.method_name.as_bytes();
102 bytes.extend_from_slice(&(method_bytes.len() as u32).to_le_bytes());
103 bytes.extend_from_slice(method_bytes);
104
105 bytes.extend_from_slice(&(self.args.len() as u32).to_le_bytes());
106 bytes.extend_from_slice(&self.args);
107
108 bytes.extend_from_slice(&self.trace_id.to_le_bytes());
109
110 let deadline = self.deadline_ns.unwrap_or(0);
111 bytes.extend_from_slice(&deadline.to_le_bytes());
112
113 if bytes.len() > MAX_PAYLOAD_SIZE {
114 return Err(ProtocolError::PayloadTooLarge(bytes.len(), MAX_PAYLOAD_SIZE));
115 }
116
117 Ok(bytes)
118 }
119
120 pub fn from_bytes(payload: &[u8], header: MessageHeader) -> Result<Self> {
121 let mut offset = 0;
122
123 if offset + 4 > payload.len() {
124 return Err(ProtocolError::InvalidHeader(
125 "insufficient data for module_name length".to_string(),
126 ));
127 }
128 let module_len =
129 u32::from_le_bytes([payload[offset], payload[offset + 1], payload[offset + 2], payload[offset + 3]])
130 as usize;
131 offset += 4;
132
133 if offset + module_len > payload.len() {
134 return Err(ProtocolError::InvalidHeader(
135 "insufficient data for module_name".to_string(),
136 ));
137 }
138 let module_bytes = &payload[offset..offset + module_len];
139 let module_name = String::from_utf8(module_bytes.to_vec()).map_err(|_| {
140 ProtocolError::InvalidHeader("module_name is not valid UTF-8".to_string())
141 })?;
142 offset += module_len;
143
144 if offset + 4 > payload.len() {
145 return Err(ProtocolError::InvalidHeader(
146 "insufficient data for method_name length".to_string(),
147 ));
148 }
149 let method_len =
150 u32::from_le_bytes([payload[offset], payload[offset + 1], payload[offset + 2], payload[offset + 3]])
151 as usize;
152 offset += 4;
153
154 if offset + method_len > payload.len() {
155 return Err(ProtocolError::InvalidHeader(
156 "insufficient data for method_name".to_string(),
157 ));
158 }
159 let method_bytes = &payload[offset..offset + method_len];
160 let method_name = String::from_utf8(method_bytes.to_vec()).map_err(|_| {
161 ProtocolError::InvalidHeader("method_name is not valid UTF-8".to_string())
162 })?;
163 offset += method_len;
164
165 if offset + 4 > payload.len() {
166 return Err(ProtocolError::InvalidHeader(
167 "insufficient data for args length".to_string(),
168 ));
169 }
170 let args_len =
171 u32::from_le_bytes([payload[offset], payload[offset + 1], payload[offset + 2], payload[offset + 3]])
172 as usize;
173 offset += 4;
174
175 if offset + args_len > payload.len() {
176 return Err(ProtocolError::InvalidHeader(
177 "insufficient data for args".to_string(),
178 ));
179 }
180 let args = payload[offset..offset + args_len].to_vec();
181 offset += args_len;
182
183 if offset + 16 > payload.len() {
184 return Err(ProtocolError::InvalidHeader(
185 "insufficient data for trace_id".to_string(),
186 ));
187 }
188 let trace_id = u128::from_le_bytes([
189 payload[offset],
190 payload[offset + 1],
191 payload[offset + 2],
192 payload[offset + 3],
193 payload[offset + 4],
194 payload[offset + 5],
195 payload[offset + 6],
196 payload[offset + 7],
197 payload[offset + 8],
198 payload[offset + 9],
199 payload[offset + 10],
200 payload[offset + 11],
201 payload[offset + 12],
202 payload[offset + 13],
203 payload[offset + 14],
204 payload[offset + 15],
205 ]);
206 offset += 16;
207
208 if offset + 8 > payload.len() {
209 return Err(ProtocolError::InvalidHeader(
210 "insufficient data for deadline_ns".to_string(),
211 ));
212 }
213 let deadline = u64::from_le_bytes([
214 payload[offset],
215 payload[offset + 1],
216 payload[offset + 2],
217 payload[offset + 3],
218 payload[offset + 4],
219 payload[offset + 5],
220 payload[offset + 6],
221 payload[offset + 7],
222 ]);
223 let deadline_ns = if deadline == 0 { None } else { Some(deadline) };
224
225 Ok(Self {
226 header,
227 module_name,
228 method_name,
229 args,
230 trace_id,
231 deadline_ns,
232 })
233 }
234}
235
236fn compute_fnv1a_hash(data: &[u8]) -> u32 {
237 const FNV_OFFSET_BASIS: u32 = 2166136261;
238 const FNV_PRIME: u32 = 16777619;
239
240 let mut hash = FNV_OFFSET_BASIS;
241 for byte in data {
242 hash ^= *byte as u32;
243 hash = hash.wrapping_mul(FNV_PRIME);
244 }
245 hash
246}