nodedb_types/sync/wire/
presence.rs1use serde::{Deserialize, Serialize};
6
7#[derive(
16 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
17)]
18pub struct PresenceUpdateMsg {
19 pub channel: String,
21 pub state: Vec<u8>,
25}
26
27#[derive(
29 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
30)]
31pub struct PeerPresence {
32 pub user_id: String,
34 pub state: Vec<u8>,
36 pub last_seen_ms: u64,
38}
39
40#[derive(
45 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
46)]
47pub struct PresenceBroadcastMsg {
48 pub channel: String,
50 pub peers: Vec<PeerPresence>,
52}
53
54#[derive(
59 Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
60)]
61pub struct PresenceLeaveMsg {
62 pub channel: String,
64 pub user_id: String,
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::sync::wire::{SyncFrame, SyncMessageType};
72
73 #[test]
74 fn presence_update_roundtrip() {
75 let msg = PresenceUpdateMsg {
76 channel: "doc:doc-123".into(),
77 state: b"user_id:user-42,cursor:blk-7:42".to_vec(),
78 };
79 let frame = SyncFrame::new_msgpack(SyncMessageType::PresenceUpdate, &msg).unwrap();
80 let bytes = frame.to_bytes();
81 assert_eq!(bytes[0], SyncFrame::FORMAT_VERSION);
82 assert_eq!(bytes[1], 0x80);
83 let decoded: PresenceUpdateMsg = SyncFrame::from_bytes(&bytes)
84 .unwrap()
85 .decode_body()
86 .unwrap();
87 assert_eq!(decoded.channel, "doc:doc-123");
88 assert!(!decoded.state.is_empty());
89 }
90
91 #[test]
92 fn presence_broadcast_roundtrip() {
93 let msg = PresenceBroadcastMsg {
94 channel: "doc:doc-123".into(),
95 peers: vec![
96 PeerPresence {
97 user_id: "user-42".into(),
98 state: vec![0xDE, 0xAD],
99 last_seen_ms: 150,
100 },
101 PeerPresence {
102 user_id: "user-99".into(),
103 state: vec![0xBE, 0xEF],
104 last_seen_ms: 2300,
105 },
106 ],
107 };
108 let frame = SyncFrame::new_msgpack(SyncMessageType::PresenceBroadcast, &msg).unwrap();
109 let decoded: PresenceBroadcastMsg = SyncFrame::from_bytes(&frame.to_bytes())
110 .unwrap()
111 .decode_body()
112 .unwrap();
113 assert_eq!(decoded.channel, "doc:doc-123");
114 assert_eq!(decoded.peers.len(), 2);
115 assert_eq!(decoded.peers[0].user_id, "user-42");
116 assert_eq!(decoded.peers[1].last_seen_ms, 2300);
117 }
118
119 #[test]
120 fn presence_leave_roundtrip() {
121 let msg = PresenceLeaveMsg {
122 channel: "doc:doc-123".into(),
123 user_id: "user-42".into(),
124 };
125 let frame = SyncFrame::new_msgpack(SyncMessageType::PresenceLeave, &msg).unwrap();
126 let bytes = frame.to_bytes();
127 assert_eq!(bytes[0], SyncFrame::FORMAT_VERSION);
128 assert_eq!(bytes[1], 0x82);
129 let decoded: PresenceLeaveMsg = SyncFrame::from_bytes(&bytes)
130 .unwrap()
131 .decode_body()
132 .unwrap();
133 assert_eq!(decoded.channel, "doc:doc-123");
134 assert_eq!(decoded.user_id, "user-42");
135 }
136}