engram/realtime/
events.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::types::MemoryId;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum EventType {
12 MemoryCreated,
13 MemoryUpdated,
14 MemoryDeleted,
15 CrossrefCreated,
16 CrossrefDeleted,
17 SyncStarted,
18 SyncCompleted,
19 SyncFailed,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct RealtimeEvent {
25 #[serde(skip_serializing_if = "Option::is_none")]
28 pub seq_id: Option<u64>,
29 #[serde(rename = "type")]
31 pub event_type: EventType,
32 pub timestamp: DateTime<Utc>,
34 pub memory_id: Option<MemoryId>,
36 pub preview: Option<String>,
38 pub changes: Option<Vec<String>>,
40 pub data: Option<serde_json::Value>,
42}
43
44impl RealtimeEvent {
45 pub fn memory_created(id: MemoryId, preview: String) -> Self {
47 Self {
48 seq_id: None,
49 event_type: EventType::MemoryCreated,
50 timestamp: Utc::now(),
51 memory_id: Some(id),
52 preview: Some(truncate(&preview, 100)),
53 changes: None,
54 data: None,
55 }
56 }
57
58 pub fn memory_updated(id: MemoryId, changes: Vec<String>) -> Self {
60 Self {
61 seq_id: None,
62 event_type: EventType::MemoryUpdated,
63 timestamp: Utc::now(),
64 memory_id: Some(id),
65 preview: None,
66 changes: Some(changes),
67 data: None,
68 }
69 }
70
71 pub fn memory_deleted(id: MemoryId) -> Self {
73 Self {
74 seq_id: None,
75 event_type: EventType::MemoryDeleted,
76 timestamp: Utc::now(),
77 memory_id: Some(id),
78 preview: None,
79 changes: None,
80 data: None,
81 }
82 }
83
84 pub fn sync_completed(direction: &str, changes: i64) -> Self {
86 Self {
87 seq_id: None,
88 event_type: EventType::SyncCompleted,
89 timestamp: Utc::now(),
90 memory_id: None,
91 preview: None,
92 changes: None,
93 data: Some(serde_json::json!({
94 "direction": direction,
95 "changes": changes,
96 })),
97 }
98 }
99
100 pub fn sync_failed(error: &str) -> Self {
102 Self {
103 seq_id: None,
104 event_type: EventType::SyncFailed,
105 timestamp: Utc::now(),
106 memory_id: None,
107 preview: None,
108 changes: None,
109 data: Some(serde_json::json!({
110 "error": error,
111 })),
112 }
113 }
114}
115
116fn truncate(s: &str, max: usize) -> String {
118 if s.chars().count() <= max {
119 s.to_string()
120 } else {
121 let truncated: String = s.chars().take(max.saturating_sub(3)).collect();
123 format!("{}...", truncated)
124 }
125}
126
127#[derive(Debug, Clone, Default, Serialize, Deserialize)]
129pub struct SubscriptionFilter {
130 pub memory_ids: Option<Vec<MemoryId>>,
132 pub tags: Option<Vec<String>>,
134 pub event_types: Option<Vec<EventType>>,
136}
137
138impl SubscriptionFilter {
139 pub fn matches(&self, event: &RealtimeEvent) -> bool {
141 if let Some(ref types) = self.event_types {
143 if !types.contains(&event.event_type) {
144 return false;
145 }
146 }
147
148 if let Some(ref ids) = self.memory_ids {
150 if let Some(event_id) = event.memory_id {
151 if !ids.contains(&event_id) {
152 return false;
153 }
154 }
155 }
156
157 true
161 }
162}