1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use uuid::Uuid;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8#[serde(rename_all = "UPPERCASE")]
9pub enum HttpMethod {
10 Get,
11 Post,
12 Put,
13 Patch,
14 Delete,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
23#[serde(tag = "type", rename_all = "lowercase")]
24pub enum HttpAuthConfig {
25 Hmac {
26 secret_key: String,
27 },
28 Bearer {
29 token_key: String,
30 },
31 #[serde(rename = "api_key")]
32 ApiKey {
33 header: String,
34 value_key: String,
35 },
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct HttpInvocationConfig {
42 pub url: String,
43 #[serde(default = "default_http_method")]
44 pub method: HttpMethod,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub timeout_ms: Option<u64>,
47 #[serde(default)]
48 pub headers: HashMap<String, String>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub auth: Option<HttpAuthConfig>,
51}
52
53fn default_http_method() -> HttpMethod {
54 HttpMethod::Post
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
63#[serde(tag = "type", rename_all = "lowercase")]
64pub enum TriggerAction {
65 Enqueue { queue: String },
67 Void,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct EnqueueResult {
74 #[serde(rename = "messageReceiptId")]
75 pub message_receipt_id: String,
76}
77
78#[derive(Debug, Clone)]
101pub struct TriggerRequest {
102 pub function_id: String,
103 pub payload: Value,
104 pub action: Option<TriggerAction>,
105 pub timeout_ms: Option<u64>,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109#[serde(tag = "type", rename_all = "lowercase")]
110pub enum Message {
111 RegisterTriggerType {
112 id: String,
113 description: String,
114 },
115 RegisterTrigger {
116 id: String,
117 trigger_type: String,
118 function_id: String,
119 config: Value,
120 },
121 TriggerRegistrationResult {
122 id: String,
123 trigger_type: String,
124 function_id: String,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 error: Option<ErrorBody>,
127 },
128 UnregisterTrigger {
129 id: String,
130 trigger_type: String,
131 },
132 UnregisterTriggerType {
133 id: String,
134 },
135 RegisterFunction {
136 id: String,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 description: Option<String>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 request_format: Option<Value>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 response_format: Option<Value>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 metadata: Option<Value>,
145 #[serde(skip_serializing_if = "Option::is_none")]
146 invocation: Option<HttpInvocationConfig>,
147 },
148 UnregisterFunction {
149 id: String,
150 },
151 InvokeFunction {
152 invocation_id: Option<Uuid>,
153 function_id: String,
154 data: Value,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 traceparent: Option<String>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 baggage: Option<String>,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 action: Option<TriggerAction>,
161 },
162 InvocationResult {
163 invocation_id: Uuid,
164 function_id: String,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 result: Option<Value>,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 error: Option<ErrorBody>,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 traceparent: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 baggage: Option<String>,
173 },
174 RegisterService {
175 id: String,
176 #[serde(default)]
177 name: String,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 description: Option<String>,
180 #[serde(default, skip_serializing_if = "Option::is_none")]
181 parent_service_id: Option<String>,
182 },
183 Ping,
184 Pong,
185 WorkerRegistered {
186 worker_id: String,
187 },
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
191pub struct RegisterTriggerTypeMessage {
192 pub id: String,
193 pub description: String,
194}
195
196impl RegisterTriggerTypeMessage {
197 pub fn to_message(&self) -> Message {
198 Message::RegisterTriggerType {
199 id: self.id.clone(),
200 description: self.description.clone(),
201 }
202 }
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct RegisterTriggerInput {
209 pub trigger_type: String,
210 pub function_id: String,
211 pub config: Value,
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct RegisterTriggerMessage {
216 pub id: String,
217 pub trigger_type: String,
218 pub function_id: String,
219 pub config: Value,
220}
221
222impl RegisterTriggerMessage {
223 pub fn to_message(&self) -> Message {
224 Message::RegisterTrigger {
225 id: self.id.clone(),
226 trigger_type: self.trigger_type.clone(),
227 function_id: self.function_id.clone(),
228 config: self.config.clone(),
229 }
230 }
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct UnregisterTriggerMessage {
235 pub id: String,
236 pub trigger_type: String,
237}
238
239impl UnregisterTriggerMessage {
240 pub fn to_message(&self) -> Message {
241 Message::UnregisterTrigger {
242 id: self.id.clone(),
243 trigger_type: self.trigger_type.clone(),
244 }
245 }
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct UnregisterTriggerTypeMessage {
250 pub id: String,
251}
252
253impl UnregisterTriggerTypeMessage {
254 pub fn to_message(&self) -> Message {
255 Message::UnregisterTriggerType {
256 id: self.id.clone(),
257 }
258 }
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct RegisterFunctionMessage {
263 pub id: String,
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub description: Option<String>,
266 #[serde(skip_serializing_if = "Option::is_none")]
267 pub request_format: Option<Value>,
268 #[serde(skip_serializing_if = "Option::is_none")]
269 pub response_format: Option<Value>,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub metadata: Option<Value>,
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub invocation: Option<HttpInvocationConfig>,
274}
275
276impl RegisterFunctionMessage {
277 pub fn with_id(name: String) -> Self {
278 RegisterFunctionMessage {
279 id: name,
280 description: None,
281 request_format: None,
282 response_format: None,
283 metadata: None,
284 invocation: None,
285 }
286 }
287 pub fn with_description(mut self, description: String) -> Self {
288 self.description = Some(description);
289 self
290 }
291 pub fn to_message(&self) -> Message {
292 Message::RegisterFunction {
293 id: self.id.clone(),
294 description: self.description.clone(),
295 request_format: self.request_format.clone(),
296 response_format: self.response_format.clone(),
297 metadata: self.metadata.clone(),
298 invocation: self.invocation.clone(),
299 }
300 }
301}
302
303#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct RegisterServiceMessage {
305 pub id: String,
306 pub name: String,
307 #[serde(skip_serializing_if = "Option::is_none")]
308 pub description: Option<String>,
309 #[serde(default, skip_serializing_if = "Option::is_none")]
310 pub parent_service_id: Option<String>,
311}
312
313impl RegisterServiceMessage {
314 pub fn to_message(&self) -> Message {
315 Message::RegisterService {
316 id: self.id.clone(),
317 name: self.name.clone(),
318 description: self.description.clone(),
319 parent_service_id: self.parent_service_id.clone(),
320 }
321 }
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct FunctionMessage {
326 pub function_id: String,
327 #[serde(skip_serializing_if = "Option::is_none")]
328 pub description: Option<String>,
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub request_format: Option<Value>,
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub response_format: Option<Value>,
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub metadata: Option<Value>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize)]
338#[non_exhaustive]
339pub struct ErrorBody {
340 pub code: String,
341 pub message: String,
342 #[serde(skip_serializing_if = "Option::is_none")]
343 pub stacktrace: Option<String>,
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn register_function_to_message_and_serializes_type() {
352 let msg = RegisterFunctionMessage {
353 id: "functions.echo".to_string(),
354 description: Some("Echo function".to_string()),
355 request_format: None,
356 response_format: None,
357 metadata: None,
358 invocation: None,
359 };
360
361 let message = msg.to_message();
362 match &message {
363 Message::RegisterFunction {
364 id, description, ..
365 } => {
366 assert_eq!(id, "functions.echo");
367 assert_eq!(description.as_deref(), Some("Echo function"));
368 }
369 _ => panic!("unexpected message variant"),
370 }
371
372 let serialized = serde_json::to_value(&message).unwrap();
373 assert_eq!(serialized["type"], "registerfunction");
374 assert_eq!(serialized["id"], "functions.echo");
375 assert_eq!(serialized["description"], "Echo function");
376 }
377
378 #[test]
379 fn register_http_function_serializes_invocation() {
380 use super::{HttpInvocationConfig, HttpMethod};
381
382 let msg = RegisterFunctionMessage {
383 id: "external::my_lambda".to_string(),
384 description: None,
385 request_format: None,
386 response_format: None,
387 metadata: None,
388 invocation: Some(HttpInvocationConfig {
389 url: "https://example.com/invoke".to_string(),
390 method: HttpMethod::Post,
391 timeout_ms: Some(30000),
392 headers: HashMap::new(),
393 auth: None,
394 }),
395 };
396
397 let serialized = serde_json::to_value(msg.to_message()).unwrap();
398 assert_eq!(serialized["type"], "registerfunction");
399 assert_eq!(serialized["id"], "external::my_lambda");
400 assert!(serialized["invocation"].is_object());
401 assert_eq!(
402 serialized["invocation"]["url"],
403 "https://example.com/invoke"
404 );
405 assert_eq!(serialized["invocation"]["method"], "POST");
406 }
407}