diff --git a/src/api/types.rs b/src/api/types.rs index c50520f..393ed01 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -2,7 +2,7 @@ To learn more about the types implemented here, please visit https://discord.com/developers/docs . I do not feel like re-documenting all of this, as everything is already perfectly explained there. - */ +*/ use std::fmt; @@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize}; use crate::{api::limits::Limits, URLBundle}; +pub trait WebSocketEvent {} + #[derive(Debug, Serialize, Deserialize)] pub struct LoginResult { 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 } +impl WebSocketEvent for MessageCreate {} + #[derive(Debug, Serialize, Deserialize)] struct PartialMessage { id: Option, @@ -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 } +impl WebSocketEvent for MessageUpdate {} + #[derive(Debug, Serialize, Deserialize)] struct MessageDelete { id: String, @@ -300,6 +306,8 @@ struct MessageDelete { guild_id: Option, } +impl WebSocketEvent for MessageDelete {} + #[derive(Debug, Serialize, Deserialize)] struct MessageDeleteBulk { ids: Vec, @@ -307,6 +315,8 @@ struct MessageDeleteBulk { guild_id: Option, } +impl WebSocketEvent for MessageDeleteBulk {} + #[derive(Debug, Serialize, Deserialize)] struct MessageReactionAdd { user_id: String, @@ -317,6 +327,8 @@ struct MessageReactionAdd { emoji: Emoji, } +impl WebSocketEvent for MessageReactionAdd {} + #[derive(Debug, Serialize, Deserialize)] struct MessageReactionRemove { user_id: String, @@ -326,6 +338,8 @@ struct MessageReactionRemove { emoji: Emoji, } +impl WebSocketEvent for MessageReactionRemove {} + #[derive(Debug, Serialize, Deserialize)] struct MessageReactionRemoveAll { channel_id: String, @@ -333,6 +347,8 @@ struct MessageReactionRemoveAll { guild_id: Option, } +impl WebSocketEvent for MessageReactionRemoveAll {} + #[derive(Debug, Serialize, Deserialize)] struct MessageReactionRemoveEmoji { channel_id: String, @@ -341,6 +357,8 @@ struct MessageReactionRemoveEmoji { emoji: Emoji, } +impl WebSocketEvent for MessageReactionRemoveEmoji {} + #[derive(Debug, Serialize, Deserialize)] struct ChannelMention { id: String, @@ -689,6 +707,8 @@ struct TypingStartEvent { member: Option, } +impl WebSocketEvent for TypingStartEvent {} + #[derive(Debug, Deserialize, Serialize)] struct GatewayIdentifyPayload { token: String, @@ -700,6 +720,8 @@ struct GatewayIdentifyPayload { intents: i32, } +impl WebSocketEvent for GatewayIdentifyPayload {} + #[derive(Debug, Deserialize, Serialize)] struct GatewayIdentifyConnectionProps { os: String, @@ -715,6 +737,8 @@ struct PresenceUpdate { afk: bool, } +impl WebSocketEvent for PresenceUpdate {} + #[derive(Debug, Deserialize, Serialize)] struct Activity { name: String, @@ -770,8 +794,10 @@ struct ActivityButton { } #[derive(Debug, Deserialize, Serialize)] -struct GatewayResume { - token: String, - session_id: String, - seq: String, +pub(crate) struct GatewayResume { + pub(crate) token: String, + pub(crate) session_id: String, + pub(crate) seq: String, } + +impl WebSocketEvent for GatewayResume {} diff --git a/src/gateway.rs b/src/gateway.rs index 9a05fec..19a6a48 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -1,24 +1,24 @@ -use crate::errors::ObserverError; +use crate::{api::WebSocketEvent, errors::ObserverError}; #[derive(Debug)] pub struct Gateway {} -pub trait Observer { - fn update(&self, data: &str); +pub trait Observer { + fn update(&self, data: &T); } -pub struct GatewayEvent<'a> { - observers: Vec<&'a dyn Observer>, - pub test_content: String, +pub struct GatewayEvent<'a, T: WebSocketEvent> { + observers: Vec<&'a dyn Observer>, + pub event_data: T, pub is_observed: bool, } -impl<'a> GatewayEvent<'a> { - fn new(test_content: String) -> Self { +impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> { + fn new(event_data: T) -> Self { Self { is_observed: false, observers: Vec::new(), - test_content, + event_data, } } @@ -26,7 +26,7 @@ impl<'a> GatewayEvent<'a> { self.is_observed } - pub fn subscribe(&mut self, observable: &'a dyn Observer) -> Option { + pub fn subscribe(&mut self, observable: &'a dyn Observer) -> Option { if self.is_observed { return Some(ObserverError::AlreadySubscribedError); } @@ -35,20 +35,65 @@ impl<'a> GatewayEvent<'a> { None } - pub fn unsubscribe(&mut self, observable: &'a dyn Observer) { - self.observers.pop(); - self.is_observed = false; + pub fn unsubscribe(&mut self, observable: &'a dyn Observer) { + // .retain()'s closure retains only those elements of the vector, which have a different + // pointer value than observable. + self.observers.retain(|obs| !std::ptr::eq(*obs, observable)); + self.is_observed = !self.observers.is_empty(); return; } - fn update_data(&mut self, test_content: String) { - self.test_content = test_content; + fn update_data(&mut self, new_event_data: T) { + self.event_data = new_event_data; self.notify(); } fn notify(&self) { 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 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), } } }