Skip to main content

codetether_agent/
cloudevents.rs

1use 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}