diff --git a/Cargo.lock b/Cargo.lock index ca4b71a..0649a7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,6 +171,7 @@ name = "chat-types" version = "0.1.0" dependencies = [ "chrono", + "dev-dtos", "serde", "serde_json", "sqlx", @@ -332,6 +333,15 @@ dependencies = [ "pem-rfc7468", ] +[[package]] +name = "dev-dtos" +version = "0.1.0" +source = "git+https://git.franklinblanco.dev/franklinblanco/user-svc-dtos-rust.git#400f705ead30467cadc96d7aef6a3163f323df45" +dependencies = [ + "chrono", + "serde", +] + [[package]] name = "digest" version = "0.10.6" diff --git a/Cargo.toml b/Cargo.toml index 7192aca..5179c6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,6 @@ edition = "2021" serde = { version = "1.0", features = ["derive"] } chrono = { version = "0.4", features = [ "serde" ] } sqlx = { version = "0.6.0", features = [ "runtime-tokio-rustls", "mysql", "chrono", "decimal", "offline" ] } -serde_json = { version = "1" } \ No newline at end of file +serde_json = { version = "1" } + +dev-dtos = { git = "https://git.franklinblanco.dev/franklinblanco/user-svc-dtos-rust.git" } \ No newline at end of file diff --git a/src/domain/error.rs b/src/domain/error.rs new file mode 100644 index 0000000..ce1670a --- /dev/null +++ b/src/domain/error.rs @@ -0,0 +1,24 @@ +use std::{error::Error, fmt::Display}; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct SocketError { + pub message: String, +} +impl SocketError { + pub fn boxed_error(message: impl ToString) -> Box { + Box::new(Self { + message: message.to_string(), + }) + } +} +impl Display for SocketError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.message) + } +} + +impl Error for SocketError {} + +pub const MUTEX_LOCK_ERROR_MESSAGE: &str = "Fatal Error, mutex was attempted to be aqcuired while another thread had it and panicked while it was locked."; diff --git a/src/domain/mod.rs b/src/domain/mod.rs index effbc4f..06798a2 100644 --- a/src/domain/mod.rs +++ b/src/domain/mod.rs @@ -1,4 +1,5 @@ pub mod chat_message; pub mod chat_message_update; pub mod chat_room; -pub mod chat_user; \ No newline at end of file +pub mod chat_user; +pub mod error; \ No newline at end of file diff --git a/src/dto/mod.rs b/src/dto/mod.rs index 0ca6a90..349d773 100644 --- a/src/dto/mod.rs +++ b/src/dto/mod.rs @@ -1,2 +1,4 @@ pub mod chat; -pub mod message; \ No newline at end of file +pub mod message; +pub mod server_out; +pub mod server_in; \ No newline at end of file diff --git a/src/dto/server_in.rs b/src/dto/server_in.rs new file mode 100644 index 0000000..aaf3290 --- /dev/null +++ b/src/dto/server_in.rs @@ -0,0 +1,66 @@ +use std::fmt::Display; + +use crate::{domain::{chat_message::ChatMessageSender, error::SocketError}, dto::message::ClientMessage}; +use dev_dtos::dtos::user::user_dtos::UserForAuthenticationDto; +use serde::{Deserialize, Serialize}; + + +pub trait Receivable { + fn from_message( + message: ClientMessage, + ) -> Result> + where + Self: Sized; +} + +/// Message that can be recieved from the client to a connected socket +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub enum ServerMessageIn { + Login(UserForAuthenticationDto), + Logout, + + /// A list of MessageId's that the client reports to see + SeeMessages(Vec), + SendMessage(ChatMessageSender), + + /// Client can send this to server to fetch old messages. + /// By Old messages I mean: Messages that have already been delivered/seen + FetchMessages(), + + JoinGroup(), + LeaveGroup(), +} + +impl Display for ServerMessageIn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ServerMessageIn::Login(_) => write!(f, "LOGIN"), + ServerMessageIn::Logout => write!(f, "LOGOUT"), + ServerMessageIn::SeeMessages(_) => write!(f, "SEE MESSAGES"), + ServerMessageIn::SendMessage(_) => write!(f, "SEND MESSAGE"), + ServerMessageIn::JoinGroup() => write!(f, "JOIN GROUP"), + ServerMessageIn::LeaveGroup() => write!(f, "LEAVE GROUP"), + ServerMessageIn::FetchMessages() => write!(f, "FETCH MESSAGES"), + } + } +} + +impl Receivable for ServerMessageIn { + fn from_message( + message: ClientMessage, + ) -> Result> { + match message.head.as_str() { + "LOGIN" => Ok(Self::Login(serde_json::from_value(message.body)?)), + "LOGOUT" => Ok(Self::Logout), + "SEE MESSAGES" => Ok(Self::SeeMessages(serde_json::from_value(message.body)?)), + "SEND MESSAGE" => Ok(Self::SendMessage(serde_json::from_value(message.body)?)), + "JOIN GROUP" => Ok(Self::JoinGroup()), + "LEAVE GROUP" => Ok(Self::LeaveGroup()), + "FETCH MESSAGES" => Ok(Self::FetchMessages()), + _ => Err(SocketError::boxed_error(format!( + "ClientMessage recieved isn't recognized by the server. ClientMessage: {:#?}", + message + ))), + } + } +} diff --git a/src/dto/server_out.rs b/src/dto/server_out.rs new file mode 100644 index 0000000..5c09eb5 --- /dev/null +++ b/src/dto/server_out.rs @@ -0,0 +1,83 @@ +use crate::{domain::chat_message::{ChatMessage, TimeSensitiveAction}, dto::message::ClientMessage}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::fmt::Display; +pub trait Sendable { + fn into_message(self) -> Result>; +} + +/// Message sent from Server to client +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub enum ServerMessageOut { + Acknowledge, + LoggedIn, + + /// Whenever a user sends a message + MessageSent, + /// Whenever a user gets a message + MessageRecieved(ChatMessage), + /// Whenever a message sent by the user gets delivered along with the MessageId + MessageDelivered(ChatMessage), + /// Whenever a message sent by the user gets seen along with the MessageId + MessageSeen(ChatMessage), + + Error(String), +} +/// Used as a dto to notify the client that a specific message has been seen or delivered +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub struct MessageTimeChangeUpdate { + #[serde(rename = "timeUpdate")] + pub time_update: TimeSensitiveAction, + #[serde(rename = "chatMessageId")] + pub chat_message_id: u128, +} + +impl Display for ServerMessageOut { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ServerMessageOut::Acknowledge => write!(f, "ACKNOWLEDGE"), + ServerMessageOut::LoggedIn => write!(f, "LOGGED IN"), + ServerMessageOut::MessageSent => write!(f, "MESSAGE SENT"), + ServerMessageOut::MessageRecieved(_) => write!(f, "MESSAGE RECIEVED"), + ServerMessageOut::MessageDelivered(_) => write!(f, "MESSAGE DELIVERED"), + ServerMessageOut::MessageSeen(_) => write!(f, "MESSAGE SEEN"), + ServerMessageOut::Error(_) => write!(f, "ERROR"), + } + } +} + +impl Sendable for ServerMessageOut { + fn into_message(self) -> Result> { + let head = self.to_string(); + match self { + ServerMessageOut::Acknowledge => Ok(ClientMessage { + head, + body: Value::Null, + }), + ServerMessageOut::LoggedIn => Ok(ClientMessage { + head, + body: Value::Null, + }), + ServerMessageOut::MessageSent => Ok(ClientMessage { + head, + body: Value::Null, + }), + ServerMessageOut::MessageRecieved(chat_message) => Ok(ClientMessage { + head, + body: serde_json::to_value(chat_message)?, + }), + ServerMessageOut::MessageDelivered(delivered_info) => Ok(ClientMessage { + head, + body: serde_json::to_value(delivered_info)?, + }), + ServerMessageOut::MessageSeen(seen_info) => Ok(ClientMessage { + head, + body: serde_json::to_value(seen_info)?, + }), + ServerMessageOut::Error(error) => Ok(ClientMessage { + head, + body: serde_json::to_value(error)?, + }), + } + } +}