diff --git a/Cargo.lock b/Cargo.lock index 1ee2ace..d25b6f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,6 +125,7 @@ dependencies = [ "actix-web", "actix-web-actors", "derive_more", + "serde_json", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml index 3a5707b..0a7f570 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,5 @@ actix = "0.10.0" actix-web = "3" actix-web-actors = "3.0.0" uuid = { version = "0.8", features = ["serde", "v4"] } -derive_more = "0.99.11" \ No newline at end of file +derive_more = "0.99.11" +serde_json = "1.0.64" \ No newline at end of file diff --git a/src/actors/chat_server.rs b/src/actors/chat_server.rs index 80e59ac..8037a85 100644 --- a/src/actors/chat_server.rs +++ b/src/actors/chat_server.rs @@ -3,14 +3,14 @@ use std::collections::{HashMap, HashSet}; use uuid::Uuid; use crate::messages::{ - chat_server::{ClientMessage, Connect, Disconnect, JoinRoom}, + chat_server::{ClientMessage, Connect, CreateRoom, Disconnect, JoinRoom}, chat_session::Message, }; -use crate::models::SessionId; +use crate::models::{RoomId, SessionId}; pub struct ChatServer { sessions: HashMap>, - rooms: HashMap>, + rooms: HashMap>, } impl ChatServer { @@ -21,7 +21,7 @@ impl ChatServer { } } - pub fn send_message(&self, room: &str, message: &str, skip_id: &Uuid) { + pub fn send_message(&self, room: &Uuid, message: &str, skip_id: &Uuid) { self.rooms.get(room).map(|sessions| { sessions.iter().for_each(|id| { if id != skip_id { @@ -68,10 +68,25 @@ impl Handler for ChatServer { fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result { let ClientMessage { session, room, msg } = msg; + self.send_message(&room, &msg, &session); } } +impl Handler for ChatServer { + type Result = MessageResult; + + fn handle(&mut self, msg: CreateRoom, _ctx: &mut Self::Context) -> Self::Result { + let CreateRoom { session } = msg; + let room_id = RoomId::new_v4(); + self.rooms.insert( + room_id, + vec![session].into_iter().collect::>(), + ); + MessageResult(room_id) + } +} + impl Handler for ChatServer { type Result = (); fn handle( @@ -93,10 +108,8 @@ impl Handler for ChatServer { } self.rooms - .entry(room.clone()) - .or_insert_with(HashSet::new) - .insert(session); - - self.send_message(&room, "Someone connected", &session); + .get_mut(&room) + .map(|sessions| sessions.insert(session)) + .map(|_| self.send_message(&room, "Someone connected", &session)); } } diff --git a/src/actors/chat_session.rs b/src/actors/chat_session.rs index 39ce44f..bc62452 100644 --- a/src/actors/chat_session.rs +++ b/src/actors/chat_session.rs @@ -4,9 +4,10 @@ use crate::{ actors::chat_server::ChatServer, commands::Command, messages::{ - chat_server::{ClientMessage, Connect, Disconnect, JoinRoom}, + chat_server::{ClientMessage, Connect, Disconnect}, chat_session::Message, }, + models::{RoomId, SessionId}, }; use actix::{ fut, ActorContext, ActorFuture, ContextFutureSpawner, Handler, Running, StreamHandler, @@ -14,11 +15,10 @@ use actix::{ }; use actix::{Actor, Addr, AsyncContext}; use actix_web_actors::ws::{self, WebsocketContext}; -use uuid::Uuid; pub struct WsChatSession { - pub id: Option, - pub room: Option, + pub id: Option, + pub room: Option, pub addr: Addr, } @@ -31,15 +31,8 @@ impl WsChatSession { } } - pub fn execute(&self, cmd: Command, ctx: &mut WebsocketContext) { + pub fn execute(&self, cmd: Command, _ctx: &mut WebsocketContext) { match cmd { - Command::Join(name) => { - self.addr.do_send(JoinRoom { - session: self.id.unwrap().clone(), - room: name, - }); - ctx.text("Joined!"); - } Command::Msg(msg) => { self.addr.do_send(ClientMessage { session: self.id.clone().unwrap(), @@ -100,6 +93,7 @@ impl StreamHandler> for WsChatSession { }; match msg { + // TODO: Deserialize string to json first, then check action type ws::Message::Text(msg) => match Command::from_str(&msg) { Ok(cmd) => self.execute(cmd, ctx), Err(err) => ctx.text(err.to_string()), diff --git a/src/commands/mod.rs b/src/commands/mod.rs index f25c675..85d83d2 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -9,21 +9,14 @@ pub struct CommandError { } pub enum Command { - Join(String), Msg(String), } +// TODO: IMPLEMENT MORE COMMANDS impl FromStr for Command { type Err = CommandError; fn from_str(s: &str) -> Result { - let words: Vec<&str> = s.trim().split_whitespace().into_iter().collect(); - let first = words.first().map(|&v| v).unwrap_or(""); - if first == "/join" { - let name = words.last().map(|&v| v).unwrap_or(""); - Ok(Command::Join(name.into())) - } else { - Ok(Command::Msg(s.into())) - } + Ok(Command::Msg(s.into())) } } diff --git a/src/messages/chat_server.rs b/src/messages/chat_server.rs index cf81c9e..1f1a1e0 100644 --- a/src/messages/chat_server.rs +++ b/src/messages/chat_server.rs @@ -1,21 +1,28 @@ -use super::chat_session::Message; -use crate::models::SessionId; use actix::{Message as ActixMessage, Recipient}; use uuid::Uuid; +use crate::models::{RoomId, SessionId}; + +use super::chat_session::Message; + #[derive(ActixMessage)] #[rtype(result = "()")] pub struct ClientMessage { pub session: SessionId, - pub room: String, + pub room: RoomId, pub msg: String, } +#[derive(ActixMessage)] +#[rtype(result = "Uuid")] +pub struct CreateRoom { + pub session: SessionId, +} #[derive(ActixMessage)] #[rtype(result = "()")] pub struct JoinRoom { pub session: SessionId, - pub room: String, + pub room: RoomId, } #[derive(ActixMessage)] diff --git a/src/models/mod.rs b/src/models/mod.rs index 569c366..ae747ac 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,3 +1,4 @@ +pub mod ws_messages; use actix::Addr; use uuid::Uuid; diff --git a/src/models/ws_messages.rs b/src/models/ws_messages.rs new file mode 100644 index 0000000..e69de29