Enhancement/updatemessage (#190)

Implements UpdateMessage for some more Gateway Events.
This commit is contained in:
Flori 2023-08-20 16:10:28 +02:00 committed by GitHub
commit 19159b0196
10 changed files with 139 additions and 60 deletions

View File

@ -1,8 +1,9 @@
use crate::errors::GatewayError; use crate::errors::GatewayError;
use crate::gateway::events::Events; use crate::gateway::events::Events;
use crate::types::{ use crate::types::{
self, Channel, ChannelUpdate, Composite, Guild, GuildRoleCreate, GuildRoleUpdate, JsonField, self, AutoModerationRule, AutoModerationRuleUpdate, Channel, ChannelCreate, ChannelDelete,
RoleObject, Snowflake, UpdateMessage, WebSocketEvent, ChannelUpdate, Composite, Guild, GuildRoleCreate, GuildRoleUpdate, JsonField, RoleObject,
Snowflake, ThreadUpdate, UpdateMessage, WebSocketEvent,
}; };
use async_trait::async_trait; use async_trait::async_trait;
use std::any::Any; use std::any::Any;
@ -512,7 +513,13 @@ impl Gateway {
$( $(
let mut message: $message_type = message; let mut message: $message_type = message;
let store = self.store.lock().await; let store = self.store.lock().await;
if let Some(to_update) = store.get(&message.id()) { let id = if message.id().is_some() {
message.id().unwrap()
} else {
event.notify(message).await;
return;
};
if let Some(to_update) = store.get(&id) {
let object = to_update.clone(); let object = to_update.clone();
let inner_object = object.read().unwrap(); let inner_object = object.read().unwrap();
if let Some(_) = inner_object.downcast_ref::<$update_type>() { if let Some(_) = inner_object.downcast_ref::<$update_type>() {
@ -526,7 +533,7 @@ impl Gateway {
message.set_json(json.to_string()); message.set_json(json.to_string());
message.update(downcasted.clone()); message.update(downcasted.clone());
} else { } else {
warn!("Received {} for {}, but it has been observed to be a different type!", $name, message.id()) warn!("Received {} for {}, but it has been observed to be a different type!", $name, id)
} }
} }
)? )?
@ -568,70 +575,70 @@ impl Gateway {
"READY_SUPPLEMENTAL" => session.ready_supplemental, "READY_SUPPLEMENTAL" => session.ready_supplemental,
"APPLICATION_COMMAND_PERMISSIONS_UPDATE" => application.command_permissions_update, "APPLICATION_COMMAND_PERMISSIONS_UPDATE" => application.command_permissions_update,
"AUTO_MODERATION_RULE_CREATE" =>auto_moderation.rule_create, "AUTO_MODERATION_RULE_CREATE" =>auto_moderation.rule_create,
"AUTO_MODERATION_RULE_UPDATE" =>auto_moderation.rule_update, "AUTO_MODERATION_RULE_UPDATE" =>auto_moderation.rule_update AutoModerationRuleUpdate: AutoModerationRule,
"AUTO_MODERATION_RULE_DELETE" => auto_moderation.rule_delete, "AUTO_MODERATION_RULE_DELETE" => auto_moderation.rule_delete,
"AUTO_MODERATION_ACTION_EXECUTION" => auto_moderation.action_execution, "AUTO_MODERATION_ACTION_EXECUTION" => auto_moderation.action_execution,
"CHANNEL_CREATE" => channel.create, "CHANNEL_CREATE" => channel.create ChannelCreate: Guild,
"CHANNEL_UPDATE" => channel.update ChannelUpdate: Channel, "CHANNEL_UPDATE" => channel.update ChannelUpdate: Channel,
"CHANNEL_UNREAD_UPDATE" => channel.unread_update, "CHANNEL_UNREAD_UPDATE" => channel.unread_update,
"CHANNEL_DELETE" => channel.delete, "CHANNEL_DELETE" => channel.delete ChannelDelete: Guild,
"CHANNEL_PINS_UPDATE" => channel.pins_update, "CHANNEL_PINS_UPDATE" => channel.pins_update,
"CALL_CREATE" => call.create, "CALL_CREATE" => call.create,
"CALL_UPDATE" => call.update, "CALL_UPDATE" => call.update,
"CALL_DELETE" => call.delete, "CALL_DELETE" => call.delete,
"THREAD_CREATE" => thread.create, "THREAD_CREATE" => thread.create, // TODO
"THREAD_UPDATE" => thread.update, "THREAD_UPDATE" => thread.update ThreadUpdate: Channel,
"THREAD_DELETE" => thread.delete, "THREAD_DELETE" => thread.delete, // TODO
"THREAD_LIST_SYNC" => thread.list_sync, "THREAD_LIST_SYNC" => thread.list_sync, // TODO
"THREAD_MEMBER_UPDATE" => thread.member_update, "THREAD_MEMBER_UPDATE" => thread.member_update, // TODO
"THREAD_MEMBERS_UPDATE" => thread.members_update, "THREAD_MEMBERS_UPDATE" => thread.members_update, // TODO
"GUILD_CREATE" => guild.create, "GUILD_CREATE" => guild.create, // TODO
"GUILD_UPDATE" => guild.update, "GUILD_UPDATE" => guild.update, // TODO
"GUILD_DELETE" => guild.delete, "GUILD_DELETE" => guild.delete, // TODO
"GUILD_AUDIT_LOG_ENTRY_CREATE" => guild.audit_log_entry_create, "GUILD_AUDIT_LOG_ENTRY_CREATE" => guild.audit_log_entry_create,
"GUILD_BAN_ADD" => guild.ban_add, "GUILD_BAN_ADD" => guild.ban_add, // TODO
"GUILD_BAN_REMOVE" => guild.ban_remove, "GUILD_BAN_REMOVE" => guild.ban_remove, // TODO
"GUILD_EMOJIS_UPDATE" => guild.emojis_update, "GUILD_EMOJIS_UPDATE" => guild.emojis_update, // TODO
"GUILD_STICKERS_UPDATE" => guild.stickers_update, "GUILD_STICKERS_UPDATE" => guild.stickers_update, // TODO
"GUILD_INTEGRATIONS_UPDATE" => guild.integrations_update, "GUILD_INTEGRATIONS_UPDATE" => guild.integrations_update,
"GUILD_MEMBER_ADD" => guild.member_add, "GUILD_MEMBER_ADD" => guild.member_add,
"GUILD_MEMBER_REMOVE" => guild.member_remove, "GUILD_MEMBER_REMOVE" => guild.member_remove,
"GUILD_MEMBER_UPDATE" => guild.member_update, "GUILD_MEMBER_UPDATE" => guild.member_update, // TODO
"GUILD_MEMBERS_CHUNK" => guild.members_chunk, "GUILD_MEMBERS_CHUNK" => guild.members_chunk, // TODO
"GUILD_ROLE_CREATE" => guild.role_create GuildRoleCreate: Guild, "GUILD_ROLE_CREATE" => guild.role_create GuildRoleCreate: Guild,
"GUILD_ROLE_UPDATE" => guild.role_update GuildRoleUpdate: RoleObject, "GUILD_ROLE_UPDATE" => guild.role_update GuildRoleUpdate: RoleObject,
"GUILD_ROLE_DELETE" => guild.role_delete, "GUILD_ROLE_DELETE" => guild.role_delete, // TODO
"GUILD_SCHEDULED_EVENT_CREATE" => guild.role_scheduled_event_create, "GUILD_SCHEDULED_EVENT_CREATE" => guild.role_scheduled_event_create, // TODO
"GUILD_SCHEDULED_EVENT_UPDATE" => guild.role_scheduled_event_update, "GUILD_SCHEDULED_EVENT_UPDATE" => guild.role_scheduled_event_update, // TODO
"GUILD_SCHEDULED_EVENT_DELETE" => guild.role_scheduled_event_delete, "GUILD_SCHEDULED_EVENT_DELETE" => guild.role_scheduled_event_delete, // TODO
"GUILD_SCHEDULED_EVENT_USER_ADD" => guild.role_scheduled_event_user_add, "GUILD_SCHEDULED_EVENT_USER_ADD" => guild.role_scheduled_event_user_add,
"GUILD_SCHEDULED_EVENT_USER_REMOVE" => guild.role_scheduled_event_user_remove, "GUILD_SCHEDULED_EVENT_USER_REMOVE" => guild.role_scheduled_event_user_remove,
"PASSIVE_UPDATE_V1" => guild.passive_update_v1, "PASSIVE_UPDATE_V1" => guild.passive_update_v1, // TODO
"INTEGRATION_CREATE" => integration.create, "INTEGRATION_CREATE" => integration.create, // TODO
"INTEGRATION_UPDATE" => integration.update, "INTEGRATION_UPDATE" => integration.update, // TODO
"INTEGRATION_DELETE" => integration.delete, "INTEGRATION_DELETE" => integration.delete, // TODO
"INTERACTION_CREATE" => interaction.create, "INTERACTION_CREATE" => interaction.create, // TODO
"INVITE_CREATE" => invite.create, "INVITE_CREATE" => invite.create, // TODO
"INVITE_DELETE" => invite.delete, "INVITE_DELETE" => invite.delete, // TODO
"MESSAGE_CREATE" => message.create, "MESSAGE_CREATE" => message.create,
"MESSAGE_UPDATE" => message.update, "MESSAGE_UPDATE" => message.update, // TODO
"MESSAGE_DELETE" => message.delete, "MESSAGE_DELETE" => message.delete,
"MESSAGE_DELETE_BULK" => message.delete_bulk, "MESSAGE_DELETE_BULK" => message.delete_bulk,
"MESSAGE_REACTION_ADD" => message.reaction_add, "MESSAGE_REACTION_ADD" => message.reaction_add, // TODO
"MESSAGE_REACTION_REMOVE" => message.reaction_remove, "MESSAGE_REACTION_REMOVE" => message.reaction_remove, // TODO
"MESSAGE_REACTION_REMOVE_ALL" => message.reaction_remove_all, "MESSAGE_REACTION_REMOVE_ALL" => message.reaction_remove_all, // TODO
"MESSAGE_REACTION_REMOVE_EMOJI" => message.reaction_remove_emoji, "MESSAGE_REACTION_REMOVE_EMOJI" => message.reaction_remove_emoji, // TODO
"MESSAGE_ACK" => message.ack, "MESSAGE_ACK" => message.ack,
"PRESENCE_UPDATE" => user.presence_update, "PRESENCE_UPDATE" => user.presence_update, // TODO
"RELATIONSHIP_ADD" => relationship.add, "RELATIONSHIP_ADD" => relationship.add,
"RELATIONSHIP_REMOVE" => relationship.remove, "RELATIONSHIP_REMOVE" => relationship.remove,
"STAGE_INSTANCE_CREATE" => stage_instance.create, "STAGE_INSTANCE_CREATE" => stage_instance.create,
"STAGE_INSTANCE_UPDATE" => stage_instance.update, "STAGE_INSTANCE_UPDATE" => stage_instance.update, // TODO
"STAGE_INSTANCE_DELETE" => stage_instance.delete, "STAGE_INSTANCE_DELETE" => stage_instance.delete,
"TYPING_START" => user.typing_start, "TYPING_START" => user.typing_start,
"USER_UPDATE" => user.update, "USER_UPDATE" => user.update, // TODO
"USER_GUILD_SETTINGS_UPDATE" => user.guild_settings_update, "USER_GUILD_SETTINGS_UPDATE" => user.guild_settings_update,
"VOICE_STATE_UPDATE" => voice.state_update, "VOICE_STATE_UPDATE" => voice.state_update, // TODO
"VOICE_SERVER_UPDATE" => voice.server_update, "VOICE_SERVER_UPDATE" => voice.server_update,
"WEBHOOKS_UPDATE" => webhooks.update "WEBHOOKS_UPDATE" => webhooks.update
); );

View File

@ -1,11 +1,13 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use crate::gateway::Updateable;
use chorus_macros::Updateable;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone, Updateable)]
/// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object> /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object>
pub struct AutoModerationRule { pub struct AutoModerationRule {
pub id: Snowflake, pub id: Snowflake,

View File

@ -16,7 +16,7 @@ use crate::types::{
#[derive(Default, Debug, Serialize, Deserialize, Clone, Updateable, Composite)] #[derive(Default, Debug, Serialize, Deserialize, Clone, Updateable, Composite)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a guild of private channel /// Represents a guild or private channel
/// ///
/// # Reference /// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#channels-resource> /// See <https://discord-userdoccers.vercel.app/resources/channel#channels-resource>

View File

@ -21,7 +21,7 @@ pub struct Invite {
pub flags: Option<i32>, pub flags: Option<i32>,
pub guild: Option<InviteGuild>, pub guild: Option<InviteGuild>,
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
pub guild_scheduled_event: Option<GuildScheduledEvent>, pub guild_scheduled_event: Option<Arc<RwLock<GuildScheduledEvent>>>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub invite_type: Option<i32>, pub invite_type: Option<i32>,
pub inviter: Option<User>, pub inviter: Option<User>,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, RwLock};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{ use crate::types::{
@ -84,7 +86,7 @@ pub struct MessageInteraction {
pub interaction_type: u8, pub interaction_type: u8,
pub name: String, pub name: String,
pub user: User, pub user: User,
pub member: Option<GuildMember>, pub member: Option<Arc<RwLock<GuildMember>>>,
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]

View File

@ -1,3 +1,5 @@
use crate::types::JsonField;
use chorus_macros::JsonField;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{ use crate::types::{
@ -5,6 +7,8 @@ use crate::types::{
WebSocketEvent, WebSocketEvent,
}; };
use super::UpdateMessage;
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create> /// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create>
pub struct AutoModerationRuleCreate { pub struct AutoModerationRuleCreate {
@ -14,11 +18,19 @@ pub struct AutoModerationRuleCreate {
impl WebSocketEvent for AutoModerationRuleCreate {} impl WebSocketEvent for AutoModerationRuleCreate {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update> /// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update>
pub struct AutoModerationRuleUpdate { pub struct AutoModerationRuleUpdate {
#[serde(flatten)] #[serde(flatten)]
pub rule: AutoModerationRule, pub rule: AutoModerationRule,
#[serde(skip)]
pub json: String,
}
impl UpdateMessage<AutoModerationRule> for AutoModerationRuleUpdate {
fn id(&self) -> Option<Snowflake> {
Some(self.rule.id)
}
} }
impl WebSocketEvent for AutoModerationRuleUpdate {} impl WebSocketEvent for AutoModerationRuleUpdate {}

View File

@ -1,6 +1,7 @@
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use crate::types::events::WebSocketEvent; use crate::types::events::WebSocketEvent;
use crate::types::Guild;
use crate::types::{entities::Channel, JsonField, Snowflake}; use crate::types::{entities::Channel, JsonField, Snowflake};
use chorus_macros::JsonField; use chorus_macros::JsonField;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
@ -18,15 +19,33 @@ pub struct ChannelPinsUpdate {
impl WebSocketEvent for ChannelPinsUpdate {} impl WebSocketEvent for ChannelPinsUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-create> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-create>
pub struct ChannelCreate { pub struct ChannelCreate {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,
#[serde(skip)]
pub json: String,
} }
impl WebSocketEvent for ChannelCreate {} impl WebSocketEvent for ChannelCreate {}
impl UpdateMessage<Guild> for ChannelCreate {
fn id(&self) -> Option<Snowflake> {
self.channel.guild_id
}
fn update(&mut self, object_to_update: Arc<RwLock<Guild>>) {
let mut write = object_to_update.write().unwrap();
let update = Arc::new(RwLock::new(self.channel.clone()));
if write.channels.is_some() {
write.channels.as_mut().unwrap().push(update);
} else {
write.channels = Some(Vec::from([update]));
}
}
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-update> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-update>
pub struct ChannelUpdate { pub struct ChannelUpdate {
@ -43,8 +62,8 @@ impl UpdateMessage<Channel> for ChannelUpdate {
let mut write = object_to_update.write().unwrap(); let mut write = object_to_update.write().unwrap();
*write = self.channel.clone(); *write = self.channel.clone();
} }
fn id(&self) -> Snowflake { fn id(&self) -> Option<Snowflake> {
self.channel.id Some(self.channel.id)
} }
} }
@ -68,11 +87,39 @@ pub struct ChannelUnreadUpdateObject {
impl WebSocketEvent for ChannelUnreadUpdate {} impl WebSocketEvent for ChannelUnreadUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#channel-delete> /// See <https://discord.com/developers/docs/topics/gateway-events#channel-delete>
pub struct ChannelDelete { pub struct ChannelDelete {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,
#[serde(skip)]
pub json: String,
}
impl UpdateMessage<Guild> for ChannelDelete {
fn id(&self) -> Option<Snowflake> {
self.channel.guild_id
}
fn update(&mut self, object_to_update: Arc<RwLock<Guild>>) {
if self.id().is_none() {
return;
}
let mut write = object_to_update.write().unwrap();
if write.channels.is_none() {
return;
}
for (iteration, item) in (0_u32..).zip(write.channels.as_mut().unwrap().iter()) {
if item.read().unwrap().id == self.id().unwrap() {
write
.channels
.as_mut()
.unwrap()
.swap_remove(iteration as usize);
return;
}
}
}
} }
impl WebSocketEvent for ChannelDelete {} impl WebSocketEvent for ChannelDelete {}

View File

@ -180,8 +180,8 @@ pub struct GuildRoleCreate {
impl WebSocketEvent for GuildRoleCreate {} impl WebSocketEvent for GuildRoleCreate {}
impl UpdateMessage<Guild> for GuildRoleCreate { impl UpdateMessage<Guild> for GuildRoleCreate {
fn id(&self) -> Snowflake { fn id(&self) -> Option<Snowflake> {
self.guild_id Some(self.guild_id)
} }
fn update(&mut self, object_to_update: Arc<RwLock<Guild>>) { fn update(&mut self, object_to_update: Arc<RwLock<Guild>>) {
@ -210,15 +210,13 @@ pub struct GuildRoleUpdate {
impl WebSocketEvent for GuildRoleUpdate {} impl WebSocketEvent for GuildRoleUpdate {}
impl UpdateMessage<RoleObject> for GuildRoleUpdate { impl UpdateMessage<RoleObject> for GuildRoleUpdate {
fn id(&self) -> Snowflake { fn id(&self) -> Option<Snowflake> {
self.role.id Some(self.role.id)
} }
fn update(&mut self, object_to_update: Arc<RwLock<RoleObject>>) { fn update(&mut self, object_to_update: Arc<RwLock<RoleObject>>) {
println!("Processing Role Update. Name: {}", self.role.name);
let mut write = object_to_update.write().unwrap(); let mut write = object_to_update.write().unwrap();
*write = self.role.clone(); *write = self.role.clone();
println!("Updated role: Name: {}", write.name);
} }
} }

View File

@ -122,7 +122,7 @@ where
fn update(&mut self, object_to_update: Arc<RwLock<T>>) { fn update(&mut self, object_to_update: Arc<RwLock<T>>) {
update_object(self.get_json(), object_to_update) update_object(self.get_json(), object_to_update)
} }
fn id(&self) -> Snowflake; fn id(&self) -> Option<Snowflake>;
} }
pub(crate) trait JsonField: Clone { pub(crate) trait JsonField: Clone {

View File

@ -1,8 +1,11 @@
use chorus_macros::JsonField;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::entities::{Channel, ThreadMember}; use crate::types::entities::{Channel, ThreadMember};
use crate::types::events::WebSocketEvent; use crate::types::events::WebSocketEvent;
use crate::types::Snowflake; use crate::types::{JsonField, Snowflake};
use super::UpdateMessage;
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See <https://discord.com/developers/docs/topics/gateway-events#thread-create> /// See <https://discord.com/developers/docs/topics/gateway-events#thread-create>
@ -13,15 +16,23 @@ pub struct ThreadCreate {
impl WebSocketEvent for ThreadCreate {} impl WebSocketEvent for ThreadCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone, JsonField)]
/// See <https://discord.com/developers/docs/topics/gateway-events#thread-update> /// See <https://discord.com/developers/docs/topics/gateway-events#thread-update>
pub struct ThreadUpdate { pub struct ThreadUpdate {
#[serde(flatten)] #[serde(flatten)]
pub thread: Channel, pub thread: Channel,
#[serde(skip)]
pub json: String,
} }
impl WebSocketEvent for ThreadUpdate {} impl WebSocketEvent for ThreadUpdate {}
impl UpdateMessage<Channel> for ThreadUpdate {
fn id(&self) -> Option<Snowflake> {
Some(self.thread.id)
}
}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See <https://discord.com/developers/docs/topics/gateway-events#thread-delete> /// See <https://discord.com/developers/docs/topics/gateway-events#thread-delete>
pub struct ThreadDelete { pub struct ThreadDelete {