diff --git a/src/api/types.rs b/src/api/types.rs index 393ed01..0ed1755 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -134,7 +134,7 @@ pub struct Error { pub code: String, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Default)] pub struct UserObject { id: String, username: String, @@ -203,8 +203,8 @@ impl User { } } -#[derive(Debug, Serialize, Deserialize)] -struct Message { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct Message { id: String, channel_id: String, author: UserObject, @@ -239,8 +239,8 @@ struct Message { role_subscription_data: Option, } -#[derive(Debug, Serialize, Deserialize)] -struct MessageCreate { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageCreate { #[serde(flatten)] message: Message, guild_id: Option, @@ -250,7 +250,7 @@ struct MessageCreate { impl WebSocketEvent for MessageCreate {} -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Default)] struct PartialMessage { id: Option, channel_id: Option, @@ -288,8 +288,8 @@ struct PartialMessage { member: Option, } -#[derive(Debug, Serialize, Deserialize)] -struct MessageUpdate { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageUpdate { #[serde(flatten)] message: PartialMessage, guild_id: Option, @@ -299,8 +299,8 @@ struct MessageUpdate { impl WebSocketEvent for MessageUpdate {} -#[derive(Debug, Serialize, Deserialize)] -struct MessageDelete { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageDelete { id: String, channel_id: String, guild_id: Option, @@ -308,8 +308,8 @@ struct MessageDelete { impl WebSocketEvent for MessageDelete {} -#[derive(Debug, Serialize, Deserialize)] -struct MessageDeleteBulk { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageDeleteBulk { ids: Vec, channel_id: String, guild_id: Option, @@ -317,8 +317,8 @@ struct MessageDeleteBulk { impl WebSocketEvent for MessageDeleteBulk {} -#[derive(Debug, Serialize, Deserialize)] -struct MessageReactionAdd { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageReactionAdd { user_id: String, channel_id: String, message_id: String, @@ -329,8 +329,8 @@ struct MessageReactionAdd { impl WebSocketEvent for MessageReactionAdd {} -#[derive(Debug, Serialize, Deserialize)] -struct MessageReactionRemove { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageReactionRemove { user_id: String, channel_id: String, message_id: String, @@ -340,8 +340,8 @@ struct MessageReactionRemove { impl WebSocketEvent for MessageReactionRemove {} -#[derive(Debug, Serialize, Deserialize)] -struct MessageReactionRemoveAll { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageReactionRemoveAll { channel_id: String, message_id: String, guild_id: Option, @@ -349,8 +349,8 @@ struct MessageReactionRemoveAll { impl WebSocketEvent for MessageReactionRemoveAll {} -#[derive(Debug, Serialize, Deserialize)] -struct MessageReactionRemoveEmoji { +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct MessageReactionRemoveEmoji { channel_id: String, message_id: String, guild_id: Option, @@ -463,7 +463,7 @@ struct Reaction { emoji: Emoji, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Default)] struct Emoji { id: Option, name: Option, @@ -698,8 +698,8 @@ struct RoleSubscriptionData { is_renewal: bool, } -#[derive(Debug, Deserialize, Serialize)] -struct TypingStartEvent { +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct TypingStartEvent { channel_id: String, guild_id: Option, user_id: String, @@ -709,8 +709,8 @@ struct TypingStartEvent { impl WebSocketEvent for TypingStartEvent {} -#[derive(Debug, Deserialize, Serialize)] -struct GatewayIdentifyPayload { +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct GatewayIdentifyPayload { token: String, properties: GatewayIdentifyConnectionProps, compress: Option, @@ -722,15 +722,15 @@ struct GatewayIdentifyPayload { impl WebSocketEvent for GatewayIdentifyPayload {} -#[derive(Debug, Deserialize, Serialize)] -struct GatewayIdentifyConnectionProps { - os: String, - browser: String, - device: String, +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct GatewayIdentifyConnectionProps { + pub os: String, + pub browser: String, + pub device: String, } -#[derive(Debug, Deserialize, Serialize)] -struct PresenceUpdate { +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct PresenceUpdate { since: Option, activities: Vec, status: String, @@ -793,11 +793,11 @@ struct ActivityButton { url: String, } -#[derive(Debug, Deserialize, Serialize)] -pub(crate) struct GatewayResume { - pub(crate) token: String, - pub(crate) session_id: String, - pub(crate) seq: String, +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct GatewayResume { + pub token: String, + pub session_id: String, + pub seq: String, } impl WebSocketEvent for GatewayResume {} diff --git a/src/gateway.rs b/src/gateway.rs index 558e66f..84a1f96 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -1,23 +1,50 @@ -use crate::{api::WebSocketEvent, errors::ObserverError}; +use crate::api::types::*; +use crate::api::WebSocketEvent; +use crate::errors::ObserverError; +use crate::gateway::events::Events; +use crate::URLBundle; +use reqwest::{Client, Url}; +use tokio::net::TcpStream; +use tokio_tungstenite::tungstenite::error::UrlError; +use tokio_tungstenite::tungstenite::Error; +use tokio_tungstenite::MaybeTlsStream; +use tokio_tungstenite::WebSocketStream; +use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; -#[derive(Debug)] /** -Represents a Gateway connection. - */ -pub struct Gateway {} +Represents a Gateway connection. A Gateway connection will create observable +[`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently +implemented [Types] with the trait [`WebSocketEvent`] +*/ +pub struct Gateway<'a> { + pub url: String, + pub events: Events<'a>, + stream: WebSocketStream>, +} + +impl<'a> Gateway<'a> { + pub async fn new(websocket_url: String) { + let parsed_url = Url::parse(&URLBundle::parse_url(websocket_url.clone())).unwrap(); + if parsed_url.scheme() != "ws" && parsed_url.scheme() != "wss" { + return Err(Error::Url(UrlError::UnsupportedUrlScheme)); + } + } +} /** Trait which defines the behaviour of an Observer. An Observer is an object which is subscribed to an Observable. The Observer is notified when the Observable's data changes. -In this case, the Observable is a GatewayEvent, which is a wrapper around a WebSocketEvent. +In this case, the Observable is a [`GatewayEvent`], which is a wrapper around a WebSocketEvent. */ pub trait Observer { fn update(&self, data: &T); } /** GatewayEvent is a wrapper around a WebSocketEvent. It is used to notify the observers of a - * change in the WebSocketEvent. - */ +change in the WebSocketEvent. GatewayEvents are observable. +*/ + +#[derive(Default)] pub struct GatewayEvent<'a, T: WebSocketEvent> { observers: Vec<&'a dyn Observer>, pub event_data: T, @@ -35,7 +62,7 @@ impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> { /** Returns true if the GatewayEvent is observed by at least one Observer. - */ + */ pub fn is_observed(&self) -> bool { self.is_observed } @@ -46,7 +73,7 @@ impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> { # Errors Returns an error if the GatewayEvent is already observed. Error type: [`ObserverError::AlreadySubscribedError`] - */ + */ pub fn subscribe(&mut self, observable: &'a dyn Observer) -> Option { if self.is_observed { return Some(ObserverError::AlreadySubscribedError); @@ -58,7 +85,7 @@ impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> { /** Unsubscribes an Observer from the GatewayEvent. - */ + */ 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. @@ -69,7 +96,7 @@ impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> { /** Updates the GatewayEvent's data and notifies the observers. - */ + */ fn update_data(&mut self, new_event_data: T) { self.event_data = new_event_data; self.notify(); @@ -77,7 +104,7 @@ impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> { /** Notifies the observers of the GatewayEvent. - */ + */ fn notify(&self) { for observer in &self.observers { observer.update(&self.event_data); @@ -85,6 +112,35 @@ impl<'a, T: WebSocketEvent> GatewayEvent<'a, T> { } } +mod events { + use super::*; + #[derive(Default)] + pub struct Events<'a> { + pub message: Message<'a>, + pub user: User<'a>, + pub gateway_identify_payload: GatewayEvent<'a, GatewayIdentifyPayload>, + pub gateway_resume: GatewayEvent<'a, GatewayResume>, + } + + #[derive(Default)] + pub struct Message<'a> { + pub create: GatewayEvent<'a, MessageCreate>, + pub update: GatewayEvent<'a, MessageUpdate>, + pub delete: GatewayEvent<'a, MessageDelete>, + pub delete_bulk: GatewayEvent<'a, MessageDeleteBulk>, + pub reaction_add: GatewayEvent<'a, MessageReactionAdd>, + pub reaction_remove: GatewayEvent<'a, MessageReactionRemove>, + pub reaction_remove_all: GatewayEvent<'a, MessageReactionRemoveAll>, + pub reaction_remove_emoji: GatewayEvent<'a, MessageReactionRemoveEmoji>, + } + + #[derive(Default)] + pub struct User<'a> { + pub presence_update: GatewayEvent<'a, PresenceUpdate>, + pub typing_start_event: GatewayEvent<'a, TypingStartEvent>, + } +} + #[cfg(test)] mod example { use super::*;