hyperstack_server/websocket/
frame.rs

1use serde::{Deserialize, Serialize};
2
3/// Streaming mode for different data access patterns
4#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
5#[serde(rename_all = "lowercase")]
6pub enum Mode {
7    /// Latest value only (watch semantics)
8    State,
9    /// Append-only stream
10    Append,
11    /// Collection/list view (also used for key-value lookups)
12    List,
13}
14
15/// Data frame sent over WebSocket
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Frame {
18    pub mode: Mode,
19    #[serde(rename = "entity")]
20    pub export: String,
21    pub op: &'static str,
22    pub key: String,
23    pub data: serde_json::Value,
24    #[serde(skip_serializing_if = "Vec::is_empty", default)]
25    pub append: Vec<String>,
26}
27
28/// A single entity within a snapshot
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct SnapshotEntity {
31    pub key: String,
32    pub data: serde_json::Value,
33}
34
35/// Batch snapshot frame for initial data load
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct SnapshotFrame {
38    pub mode: Mode,
39    #[serde(rename = "entity")]
40    pub export: String,
41    pub op: &'static str,
42    pub data: Vec<SnapshotEntity>,
43}
44
45impl Frame {
46    pub fn entity(&self) -> &str {
47        &self.export
48    }
49
50    pub fn key(&self) -> &str {
51        &self.key
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn test_frame_entity_key_accessors() {
61        let frame = Frame {
62            mode: Mode::List,
63            export: "SettlementGame/list".to_string(),
64            op: "upsert",
65            key: "123".to_string(),
66            data: serde_json::json!({}),
67            append: vec![],
68        };
69
70        assert_eq!(frame.entity(), "SettlementGame/list");
71        assert_eq!(frame.key(), "123");
72    }
73
74    #[test]
75    fn test_frame_serialization() {
76        let frame = Frame {
77            mode: Mode::List,
78            export: "SettlementGame/list".to_string(),
79            op: "upsert",
80            key: "123".to_string(),
81            data: serde_json::json!({"gameId": "123"}),
82            append: vec![],
83        };
84
85        let json = serde_json::to_value(&frame).unwrap();
86        assert_eq!(json["op"], "upsert");
87        assert_eq!(json["mode"], "list");
88        assert_eq!(json["entity"], "SettlementGame/list");
89        assert_eq!(json["key"], "123");
90    }
91}