This commit is contained in:
Víctor Martínez 2021-03-07 15:04:03 +01:00
parent 76f3a81d07
commit 7bef1322a3
8 changed files with 45 additions and 35 deletions

1
Cargo.lock generated
View file

@ -125,6 +125,7 @@ dependencies = [
"actix-web", "actix-web",
"actix-web-actors", "actix-web-actors",
"derive_more", "derive_more",
"serde_json",
"uuid", "uuid",
] ]

View file

@ -14,4 +14,5 @@ actix = "0.10.0"
actix-web = "3" actix-web = "3"
actix-web-actors = "3.0.0" actix-web-actors = "3.0.0"
uuid = { version = "0.8", features = ["serde", "v4"] } uuid = { version = "0.8", features = ["serde", "v4"] }
derive_more = "0.99.11" derive_more = "0.99.11"
serde_json = "1.0.64"

View file

@ -3,14 +3,14 @@ use std::collections::{HashMap, HashSet};
use uuid::Uuid; use uuid::Uuid;
use crate::messages::{ use crate::messages::{
chat_server::{ClientMessage, Connect, Disconnect, JoinRoom}, chat_server::{ClientMessage, Connect, CreateRoom, Disconnect, JoinRoom},
chat_session::Message, chat_session::Message,
}; };
use crate::models::SessionId; use crate::models::{RoomId, SessionId};
pub struct ChatServer { pub struct ChatServer {
sessions: HashMap<SessionId, Recipient<Message>>, sessions: HashMap<SessionId, Recipient<Message>>,
rooms: HashMap<String, HashSet<SessionId>>, rooms: HashMap<RoomId, HashSet<SessionId>>,
} }
impl ChatServer { 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| { self.rooms.get(room).map(|sessions| {
sessions.iter().for_each(|id| { sessions.iter().for_each(|id| {
if id != skip_id { if id != skip_id {
@ -68,10 +68,25 @@ impl Handler<ClientMessage> for ChatServer {
fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result { fn handle(&mut self, msg: ClientMessage, _ctx: &mut Self::Context) -> Self::Result {
let ClientMessage { session, room, msg } = msg; let ClientMessage { session, room, msg } = msg;
self.send_message(&room, &msg, &session); self.send_message(&room, &msg, &session);
} }
} }
impl Handler<CreateRoom> for ChatServer {
type Result = MessageResult<CreateRoom>;
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::<HashSet<Uuid>>(),
);
MessageResult(room_id)
}
}
impl Handler<JoinRoom> for ChatServer { impl Handler<JoinRoom> for ChatServer {
type Result = (); type Result = ();
fn handle( fn handle(
@ -93,10 +108,8 @@ impl Handler<JoinRoom> for ChatServer {
} }
self.rooms self.rooms
.entry(room.clone()) .get_mut(&room)
.or_insert_with(HashSet::new) .map(|sessions| sessions.insert(session))
.insert(session); .map(|_| self.send_message(&room, "Someone connected", &session));
self.send_message(&room, "Someone connected", &session);
} }
} }

View file

@ -4,9 +4,10 @@ use crate::{
actors::chat_server::ChatServer, actors::chat_server::ChatServer,
commands::Command, commands::Command,
messages::{ messages::{
chat_server::{ClientMessage, Connect, Disconnect, JoinRoom}, chat_server::{ClientMessage, Connect, Disconnect},
chat_session::Message, chat_session::Message,
}, },
models::{RoomId, SessionId},
}; };
use actix::{ use actix::{
fut, ActorContext, ActorFuture, ContextFutureSpawner, Handler, Running, StreamHandler, fut, ActorContext, ActorFuture, ContextFutureSpawner, Handler, Running, StreamHandler,
@ -14,11 +15,10 @@ use actix::{
}; };
use actix::{Actor, Addr, AsyncContext}; use actix::{Actor, Addr, AsyncContext};
use actix_web_actors::ws::{self, WebsocketContext}; use actix_web_actors::ws::{self, WebsocketContext};
use uuid::Uuid;
pub struct WsChatSession { pub struct WsChatSession {
pub id: Option<Uuid>, pub id: Option<SessionId>,
pub room: Option<String>, pub room: Option<RoomId>,
pub addr: Addr<ChatServer>, pub addr: Addr<ChatServer>,
} }
@ -31,15 +31,8 @@ impl WsChatSession {
} }
} }
pub fn execute(&self, cmd: Command, ctx: &mut WebsocketContext<Self>) { pub fn execute(&self, cmd: Command, _ctx: &mut WebsocketContext<Self>) {
match cmd { match cmd {
Command::Join(name) => {
self.addr.do_send(JoinRoom {
session: self.id.unwrap().clone(),
room: name,
});
ctx.text("Joined!");
}
Command::Msg(msg) => { Command::Msg(msg) => {
self.addr.do_send(ClientMessage { self.addr.do_send(ClientMessage {
session: self.id.clone().unwrap(), session: self.id.clone().unwrap(),
@ -100,6 +93,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession {
}; };
match msg { match msg {
// TODO: Deserialize string to json first, then check action type
ws::Message::Text(msg) => match Command::from_str(&msg) { ws::Message::Text(msg) => match Command::from_str(&msg) {
Ok(cmd) => self.execute(cmd, ctx), Ok(cmd) => self.execute(cmd, ctx),
Err(err) => ctx.text(err.to_string()), Err(err) => ctx.text(err.to_string()),

View file

@ -9,21 +9,14 @@ pub struct CommandError {
} }
pub enum Command { pub enum Command {
Join(String),
Msg(String), Msg(String),
} }
// TODO: IMPLEMENT MORE COMMANDS
impl FromStr for Command { impl FromStr for Command {
type Err = CommandError; type Err = CommandError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let words: Vec<&str> = s.trim().split_whitespace().into_iter().collect(); Ok(Command::Msg(s.into()))
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()))
}
} }
} }

View file

@ -1,21 +1,28 @@
use super::chat_session::Message;
use crate::models::SessionId;
use actix::{Message as ActixMessage, Recipient}; use actix::{Message as ActixMessage, Recipient};
use uuid::Uuid; use uuid::Uuid;
use crate::models::{RoomId, SessionId};
use super::chat_session::Message;
#[derive(ActixMessage)] #[derive(ActixMessage)]
#[rtype(result = "()")] #[rtype(result = "()")]
pub struct ClientMessage { pub struct ClientMessage {
pub session: SessionId, pub session: SessionId,
pub room: String, pub room: RoomId,
pub msg: String, pub msg: String,
} }
#[derive(ActixMessage)]
#[rtype(result = "Uuid")]
pub struct CreateRoom {
pub session: SessionId,
}
#[derive(ActixMessage)] #[derive(ActixMessage)]
#[rtype(result = "()")] #[rtype(result = "()")]
pub struct JoinRoom { pub struct JoinRoom {
pub session: SessionId, pub session: SessionId,
pub room: String, pub room: RoomId,
} }
#[derive(ActixMessage)] #[derive(ActixMessage)]

View file

@ -1,3 +1,4 @@
pub mod ws_messages;
use actix::Addr; use actix::Addr;
use uuid::Uuid; use uuid::Uuid;

View file