Implement Observer for WebSocketEvents

This commit is contained in:
bitfl0wer 2023-04-28 12:31:59 +02:00
parent 8f97b48a09
commit 50b6029f54
No known key found for this signature in database
GPG Key ID: 84BBB60DF895ABF2
2 changed files with 92 additions and 21 deletions

View File

@ -2,7 +2,7 @@
To learn more about the types implemented here, please visit To learn more about the types implemented here, please visit
https://discord.com/developers/docs . https://discord.com/developers/docs .
I do not feel like re-documenting all of this, as everything is already perfectly explained there. I do not feel like re-documenting all of this, as everything is already perfectly explained there.
*/ */
use std::fmt; use std::fmt;
@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize};
use crate::{api::limits::Limits, URLBundle}; use crate::{api::limits::Limits, URLBundle};
pub trait WebSocketEvent {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct LoginResult { pub struct LoginResult {
token: String, token: String,
@ -246,6 +248,8 @@ struct MessageCreate {
mentions: Vec<(UserObject, GuildMember)>, // Not sure if this is correct: https://discord.com/developers/docs/topics/gateway-events#message-create mentions: Vec<(UserObject, GuildMember)>, // Not sure if this is correct: https://discord.com/developers/docs/topics/gateway-events#message-create
} }
impl WebSocketEvent for MessageCreate {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct PartialMessage { struct PartialMessage {
id: Option<String>, id: Option<String>,
@ -293,6 +297,8 @@ struct MessageUpdate {
mentions: Vec<(UserObject, GuildMember)>, // Not sure if this is correct: https://discord.com/developers/docs/topics/gateway-events#message-create mentions: Vec<(UserObject, GuildMember)>, // Not sure if this is correct: https://discord.com/developers/docs/topics/gateway-events#message-create
} }
impl WebSocketEvent for MessageUpdate {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct MessageDelete { struct MessageDelete {
id: String, id: String,
@ -300,6 +306,8 @@ struct MessageDelete {
guild_id: Option<String>, guild_id: Option<String>,
} }
impl WebSocketEvent for MessageDelete {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct MessageDeleteBulk { struct MessageDeleteBulk {
ids: Vec<String>, ids: Vec<String>,
@ -307,6 +315,8 @@ struct MessageDeleteBulk {
guild_id: Option<String>, guild_id: Option<String>,
} }
impl WebSocketEvent for MessageDeleteBulk {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct MessageReactionAdd { struct MessageReactionAdd {
user_id: String, user_id: String,
@ -317,6 +327,8 @@ struct MessageReactionAdd {
emoji: Emoji, emoji: Emoji,
} }
impl WebSocketEvent for MessageReactionAdd {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct MessageReactionRemove { struct MessageReactionRemove {
user_id: String, user_id: String,
@ -326,6 +338,8 @@ struct MessageReactionRemove {
emoji: Emoji, emoji: Emoji,
} }
impl WebSocketEvent for MessageReactionRemove {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct MessageReactionRemoveAll { struct MessageReactionRemoveAll {
channel_id: String, channel_id: String,
@ -333,6 +347,8 @@ struct MessageReactionRemoveAll {
guild_id: Option<String>, guild_id: Option<String>,
} }
impl WebSocketEvent for MessageReactionRemoveAll {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct MessageReactionRemoveEmoji { struct MessageReactionRemoveEmoji {
channel_id: String, channel_id: String,
@ -341,6 +357,8 @@ struct MessageReactionRemoveEmoji {
emoji: Emoji, emoji: Emoji,
} }
impl WebSocketEvent for MessageReactionRemoveEmoji {}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct ChannelMention { struct ChannelMention {
id: String, id: String,
@ -689,6 +707,8 @@ struct TypingStartEvent {
member: Option<GuildMember>, member: Option<GuildMember>,
} }
impl WebSocketEvent for TypingStartEvent {}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct GatewayIdentifyPayload { struct GatewayIdentifyPayload {
token: String, token: String,
@ -700,6 +720,8 @@ struct GatewayIdentifyPayload {
intents: i32, intents: i32,
} }
impl WebSocketEvent for GatewayIdentifyPayload {}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct GatewayIdentifyConnectionProps { struct GatewayIdentifyConnectionProps {
os: String, os: String,
@ -715,6 +737,8 @@ struct PresenceUpdate {
afk: bool, afk: bool,
} }
impl WebSocketEvent for PresenceUpdate {}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct Activity { struct Activity {
name: String, name: String,
@ -770,8 +794,10 @@ struct ActivityButton {
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct GatewayResume { pub(crate) struct GatewayResume {
token: String, pub(crate) token: String,
session_id: String, pub(crate) session_id: String,
seq: String, pub(crate) seq: String,
} }
impl WebSocketEvent for GatewayResume {}

View File

@ -1,24 +1,24 @@
use crate::errors::ObserverError; use crate::{api::WebSocketEvent, errors::ObserverError};
#[derive(Debug)] #[derive(Debug)]
pub struct Gateway {} pub struct Gateway {}
pub trait Observer { pub trait Observer<T: WebSocketEvent> {
fn update(&self, data: &str); fn update(&self, data: &T);
} }
pub struct GatewayEvent<'a> { pub struct GatewayEvent<'a, T: WebSocketEvent> {
observers: Vec<&'a dyn Observer>, observers: Vec<&'a dyn Observer<T>>,
pub test_content: String, pub event_data: T,
pub is_observed: bool, pub is_observed: bool,
} }
impl<'a> GatewayEvent<'a> { impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> {
fn new(test_content: String) -> Self { fn new(event_data: T) -> Self {
Self { Self {
is_observed: false, is_observed: false,
observers: Vec::new(), observers: Vec::new(),
test_content, event_data,
} }
} }
@ -26,7 +26,7 @@ impl<'a> GatewayEvent<'a> {
self.is_observed self.is_observed
} }
pub fn subscribe(&mut self, observable: &'a dyn Observer) -> Option<ObserverError> { pub fn subscribe(&mut self, observable: &'a dyn Observer<T>) -> Option<ObserverError> {
if self.is_observed { if self.is_observed {
return Some(ObserverError::AlreadySubscribedError); return Some(ObserverError::AlreadySubscribedError);
} }
@ -35,20 +35,65 @@ impl<'a> GatewayEvent<'a> {
None None
} }
pub fn unsubscribe(&mut self, observable: &'a dyn Observer) { pub fn unsubscribe(&mut self, observable: &'a dyn Observer<T>) {
self.observers.pop(); // .retain()'s closure retains only those elements of the vector, which have a different
self.is_observed = false; // pointer value than observable.
self.observers.retain(|obs| !std::ptr::eq(*obs, observable));
self.is_observed = !self.observers.is_empty();
return; return;
} }
fn update_data(&mut self, test_content: String) { fn update_data(&mut self, new_event_data: T) {
self.test_content = test_content; self.event_data = new_event_data;
self.notify(); self.notify();
} }
fn notify(&self) { fn notify(&self) {
for observer in &self.observers { for observer in &self.observers {
observer.update(&self.test_content); observer.update(&self.event_data);
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::api::types::GatewayResume;
struct Consumer;
impl Observer<GatewayResume> for Consumer {
fn update(&self, data: &GatewayResume) {
println!("{}", data.token)
}
}
#[test]
fn test_observer_behaviour() {
let mut event = GatewayEvent::new(GatewayResume {
token: "start".to_string(),
session_id: "start".to_string(),
seq: "start".to_string(),
});
let new_data = GatewayResume {
token: "token_3276ha37am3".to_string(),
session_id: "89346671230".to_string(),
seq: "3".to_string(),
};
let consumer = Consumer;
event.subscribe(&consumer);
event.notify();
event.update_data(new_data);
let second_consumer = Consumer;
match event.subscribe(&second_consumer) {
None => return,
Some(err) => println!("You cannot subscribe twice: {}", err),
} }
} }
} }