commands added & WsMessage data now is json

This commit is contained in:
Víctor Martínez 2021-03-22 00:58:39 +01:00
parent 64c80bf54a
commit adf255bd00
9 changed files with 119 additions and 30 deletions

57
Cargo.lock generated
View file

@ -99,7 +99,7 @@ dependencies = [
"mime", "mime",
"percent-encoding", "percent-encoding",
"pin-project 1.0.5", "pin-project 1.0.5",
"rand", "rand 0.7.3",
"regex", "regex",
"serde", "serde",
"serde_json", "serde_json",
@ -128,6 +128,7 @@ dependencies = [
"actix-web-actors", "actix-web-actors",
"derive_more", "derive_more",
"env_logger", "env_logger",
"rand 0.8.3",
"serde", "serde",
"serde_json", "serde_json",
"uuid", "uuid",
@ -399,7 +400,7 @@ dependencies = [
"log", "log",
"mime", "mime",
"percent-encoding", "percent-encoding",
"rand", "rand 0.7.3",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
@ -1269,9 +1270,21 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [ dependencies = [
"getrandom 0.1.16", "getrandom 0.1.16",
"libc", "libc",
"rand_chacha", "rand_chacha 0.2.2",
"rand_core", "rand_core 0.5.1",
"rand_hc", "rand_hc 0.2.0",
]
[[package]]
name = "rand"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
dependencies = [
"libc",
"rand_chacha 0.3.0",
"rand_core 0.6.2",
"rand_hc 0.3.0",
] ]
[[package]] [[package]]
@ -1281,7 +1294,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [ dependencies = [
"ppv-lite86", "ppv-lite86",
"rand_core", "rand_core 0.5.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
"ppv-lite86",
"rand_core 0.6.2",
] ]
[[package]] [[package]]
@ -1293,13 +1316,31 @@ dependencies = [
"getrandom 0.1.16", "getrandom 0.1.16",
] ]
[[package]]
name = "rand_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
dependencies = [
"getrandom 0.2.2",
]
[[package]] [[package]]
name = "rand_hc" name = "rand_hc"
version = "0.2.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [ dependencies = [
"rand_core", "rand_core 0.5.1",
]
[[package]]
name = "rand_hc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
"rand_core 0.6.2",
] ]
[[package]] [[package]]
@ -1724,7 +1765,7 @@ dependencies = [
"idna", "idna",
"lazy_static", "lazy_static",
"log", "log",
"rand", "rand 0.7.3",
"smallvec", "smallvec",
"thiserror", "thiserror",
"tokio", "tokio",

View file

@ -14,4 +14,5 @@ uuid = { version = "0.8", features = ["serde", "v4"] }
derive_more = "0.99.11" derive_more = "0.99.11"
serde_json = "1.0.64" serde_json = "1.0.64"
serde = "1.0.124" serde = "1.0.124"
env_logger = "0.8.3" env_logger = "0.8.3"
rand = "0.8.3"

View file

@ -27,13 +27,16 @@ impl ChatServer {
.unwrap_or(false) .unwrap_or(false)
} }
pub fn send_message(&self, room: &Uuid, message: &str, skip_id: &Uuid) { pub fn send_message(&self, room: &Uuid, message: &str, skip_id: &Uuid, user: Option<String>) {
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 {
self.sessions self.sessions.get(id).map(|addr| {
.get(id) addr.do_send(Message {
.map(|addr| addr.do_send(Message(message.into()))); nickname: user.clone(),
msg: message.into(),
})
});
} }
}); });
}); });
@ -49,7 +52,7 @@ impl ChatServer {
} }
// send message to other users // send message to other users
for room in rooms { for room in rooms {
self.send_message(&room, "Someone disconnected", &session_id); self.send_message(&room, "Someone disconnected", &session_id, None);
if self.is_empty(&room) { if self.is_empty(&room) {
self.rooms.remove(&room); self.rooms.remove(&room);
} }
@ -95,8 +98,13 @@ impl Handler<ClientMessage> for ChatServer {
type Result = (); type Result = ();
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 {
self.send_message(&room, &msg, &session); session,
user,
room,
msg,
} = msg;
self.send_message(&room, &msg, &session, Some(user));
} }
} }
@ -129,7 +137,7 @@ impl Handler<JoinRoom> for ChatServer {
.rooms .rooms
.get_mut(&room) .get_mut(&room)
.map(|sessions| sessions.insert(session)) .map(|sessions| sessions.insert(session))
.map(|_| self.send_message(&room, "Someone connected", &session)) .map(|_| self.send_message(&room, "Someone connected", &session, None))
.ok_or("The room doesn't exists".into()); .ok_or("The room doesn't exists".into());
MessageResult(result) MessageResult(result)

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
actors::chat_server::ChatServer, actors::chat_server::ChatServer,
constants::CLIENT_TIMEOUT, constants::CLIENT_TIMEOUT,
models::{RoomId, SessionId}, models::{RoomId, SessionId, UserInfo},
}; };
use crate::{ use crate::{
constants::HEARTBEAT_INTERVAL, constants::HEARTBEAT_INTERVAL,
@ -20,6 +20,7 @@ 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 serde_json::json;
use std::str::FromStr; use std::str::FromStr;
use uuid::Uuid; use uuid::Uuid;
@ -28,6 +29,7 @@ pub struct WsChatSession {
pub room: Option<RoomId>, pub room: Option<RoomId>,
pub addr: Addr<ChatServer>, pub addr: Addr<ChatServer>,
pub hb: Instant, pub hb: Instant,
pub user: UserInfo,
} }
impl WsChatSession { impl WsChatSession {
@ -36,6 +38,7 @@ impl WsChatSession {
id: Uuid::new_v4(), id: Uuid::new_v4(),
room: None, room: None,
hb: Instant::now(), hb: Instant::now(),
user: UserInfo::default(),
addr, addr,
} }
} }
@ -92,7 +95,10 @@ impl Handler<Message> for WsChatSession {
type Result = (); type Result = ();
fn handle(&mut self, msg: Message, ctx: &mut Self::Context) -> Self::Result { fn handle(&mut self, msg: Message, ctx: &mut Self::Context) -> Self::Result {
ctx.text(msg.0); ctx.text(WsMessage {
ty: MessageType::Msg,
data: json!(msg),
});
} }
} }
@ -132,14 +138,14 @@ impl Handler<WsMessage> for WsChatSession {
type Result = (); type Result = ();
fn handle(&mut self, msg: WsMessage, ctx: &mut Self::Context) -> Self::Result { fn handle(&mut self, msg: WsMessage, ctx: &mut Self::Context) -> Self::Result {
let data = msg.data.unwrap_or("".into()); let data = msg.data.as_str().unwrap();
match msg.ty { match msg.ty {
MessageType::Create => self.create(ctx), MessageType::Create => self.create(ctx),
MessageType::Join => match Uuid::from_str(&data) { MessageType::Join => match Uuid::from_str(&data) {
Ok(uuid) => self.join(uuid, ctx), Ok(uuid) => self.join(uuid, ctx),
Err(err) => ctx.text(WsMessage::err(err.to_string())), Err(err) => ctx.text(WsMessage::err(err.to_string())),
}, },
MessageType::Msg => self.msg(data, ctx), MessageType::Msg => self.msg(data.into(), ctx),
MessageType::Leave => self.leave(ctx), MessageType::Leave => self.leave(ctx),
_ => (), _ => (),
} }
@ -184,7 +190,7 @@ impl WsChatSession {
act.room = Some(room_id.clone()); act.room = Some(room_id.clone());
ctx.text(WsMessage { ctx.text(WsMessage {
ty: MessageType::Msg, ty: MessageType::Msg,
data: Some("Joined!".into()), data: json!("Joined!"),
}) })
} }
Ok(res) => ctx.text(WsMessage::err(res.unwrap_err().to_string())), Ok(res) => ctx.text(WsMessage::err(res.unwrap_err().to_string())),
@ -242,10 +248,12 @@ impl Handler<Command> for WsChatSession {
Command::Msg(msg) => { Command::Msg(msg) => {
self.addr.do_send(ClientMessage { self.addr.do_send(ClientMessage {
session: self.id.clone(), session: self.id.clone(),
user: self.user.nickname.clone(),
room: room_id, room: room_id,
msg, msg,
}); });
} }
Command::SetName(name) => self.user.nickname = name,
Command::GetRoomId => { Command::GetRoomId => {
ctx.text(WsMessage::info(room_id.to_string())); ctx.text(WsMessage::info(room_id.to_string()));
} }

View file

@ -7,6 +7,7 @@ use uuid::Uuid;
#[rtype(result = "()")] #[rtype(result = "()")]
pub struct ClientMessage { pub struct ClientMessage {
pub session: SessionId, pub session: SessionId,
pub user: String,
pub room: RoomId, pub room: RoomId,
pub msg: String, pub msg: String,
} }

View file

@ -8,6 +8,7 @@ use std::str::FromStr;
pub enum Command { pub enum Command {
Msg(String), Msg(String),
GetRoomId, GetRoomId,
SetName(String),
} }
#[derive(Debug, Display, Error)] #[derive(Debug, Display, Error)]
@ -22,11 +23,15 @@ impl FromStr for Command {
fn from_str(data: &str) -> Result<Self, Self::Err> { fn from_str(data: &str) -> Result<Self, Self::Err> {
let words: Vec<&str> = data.trim().split_whitespace().collect(); let words: Vec<&str> = data.trim().split_whitespace().collect();
let first_word = words.first(); let opt = words.split_first();
if let Some(&word) = first_word { if let Some((&command, words)) = opt {
return match word { return match command {
"/roomId" => Ok(Command::GetRoomId), "/roomId" => Ok(Command::GetRoomId),
"/setName" if words.len() > 0 => Ok(Command::SetName(words[0].into())),
"/setName" => Err(CommandError {
msg: "Invalid empty name",
}),
_ => Ok(Command::Msg(data.into())), _ => Ok(Command::Msg(data.into())),
}; };
} }

View file

@ -1,7 +1,11 @@
pub mod command; pub mod command;
pub mod wsmessage; pub mod wsmessage;
use actix::Message as ActixMessage; use actix::Message as ActixMessage;
use serde::Serialize;
#[derive(ActixMessage)] #[derive(Serialize, ActixMessage)]
#[rtype(result = "()")] #[rtype(result = "()")]
pub struct Message(pub String); pub struct Message {
pub nickname: Option<String>,
pub msg: String,
}

View file

@ -1,26 +1,27 @@
use actix::Message as ActixMessage; use actix::Message as ActixMessage;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use std::convert::Into; use std::convert::Into;
#[derive(Serialize, Deserialize, ActixMessage)] #[derive(Serialize, Deserialize, ActixMessage)]
#[rtype(result = "()")] #[rtype(result = "()")]
pub struct WsMessage { pub struct WsMessage {
pub ty: MessageType, pub ty: MessageType,
pub data: Option<String>, pub data: Value,
} }
impl WsMessage { impl WsMessage {
pub fn err(msg: String) -> Self { pub fn err(msg: String) -> Self {
WsMessage { WsMessage {
ty: MessageType::Err, ty: MessageType::Err,
data: Some(msg), data: json!(msg),
} }
} }
pub fn info(msg: String) -> Self { pub fn info(msg: String) -> Self {
WsMessage { WsMessage {
ty: MessageType::Info, ty: MessageType::Info,
data: Some(msg), data: json!(msg),
} }
} }
} }

View file

@ -1,5 +1,7 @@
use crate::actors::chat_server::ChatServer; use crate::actors::chat_server::ChatServer;
use actix::Addr; use actix::Addr;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use uuid::Uuid; use uuid::Uuid;
pub type SessionId = Uuid; pub type SessionId = Uuid;
@ -8,3 +10,21 @@ pub type RoomId = Uuid;
pub struct AppState { pub struct AppState {
pub chat: Addr<ChatServer>, pub chat: Addr<ChatServer>,
} }
pub struct UserInfo {
pub nickname: String,
}
impl Default for UserInfo {
fn default() -> Self {
let rand_string: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(15)
.map(char::from)
.collect();
let nickname = format!("User-{}", rand_string);
UserInfo { nickname }
}
}