use authifier::AuthifierEvent; use serde::{Deserialize, Serialize}; use revolt_models::v0::{ AppendMessage, Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, Report, Server, User, UserSettings, Webhook, }; use revolt_result::Error; use crate::Database; /// WebSocket Client Errors #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "error")] pub enum WebSocketError { LabelMe, InternalError { at: String }, InvalidSession, OnboardingNotFinished, AlreadyAuthenticated, MalformedData { msg: String }, } /// Ping Packet #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum Ping { Binary(Vec), Number(usize), } /// Untagged Error #[derive(Serialize)] #[serde(untagged)] pub enum ErrorEvent { Error(WebSocketError), APIError(Error), } /// Protocol Events #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type")] pub enum EventV1 { /// Multiple events Bulk { v: Vec }, /// Successfully authenticated Authenticated, /// Logged out Logout, /// Basic data to cache Ready { users: Vec, servers: Vec, channels: Vec, members: Vec, emojis: Vec, }, /// Ping response Pong { data: Ping }, /// New message Message(Message), /// Update existing message MessageUpdate { id: String, channel: String, data: PartialMessage, }, /// Append information to existing message MessageAppend { id: String, channel: String, append: AppendMessage, }, /// Delete message MessageDelete { id: String, channel: String }, /// New reaction to a message MessageReact { id: String, channel_id: String, user_id: String, emoji_id: String, }, /// Remove user's reaction from message MessageUnreact { id: String, channel_id: String, user_id: String, emoji_id: String, }, /// Remove a reaction from message MessageRemoveReaction { id: String, channel_id: String, emoji_id: String, }, /// Bulk delete messages BulkMessageDelete { channel: String, ids: Vec }, /// New server ServerCreate { id: String, server: Server, channels: Vec, emojis: Vec, }, /// Update existing server ServerUpdate { id: String, data: PartialServer, clear: Vec, }, /// Delete server ServerDelete { id: String }, /// Update existing server member ServerMemberUpdate { id: MemberCompositeKey, data: PartialMember, clear: Vec, }, /// User joins server ServerMemberJoin { id: String, user: String }, /// User left server ServerMemberLeave { id: String, user: String }, /// Server role created or updated ServerRoleUpdate { id: String, role_id: String, data: PartialRole, clear: Vec, }, /// Server role deleted ServerRoleDelete { id: String, role_id: String }, /// Update existing user UserUpdate { id: String, data: PartialUser, clear: Vec, event_id: Option, }, /// Relationship with another user changed UserRelationship { id: String, user: User }, /// Settings updated remotely UserSettingsUpdate { id: String, update: UserSettings }, /// User has been platform banned or deleted their account /// /// Clients should remove the following associated data: /// - Messages /// - DM Channels /// - Relationships /// - Server Memberships /// /// User flags are specified to explain why a wipe is occurring though not all reasons will necessarily ever appear. UserPlatformWipe { user_id: String, flags: i32 }, /// New emoji EmojiCreate(Emoji), /// Delete emoji EmojiDelete { id: String }, /// New report ReportCreate(Report), /// New channel ChannelCreate(Channel), /// Update existing channel ChannelUpdate { id: String, data: PartialChannel, clear: Vec, }, /// Delete channel ChannelDelete { id: String }, /// User joins a group ChannelGroupJoin { id: String, user: String }, /// User leaves a group ChannelGroupLeave { id: String, user: String }, /// User started typing in a channel ChannelStartTyping { id: String, user: String }, /// User stopped typing in a channel ChannelStopTyping { id: String, user: String }, /// User acknowledged message in channel ChannelAck { id: String, user: String, message_id: String, }, /// New webhook WebhookCreate(Webhook), /// Update existing webhook WebhookUpdate { id: String, data: PartialWebhook, remove: Vec, }, /// Delete webhook WebhookDelete { id: String }, /// Auth events Auth(AuthifierEvent), } impl EventV1 { /// Publish helper wrapper pub async fn p(self, channel: String) { #[cfg(not(debug_assertions))] redis_kiss::p(channel, self).await; #[cfg(debug_assertions)] info!("Publishing event to {channel}: {self:?}"); #[cfg(debug_assertions)] redis_kiss::publish(channel, self).await.unwrap(); } /// Publish user event pub async fn p_user(self, id: String, db: &Database) { self.clone().p(id.clone()).await; // TODO: this should be captured by member list in the future and not immediately fanned out to users if let Ok(members) = db.fetch_all_memberships(&id).await { for member in members { self.clone().p(member.id.server).await; } } } /// Publish private event pub async fn private(self, id: String) { self.p(format!("{id}!")).await; } /// Publish internal global event pub async fn global(self) { self.p("global".to_string()).await; } }