ds_event_stream_rs_sdk/model/
v1.rs

1// event_stream.rs
2use std::hash::{Hash, Hasher};
3
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use uuid::Uuid;
8
9// region: --> EventStream
10
11/// Generic Event-Stream envelope (Event V1).
12///
13/// This struct matches the Event V1 schema exactly.
14/// All required and optional fields are included, with correct types.
15#[derive(Debug, Serialize, Deserialize)]
16pub struct EventStream {
17    /* -------- required core ------------------------------------------- */
18    pub id: Uuid,
19    pub session_id: Uuid,
20    pub tenant_id: Uuid,
21    pub event_source: String,
22    pub event_type: String,
23    pub timestamp: DateTime<Utc>,
24    pub created_by: String,
25    pub md5_hash: String,
26
27    /* -------- optional context ---------------------------------------- */
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub request_id: Option<Uuid>,
30
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub owner_id: Option<String>,
33
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub product_id: Option<Uuid>,
36
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub product_schema_uri: Option<String>,
39
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub event_source_uri: Option<String>,
42
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub affected_entity_uri: Option<String>,
45
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub message: Option<String>,
48
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub payload: Option<Value>,
51
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub payload_uri: Option<String>,
54
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub context: Option<Value>,
57
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub context_uri: Option<String>,
60
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub metadata: Option<Value>,
63
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub tags: Option<Value>,
66}
67
68impl EventStream {
69    /// Compute hash for the given payload
70    /// # Arguments
71    /// * `payload` - The payload to compute the hash for
72    /// # Returns
73    /// * `String` - The hash of the payload
74    fn compute_payload_hash(payload: &Option<Value>) -> String {
75        match payload {
76            Some(payload) => {
77                let payload_str = serde_json::to_string(payload).unwrap_or_default();
78                let mut hasher = std::collections::hash_map::DefaultHasher::new();
79                payload_str.hash(&mut hasher);
80                format!("{:x}", hasher.finish())
81            }
82            None => String::new(),
83        }
84    }
85
86    /// Create a new EventStream
87    /// # Arguments
88    /// * `session_id` - The session ID
89    /// * `tenant_id` - The tenant ID
90    /// * `event_source` - The event source
91    /// * `event_type` - The event type
92    /// * `created_by` - The created by
93    /// * `request_id` - The request ID
94    /// * `owner_id` - The owner ID
95    /// * `product_id` - The product ID
96    /// * `product_schema_uri` - The product schema URI
97    /// * `event_source_uri` - The event source URI
98    /// * `affected_entity_uri` - The affected entity URI
99    /// * `message` - The message
100    /// * `payload` - The payload
101    /// * `payload_uri` - The payload URI
102    /// * `context` - The context
103    /// * `context_uri` - The context URI
104    /// * `metadata` - The metadata
105    /// * `tags` - The tags
106    /// # Returns
107    /// * `EventStream` - The new EventStream
108    #[allow(clippy::too_many_arguments)]
109    pub fn new(
110        session_id: Uuid,
111        tenant_id: Uuid,
112        event_source: String,
113        event_type: String,
114        created_by: String,
115        request_id: Option<Uuid>,
116        owner_id: Option<String>,
117        product_id: Option<Uuid>,
118        product_schema_uri: Option<String>,
119        event_source_uri: Option<String>,
120        affected_entity_uri: Option<String>,
121        message: Option<String>,
122        payload: Option<Value>,
123        payload_uri: Option<String>,
124        context: Option<Value>,
125        context_uri: Option<String>,
126        metadata: Option<Value>,
127        tags: Option<Value>,
128    ) -> Self {
129        let md5_hash = Self::compute_payload_hash(&payload);
130        Self {
131            id: Uuid::new_v4(),
132            session_id,
133            tenant_id,
134            event_source,
135            event_type,
136            timestamp: Utc::now(),
137            created_by,
138            md5_hash,
139            request_id,
140            owner_id,
141            product_id,
142            product_schema_uri,
143            event_source_uri,
144            affected_entity_uri,
145            message,
146            payload,
147            payload_uri,
148            context,
149            context_uri,
150            metadata,
151            tags,
152        }
153    }
154}
155
156// endregion: --> EventStream