Skip to main content

revolt_database/events/
client.rs

1use revolt_result::Error;
2use serde::{Deserialize, Serialize};
3
4use revolt_models::v0::{
5    AppendMessage, Channel, ChannelSlowmode, ChannelUnread, ChannelVoiceState, Emoji,
6    FieldsChannel, FieldsMember, FieldsMessage, FieldsRole, FieldsServer, FieldsUser,
7    FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialEmoji,
8    PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser, PartialUserVoiceState,
9    PartialWebhook, PolicyChange, RemovalIntention, Report, Server, User, UserSettings,
10    UserVoiceState, Webhook,
11};
12
13use crate::{Account, Database, Session};
14
15/// Ping Packet
16#[derive(Serialize, Deserialize, Debug, Clone)]
17#[serde(untagged)]
18pub enum Ping {
19    Binary(Vec<u8>),
20    Number(usize),
21}
22
23/// Fields provided in Ready payload
24#[derive(PartialEq, Debug, Clone, Deserialize)]
25pub struct ReadyPayloadFields {
26    pub users: bool,
27    pub servers: bool,
28    pub channels: bool,
29    pub members: bool,
30    pub emojis: bool,
31    pub voice_states: bool,
32    pub user_settings: Vec<String>,
33    pub channel_unreads: bool,
34    pub policy_changes: bool,
35}
36
37impl Default for ReadyPayloadFields {
38    fn default() -> Self {
39        Self {
40            users: true,
41            servers: true,
42            channels: true,
43            members: true,
44            emojis: true,
45            voice_states: true,
46            user_settings: Vec::new(),
47            channel_unreads: false,
48            policy_changes: true,
49        }
50    }
51}
52
53/// Protocol Events
54#[derive(Serialize, Deserialize, Debug, Clone)]
55#[serde(tag = "type")]
56pub enum EventV1 {
57    /// Multiple events
58    Bulk {
59        v: Vec<EventV1>,
60    },
61    /// Error event
62    Error {
63        data: Error,
64    },
65
66    /// Successfully authenticated
67    Authenticated,
68    /// Logged out
69    Logout,
70    /// Basic data to cache
71    Ready {
72        #[serde(skip_serializing_if = "Option::is_none")]
73        users: Option<Vec<User>>,
74        #[serde(skip_serializing_if = "Option::is_none")]
75        servers: Option<Vec<Server>>,
76        #[serde(skip_serializing_if = "Option::is_none")]
77        channels: Option<Vec<Channel>>,
78        #[serde(skip_serializing_if = "Option::is_none")]
79        members: Option<Vec<Member>>,
80        #[serde(skip_serializing_if = "Option::is_none")]
81        emojis: Option<Vec<Emoji>>,
82        #[serde(skip_serializing_if = "Option::is_none")]
83        voice_states: Option<Vec<ChannelVoiceState>>,
84
85        #[serde(skip_serializing_if = "Option::is_none")]
86        user_settings: Option<UserSettings>,
87        #[serde(skip_serializing_if = "Option::is_none")]
88        channel_unreads: Option<Vec<ChannelUnread>>,
89
90        #[serde(skip_serializing_if = "Option::is_none")]
91        policy_changes: Option<Vec<PolicyChange>>,
92    },
93
94    /// Ping response
95    Pong {
96        data: Ping,
97    },
98    /// New message
99    Message(Message),
100
101    /// Update existing message
102    MessageUpdate {
103        id: String,
104        channel: String,
105        data: PartialMessage,
106        #[serde(default)]
107        clear: Vec<FieldsMessage>,
108    },
109
110    /// Append information to existing message
111    MessageAppend {
112        id: String,
113        channel: String,
114        append: AppendMessage,
115    },
116
117    /// Delete message
118    MessageDelete {
119        id: String,
120        channel: String,
121    },
122
123    /// New reaction to a message
124    MessageReact {
125        id: String,
126        channel_id: String,
127        user_id: String,
128        emoji_id: String,
129    },
130
131    /// Remove user's reaction from message
132    MessageUnreact {
133        id: String,
134        channel_id: String,
135        user_id: String,
136        emoji_id: String,
137    },
138
139    /// Remove a reaction from message
140    MessageRemoveReaction {
141        id: String,
142        channel_id: String,
143        emoji_id: String,
144    },
145
146    /// Bulk delete messages
147    BulkMessageDelete {
148        channel: String,
149        ids: Vec<String>,
150    },
151
152    /// New server
153    ServerCreate {
154        id: String,
155        server: Server,
156        channels: Vec<Channel>,
157        emojis: Vec<Emoji>,
158        voice_states: Vec<ChannelVoiceState>,
159    },
160
161    /// Update existing server
162    ServerUpdate {
163        id: String,
164        data: PartialServer,
165        #[serde(default)]
166        clear: Vec<FieldsServer>,
167    },
168
169    /// Delete server
170    ServerDelete {
171        id: String,
172    },
173
174    /// Update existing server member
175    ServerMemberUpdate {
176        id: MemberCompositeKey,
177        data: PartialMember,
178        #[serde(default)]
179        clear: Vec<FieldsMember>,
180    },
181
182    /// User joins server
183    ServerMemberJoin {
184        id: String,
185        // Deprecated: use member.id.user
186        #[deprecated = "Use member.id.user instead"]
187        user: String,
188        member: Member,
189    },
190
191    /// User left server
192    ServerMemberLeave {
193        id: String,
194        user: String,
195        reason: RemovalIntention,
196    },
197
198    /// Server role created or updated
199    ServerRoleUpdate {
200        id: String,
201        role_id: String,
202        data: PartialRole,
203        #[serde(default)]
204        clear: Vec<FieldsRole>,
205    },
206
207    /// Server role deleted
208    ServerRoleDelete {
209        id: String,
210        role_id: String,
211    },
212
213    /// Server roles ranks updated
214    ServerRoleRanksUpdate {
215        id: String,
216        ranks: Vec<String>,
217    },
218
219    /// Update existing user
220    UserUpdate {
221        id: String,
222        data: PartialUser,
223        #[serde(default)]
224        clear: Vec<FieldsUser>,
225        event_id: Option<String>,
226    },
227
228    /// Relationship with another user changed
229    UserRelationship {
230        id: String,
231        user: User,
232    },
233    /// Settings updated remotely
234    UserSettingsUpdate {
235        id: String,
236        update: UserSettings,
237    },
238
239    /// User has been platform banned or deleted their account
240    ///
241    /// Clients should remove the following associated data:
242    /// - Messages
243    /// - DM Channels
244    /// - Relationships
245    /// - Server Memberships
246    ///
247    /// User flags are specified to explain why a wipe is occurring though not all reasons will necessarily ever appear.
248    UserPlatformWipe {
249        user_id: String,
250        flags: i32,
251    },
252    /// New emoji
253    EmojiCreate(Emoji),
254
255    /// Update existing emoji
256    EmojiUpdate {
257        id: String,
258        data: PartialEmoji,
259    },
260
261    /// Delete emoji
262    EmojiDelete {
263        id: String,
264    },
265
266    /// New report
267    ReportCreate(Report),
268    /// New channel
269    ChannelCreate(Channel),
270
271    /// Update existing channel
272    ChannelUpdate {
273        id: String,
274        data: PartialChannel,
275        #[serde(default)]
276        clear: Vec<FieldsChannel>,
277    },
278
279    /// Delete channel
280    ChannelDelete {
281        id: String,
282    },
283
284    /// User joins a group
285    ChannelGroupJoin {
286        id: String,
287        user: String,
288    },
289
290    /// User leaves a group
291    ChannelGroupLeave {
292        id: String,
293        user: String,
294    },
295
296    /// User started typing in a channel
297    ChannelStartTyping {
298        id: String,
299        user: String,
300    },
301
302    /// User stopped typing in a channel
303    ChannelStopTyping {
304        id: String,
305        user: String,
306    },
307
308    /// User acknowledged message in channel
309    ChannelAck {
310        id: String,
311        user: String,
312        message_id: String,
313    },
314
315    /// New webhook
316    WebhookCreate(Webhook),
317
318    /// Update existing webhook
319    WebhookUpdate {
320        id: String,
321        data: PartialWebhook,
322        remove: Vec<FieldsWebhook>,
323    },
324
325    /// Delete webhook
326    WebhookDelete {
327        id: String,
328    },
329
330    /// Auth events
331    CreateAccount {
332        account: Account,
333    },
334    CreateSession {
335        session: Session,
336    },
337    DeleteSession {
338        user_id: String,
339        session_id: String,
340    },
341    DeleteAllSessions {
342        user_id: String,
343        exclude_session_id: Option<String>,
344    },
345
346    /// Voice events
347    VoiceChannelJoin {
348        id: String,
349        state: UserVoiceState,
350    },
351    VoiceChannelLeave {
352        id: String,
353        user: String,
354    },
355    VoiceChannelMove {
356        user: String,
357        from: String,
358        to: String,
359        state: UserVoiceState,
360    },
361    UserVoiceStateUpdate {
362        id: String,
363        channel_id: String,
364        data: PartialUserVoiceState,
365    },
366    UserMoveVoiceChannel {
367        node: String,
368        from: String,
369        to: String,
370        token: String,
371    },
372    /// User's active slowmodes
373    UserSlowmodes {
374        slowmodes: Vec<ChannelSlowmode>,
375    },
376}
377
378impl EventV1 {
379    /// Publish helper wrapper
380    pub async fn p(self, channel: String) {
381        #[cfg(not(debug_assertions))]
382        redis_kiss::p(channel, self).await;
383
384        #[cfg(debug_assertions)]
385        info!("Publishing event to {channel}: {self:?}");
386
387        #[cfg(debug_assertions)]
388        redis_kiss::publish(channel, self).await.unwrap();
389    }
390
391    /// Publish user event
392    pub async fn p_user(self, id: String, db: &Database) {
393        self.clone().p(id.clone()).await;
394
395        // TODO: this should be captured by member list in the future and not immediately fanned out to users
396        if let Ok(members) = db.fetch_all_memberships(&id).await {
397            for member in members {
398                self.clone().server(member.id.server).await;
399            }
400        }
401    }
402
403    /// Publish private event
404    pub async fn private(self, id: String) {
405        self.p(format!("{id}!")).await;
406    }
407
408    /// Publish server member event
409    pub async fn server(self, id: String) {
410        self.p(format!("{id}u")).await;
411    }
412
413    /// Publish internal global event
414    pub async fn global(self) {
415        self.p("global".to_string()).await;
416    }
417}