codetether_agent/
cloudevents.rs1use axum::http::HeaderMap;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct CloudEvent {
7 pub id: String,
8 pub source: String,
9 #[serde(rename = "type")]
10 pub event_type: String,
11 #[serde(rename = "time")]
12 pub timestamp: Option<String>,
13 #[serde(rename = "specversion")]
14 pub spec_version: Option<String>,
15 #[serde(default)]
16 pub data: Value,
17}
18
19pub fn parse_cloud_event(headers: &HeaderMap, body: Value) -> Result<CloudEvent, String> {
20 if body.get("type").is_some() && body.get("source").is_some() && body.get("id").is_some() {
21 return serde_json::from_value(body).map_err(|err| err.to_string());
22 }
23 if body.get("task_id").is_none()
24 && body.get("id").is_none()
25 && header(headers, "ce-id").is_none()
26 {
27 return Err("request body is not a CloudEvent or task payload".to_string());
28 }
29 Ok(CloudEvent {
30 id: header(headers, "ce-id")
31 .or_else(|| body.get("id").and_then(Value::as_str).map(str::to_string))
32 .unwrap_or_else(|| "legacy-task-event".to_string()),
33 source: header(headers, "ce-source").unwrap_or_else(|| "codetether:legacy".to_string()),
34 event_type: header(headers, "ce-type")
35 .unwrap_or_else(|| "codetether.task.created".to_string()),
36 timestamp: header(headers, "ce-time"),
37 spec_version: header(headers, "ce-specversion").or(Some("1.0".to_string())),
38 data: body,
39 })
40}
41
42fn header(headers: &HeaderMap, name: &str) -> Option<String> {
43 headers
44 .get(name)
45 .and_then(|value| value.to_str().ok())
46 .map(str::to_string)
47}