use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::types::MemoryId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EventType {
MemoryCreated,
MemoryUpdated,
MemoryDeleted,
CrossrefCreated,
CrossrefDeleted,
SyncStarted,
SyncCompleted,
SyncFailed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RealtimeEvent {
#[serde(skip_serializing_if = "Option::is_none")]
pub seq_id: Option<u64>,
#[serde(rename = "type")]
pub event_type: EventType,
pub timestamp: DateTime<Utc>,
pub memory_id: Option<MemoryId>,
pub preview: Option<String>,
pub changes: Option<Vec<String>>,
pub data: Option<serde_json::Value>,
}
impl RealtimeEvent {
pub fn memory_created(id: MemoryId, preview: String) -> Self {
Self {
seq_id: None,
event_type: EventType::MemoryCreated,
timestamp: Utc::now(),
memory_id: Some(id),
preview: Some(truncate(&preview, 100)),
changes: None,
data: None,
}
}
pub fn memory_updated(id: MemoryId, changes: Vec<String>) -> Self {
Self {
seq_id: None,
event_type: EventType::MemoryUpdated,
timestamp: Utc::now(),
memory_id: Some(id),
preview: None,
changes: Some(changes),
data: None,
}
}
pub fn memory_deleted(id: MemoryId) -> Self {
Self {
seq_id: None,
event_type: EventType::MemoryDeleted,
timestamp: Utc::now(),
memory_id: Some(id),
preview: None,
changes: None,
data: None,
}
}
pub fn sync_completed(direction: &str, changes: i64) -> Self {
Self {
seq_id: None,
event_type: EventType::SyncCompleted,
timestamp: Utc::now(),
memory_id: None,
preview: None,
changes: None,
data: Some(serde_json::json!({
"direction": direction,
"changes": changes,
})),
}
}
pub fn sync_failed(error: &str) -> Self {
Self {
seq_id: None,
event_type: EventType::SyncFailed,
timestamp: Utc::now(),
memory_id: None,
preview: None,
changes: None,
data: Some(serde_json::json!({
"error": error,
})),
}
}
}
fn truncate(s: &str, max: usize) -> String {
if s.chars().count() <= max {
s.to_string()
} else {
let truncated: String = s.chars().take(max.saturating_sub(3)).collect();
format!("{}...", truncated)
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SubscriptionFilter {
pub memory_ids: Option<Vec<MemoryId>>,
pub tags: Option<Vec<String>>,
pub event_types: Option<Vec<EventType>>,
}
impl SubscriptionFilter {
pub fn matches(&self, event: &RealtimeEvent) -> bool {
if let Some(ref types) = self.event_types {
if !types.contains(&event.event_type) {
return false;
}
}
if let Some(ref ids) = self.memory_ids {
if let Some(event_id) = event.memory_id {
if !ids.contains(&event_id) {
return false;
}
}
}
true
}
}