realtime_rs/message/
payload.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use super::presence::{PresenceEvent, RawPresenceDiff, RawPresenceState};
7
8/// Message payload, enum allows each payload type to be contained in
9/// [crate::message::realtime_message::RealtimeMessage] without
10/// needing a seperate struct per message type.
11#[derive(Serialize, Deserialize, Debug, Clone)]
12#[serde(untagged)]
13pub enum Payload {
14    Join(JoinPayload),
15    Response(JoinResponsePayload),
16    System(SystemPayload),
17    AccessToken(AccessTokenPayload),
18    PostgresChanges(PostgresChangesPayload),
19    Broadcast(BroadcastPayload),
20    PresenceState(RawPresenceState),
21    PresenceDiff(RawPresenceDiff),
22    Reply(ReplyPayload),                 // think is only used for heartbeat?
23    PresenceTrack(PresenceTrackPayload), // TODO matches greedily
24    Empty {}, // TODO implement custom deser cos this bad. typechecking: this matches
25              // everything that can't deser elsewhere. not good.
26}
27
28impl Default for Payload {
29    fn default() -> Self {
30        Payload::Broadcast(BroadcastPayload::default())
31    }
32}
33
34#[derive(Serialize, Deserialize, Debug, Clone)]
35pub struct ReplyPayload {
36    pub response: Value,
37    pub status: String,
38}
39
40/// Data to track with presence
41///
42/// Use [crate::sync::realtime_channel::RealtimeChannel::track()]
43#[derive(Serialize, Deserialize, Debug, Clone)]
44pub struct PresenceTrackPayload {
45    pub event: PresenceEvent, // TODO custom serialize to remove required event here
46    pub payload: HashMap<String, Value>,
47}
48
49impl Default for PresenceTrackPayload {
50    fn default() -> Self {
51        Self {
52            event: PresenceEvent::Track,
53            payload: HashMap::new(),
54        }
55    }
56}
57
58impl From<HashMap<String, Value>> for PresenceTrackPayload {
59    fn from(value: HashMap<String, Value>) -> Self {
60        PresenceTrackPayload {
61            payload: value,
62            ..Default::default()
63        }
64    }
65}
66
67/// Payload for broadcast messages
68#[derive(Serialize, Deserialize, Debug, Clone)]
69pub struct BroadcastPayload {
70    pub event: String,
71    pub payload: HashMap<String, Value>,
72    #[serde(rename = "type")]
73    pub broadcast_type: String, // TODO this is always 'broadcast', impl custom serde ;_;
74}
75
76// TODO impl From<HashMap<String, Value>>
77
78impl BroadcastPayload {
79    pub fn new(event: impl Into<String>, payload: HashMap<String, Value>) -> Self {
80        BroadcastPayload {
81            event: event.into(),
82            payload,
83            broadcast_type: "broadcast".into(),
84        }
85    }
86}
87
88impl Default for BroadcastPayload {
89    fn default() -> Self {
90        BroadcastPayload {
91            event: "event_missing".into(),
92            payload: HashMap::new(),
93            broadcast_type: "broadcast".into(),
94        }
95    }
96}
97
98/// Payload wrapper for postgres changes
99#[derive(Serialize, Deserialize, Debug, Clone)]
100pub struct PostgresChangesPayload {
101    pub data: PostgresChangeData,
102    pub ids: Vec<usize>,
103}
104
105/// Recieved data regarding a postgres change
106#[derive(Serialize, Deserialize, Debug, Clone)]
107pub struct PostgresChangeData {
108    pub columns: Vec<PostgresColumn>,
109    pub commit_timestamp: String,
110    pub errors: Option<String>,
111    pub old_record: Option<PostgresOldDataRef>,
112    pub record: Option<HashMap<String, Value>>,
113    #[serde(rename = "type")]
114    pub change_type: PostgresChangesEvent,
115    pub schema: String,
116    pub table: String,
117}
118
119#[derive(Serialize, Deserialize, Debug, Clone)]
120pub struct PostgresColumn {
121    pub name: String,
122    #[serde(rename = "type")]
123    pub column_type: String,
124}
125
126#[derive(Serialize, Deserialize, Debug, Clone)]
127pub struct PostgresOldDataRef {
128    pub id: isize,
129}
130
131#[derive(Serialize, Deserialize, Debug, Clone)]
132pub struct AccessTokenPayload {
133    pub access_token: String,
134}
135
136/// Subscription result payload
137#[derive(Serialize, Deserialize, Debug, Clone)]
138pub struct SystemPayload {
139    pub channel: String,
140    pub extension: String,
141    pub message: String,
142    pub status: PayloadStatus,
143}
144
145/// Subscription configuration payload wrapper
146#[derive(Serialize, Deserialize, Debug, Clone, Default)]
147pub struct JoinPayload {
148    pub config: JoinConfig,
149    pub access_token: String,
150}
151
152/// Subscription configuration data
153#[derive(Serialize, Deserialize, Debug, Clone, Default)]
154pub struct JoinConfig {
155    pub broadcast: BroadcastConfig,
156    pub presence: PresenceConfig,
157    pub postgres_changes: Vec<PostgresChange>,
158}
159
160/// Channel broadcast options
161#[derive(Serialize, Deserialize, Debug, Clone, Default)]
162pub struct BroadcastConfig {
163    #[serde(rename = "self")]
164    pub broadcast_self: bool,
165    pub ack: bool,
166}
167
168/// Channel presence options
169#[derive(Serialize, Deserialize, Debug, Clone, Default)]
170pub struct PresenceConfig {
171    pub key: Option<String>,
172}
173
174#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Default, Clone, Hash)]
175pub enum PostgresChangesEvent {
176    #[serde(rename = "*")]
177    #[default]
178    All,
179    #[serde(rename = "INSERT")]
180    Insert,
181    #[serde(rename = "UPDATE")]
182    Update,
183    #[serde(rename = "DELETE")]
184    Delete,
185}
186
187#[derive(Serialize, Deserialize, Debug, Default, Clone)]
188pub struct PostgresChange {
189    pub event: PostgresChangesEvent,
190    pub schema: String,
191    pub table: String,
192    #[serde(skip_serializing_if = "Option::is_none")]
193    pub filter: Option<String>, // TODO structured filters
194}
195
196#[derive(Serialize, Deserialize, Debug, Clone)]
197pub struct JoinResponsePayload {
198    pub response: PostgresChangesList,
199    pub status: PayloadStatus,
200}
201
202#[derive(Serialize, Deserialize, Debug, Clone)]
203pub struct PostgresChangesList {
204    pub postgres_changes: Vec<PostgresChange>,
205}
206
207#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
208pub enum PayloadStatus {
209    #[serde(rename = "ok")]
210    Ok,
211    #[serde(rename = "error")]
212    Error,
213}