mirror of
https://codeberg.org/JasterV/chat-rooms-actix.git
synced 2026-04-26 18:10:04 +00:00
refactor
This commit is contained in:
parent
667053ce6b
commit
4e0ca5821e
11 changed files with 167 additions and 156 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::messages::{
|
use crate::messages::{
|
||||||
chat_server::{ClientMessage, Connect, CreateRoom, Disconnect, JoinRoom, Leave},
|
server::{ClientMessage, Connect, CreateRoom, Disconnect, JoinRoom, Leave},
|
||||||
chat_session::Message,
|
session::Message,
|
||||||
};
|
};
|
||||||
use crate::models::{RoomId, SessionId};
|
use crate::models::{RoomId, SessionId};
|
||||||
use actix::{Actor, Context, Handler, MessageResult, Recipient};
|
use actix::{Actor, Context, Handler, MessageResult, Recipient};
|
||||||
|
|
@ -63,7 +63,7 @@ impl Actor for ChatServer {
|
||||||
|
|
||||||
impl Handler<Connect> for ChatServer {
|
impl Handler<Connect> for ChatServer {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
|
|
||||||
fn handle(&mut self, msg: Connect, _ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, msg: Connect, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
let Connect { id, addr } = msg;
|
let Connect { id, addr } = msg;
|
||||||
self.sessions.insert(id, addr);
|
self.sessions.insert(id, addr);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
actors::chat_server::ChatServer,
|
actors::chat_server::ChatServer,
|
||||||
constants::CLIENT_TIMEOUT,
|
constants::CLIENT_TIMEOUT,
|
||||||
models::{
|
models::{RoomId, SessionId},
|
||||||
commands::Command,
|
|
||||||
ws::{MessageType, WsMessage},
|
|
||||||
RoomId, SessionId,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::HEARTBEAT_INTERVAL,
|
constants::HEARTBEAT_INTERVAL,
|
||||||
messages::{
|
messages::{
|
||||||
chat_server::{ClientMessage, Connect, CreateRoom, Disconnect, JoinRoom, Leave},
|
server::{ClientMessage, Connect, CreateRoom, Disconnect, JoinRoom, Leave},
|
||||||
chat_session::Message,
|
session::{
|
||||||
|
command::Command,
|
||||||
|
wsmessage::{MessageType, WsMessage},
|
||||||
|
Message,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use actix::{
|
use actix::{
|
||||||
|
|
@ -55,124 +55,6 @@ impl WsChatSession {
|
||||||
ctx.ping(b"");
|
ctx.ping(b"");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_msg(&self, msg: WsMessage, ctx: &mut WebsocketContext<Self>) {
|
|
||||||
let data = msg.data.unwrap_or("".into());
|
|
||||||
match msg.ty {
|
|
||||||
MessageType::Create => self.create(ctx),
|
|
||||||
MessageType::Join => self.join(data, ctx),
|
|
||||||
MessageType::Msg => self.msg(data, ctx),
|
|
||||||
MessageType::Leave => self.leave(ctx),
|
|
||||||
MessageType::Err => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute(&self, cmd: Command, _ctx: &mut WebsocketContext<Self>) {
|
|
||||||
match cmd {
|
|
||||||
Command::Msg(msg) => {
|
|
||||||
self.addr.do_send(ClientMessage {
|
|
||||||
session: self.id.clone(),
|
|
||||||
room: self.room.clone().unwrap(),
|
|
||||||
msg,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(&self, ctx: &mut WebsocketContext<Self>) {
|
|
||||||
self.addr
|
|
||||||
.send(CreateRoom {
|
|
||||||
session: self.id.clone(),
|
|
||||||
})
|
|
||||||
.into_actor(self)
|
|
||||||
.then(|res, act, ctx| {
|
|
||||||
match res {
|
|
||||||
Ok(res) => {
|
|
||||||
act.room = Some(res.clone());
|
|
||||||
ctx.text(WsMessage {
|
|
||||||
ty: MessageType::Create,
|
|
||||||
data: Some(res.to_string()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// something is wrong with chat server
|
|
||||||
Err(err) => {
|
|
||||||
ctx.text(WsMessage::err(err.to_string()));
|
|
||||||
ctx.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fut::ready(())
|
|
||||||
})
|
|
||||||
.wait(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn join(&self, room_id: String, ctx: &mut WebsocketContext<Self>) {
|
|
||||||
match Uuid::from_str(&room_id) {
|
|
||||||
Ok(uuid) => {
|
|
||||||
self.addr
|
|
||||||
.send(JoinRoom {
|
|
||||||
room: uuid,
|
|
||||||
session: self.id.clone(),
|
|
||||||
})
|
|
||||||
.into_actor(self)
|
|
||||||
.then(move |res, act, ctx| {
|
|
||||||
match res {
|
|
||||||
Ok(res) => match res {
|
|
||||||
Ok(_) => {
|
|
||||||
act.room = Some(uuid.clone());
|
|
||||||
ctx.text(WsMessage {
|
|
||||||
ty: MessageType::Msg,
|
|
||||||
data: Some("Joined!".into()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Err(err) => ctx.text(WsMessage::err(err.to_string())),
|
|
||||||
},
|
|
||||||
// something is wrong with chat server
|
|
||||||
Err(err) => {
|
|
||||||
ctx.text(WsMessage::err(err.to_string()));
|
|
||||||
ctx.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fut::ready(())
|
|
||||||
})
|
|
||||||
.wait(ctx);
|
|
||||||
}
|
|
||||||
Err(err) => ctx.text(WsMessage::err(err.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn msg(&self, msg: String, ctx: &mut WebsocketContext<Self>) {
|
|
||||||
match Command::from_str(&msg) {
|
|
||||||
Ok(cmd) if self.room.is_some() => self.execute(cmd, ctx),
|
|
||||||
Ok(_) => ctx.text(WsMessage::err("You are not in a room yet".into())),
|
|
||||||
Err(err) => ctx.text(WsMessage::err(err.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn leave(&self, ctx: &mut WebsocketContext<Self>) {
|
|
||||||
self.addr
|
|
||||||
.send(Leave {
|
|
||||||
session: self.id.clone(),
|
|
||||||
})
|
|
||||||
.into_actor(self)
|
|
||||||
.then(move |res, act, ctx| {
|
|
||||||
match res {
|
|
||||||
Ok(_) => {
|
|
||||||
act.room = None;
|
|
||||||
ctx.text(WsMessage {
|
|
||||||
ty: MessageType::Leave,
|
|
||||||
data: Some("Room leaved".into()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// something is wrong with chat server
|
|
||||||
Err(err) => {
|
|
||||||
ctx.text(WsMessage::err(err.to_string()));
|
|
||||||
ctx.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fut::ready(())
|
|
||||||
})
|
|
||||||
.wait(ctx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actor for WsChatSession {
|
impl Actor for WsChatSession {
|
||||||
|
|
@ -227,7 +109,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession {
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
ws::Message::Text(msg) => match serde_json::from_str::<WsMessage>(&msg) {
|
ws::Message::Text(msg) => match serde_json::from_str::<WsMessage>(&msg) {
|
||||||
Ok(content) => self.handle_msg(content, ctx),
|
Ok(content) => ctx.notify(content),
|
||||||
Err(err) => ctx.text(WsMessage::err(err.to_string())),
|
Err(err) => ctx.text(WsMessage::err(err.to_string())),
|
||||||
},
|
},
|
||||||
ws::Message::Ping(msg) => {
|
ws::Message::Ping(msg) => {
|
||||||
|
|
@ -245,3 +127,121 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsChatSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Handler<WsMessage> for WsChatSession {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: WsMessage, ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
let data = msg.data.unwrap_or("".into());
|
||||||
|
match msg.ty {
|
||||||
|
MessageType::Create => self.create(ctx),
|
||||||
|
MessageType::Join => match Uuid::from_str(&data) {
|
||||||
|
Ok(uuid) => self.join(uuid, ctx),
|
||||||
|
Err(err) => ctx.text(WsMessage::err(err.to_string())),
|
||||||
|
},
|
||||||
|
MessageType::Msg => self.msg(data, ctx),
|
||||||
|
MessageType::Leave => self.leave(ctx),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WsChatSession {
|
||||||
|
fn create(&self, ctx: &mut WebsocketContext<Self>) {
|
||||||
|
let send_create = self.addr.send(CreateRoom {
|
||||||
|
session: self.id.clone(),
|
||||||
|
});
|
||||||
|
let send_create = send_create.into_actor(self);
|
||||||
|
send_create
|
||||||
|
.then(move |res, act, ctx| {
|
||||||
|
// Actor's state updated here
|
||||||
|
match res {
|
||||||
|
Ok(res) => {
|
||||||
|
act.room = Some(res.clone());
|
||||||
|
ctx.text(WsMessage::info(res.to_string()));
|
||||||
|
}
|
||||||
|
// something is wrong with chat server
|
||||||
|
Err(err) => {
|
||||||
|
ctx.text(WsMessage::err(err.to_string()));
|
||||||
|
ctx.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fut::ready(())
|
||||||
|
})
|
||||||
|
.wait(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn join(&self, room_id: Uuid, ctx: &mut WebsocketContext<Self>) {
|
||||||
|
let join_room = self.addr.send(JoinRoom {
|
||||||
|
room: room_id,
|
||||||
|
session: self.id.clone(),
|
||||||
|
});
|
||||||
|
let join_room = join_room.into_actor(self);
|
||||||
|
join_room
|
||||||
|
.then(move |response, act, ctx| {
|
||||||
|
match response {
|
||||||
|
Ok(res) if res.is_ok() => {
|
||||||
|
act.room = Some(room_id.clone());
|
||||||
|
ctx.text(WsMessage {
|
||||||
|
ty: MessageType::Msg,
|
||||||
|
data: Some("Joined!".into()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(res) => ctx.text(WsMessage::err(res.unwrap_err().to_string())),
|
||||||
|
Err(err) => {
|
||||||
|
ctx.text(WsMessage::err(err.to_string()));
|
||||||
|
ctx.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fut::ready(())
|
||||||
|
})
|
||||||
|
.wait(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msg(&self, msg: String, ctx: &mut WebsocketContext<Self>) {
|
||||||
|
match Command::from_str(&msg) {
|
||||||
|
Ok(cmd) if self.room.is_some() => ctx.notify(cmd),
|
||||||
|
Ok(_) => ctx.text(WsMessage::err("You are not in a room yet".into())),
|
||||||
|
Err(err) => ctx.text(WsMessage::err(err.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(&self, ctx: &mut WebsocketContext<Self>) {
|
||||||
|
self.addr
|
||||||
|
.send(Leave {
|
||||||
|
session: self.id.clone(),
|
||||||
|
})
|
||||||
|
.into_actor(self)
|
||||||
|
.then(move |res, act, ctx| {
|
||||||
|
match res {
|
||||||
|
Ok(_) => {
|
||||||
|
act.room = None;
|
||||||
|
ctx.text(WsMessage::info("Room leaved".into()))
|
||||||
|
}
|
||||||
|
// something is wrong with chat server
|
||||||
|
Err(err) => {
|
||||||
|
ctx.text(WsMessage::err(err.to_string()));
|
||||||
|
ctx.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fut::ready(())
|
||||||
|
})
|
||||||
|
.wait(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<Command> for WsChatSession {
|
||||||
|
type Result = ();
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: Command, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
match msg {
|
||||||
|
Command::Msg(msg) => {
|
||||||
|
self.addr.do_send(ClientMessage {
|
||||||
|
session: self.id.clone(),
|
||||||
|
room: self.room.clone().unwrap(),
|
||||||
|
msg,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ mod routes;
|
||||||
use crate::{actors::chat_server::ChatServer, models::AppState};
|
use crate::{actors::chat_server::ChatServer, models::AppState};
|
||||||
use actix::Actor;
|
use actix::Actor;
|
||||||
use actix_web::{App, HttpServer};
|
use actix_web::{App, HttpServer};
|
||||||
use routes::ws::connect;
|
use routes::connect;
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod chat_server;
|
pub mod server;
|
||||||
pub mod chat_session;
|
pub mod session;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::chat_session::Message;
|
use super::session::Message;
|
||||||
use crate::models::{RoomId, SessionId};
|
use crate::models::{RoomId, SessionId};
|
||||||
use actix::{Message as ActixMessage, Recipient};
|
use actix::{Message as ActixMessage, Recipient};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
|
use actix::Message as ActixMessage;
|
||||||
use derive_more::{Display, Error};
|
use derive_more::{Display, Error};
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(ActixMessage)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
|
pub enum Command {
|
||||||
|
Msg(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display, Error)]
|
#[derive(Debug, Display, Error)]
|
||||||
#[display(fmt = "Invalid command: {}", msg)]
|
#[display(fmt = "Invalid command: {}", msg)]
|
||||||
pub struct CommandError {
|
pub struct CommandError {
|
||||||
msg: &'static str,
|
msg: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Command {
|
|
||||||
Msg(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: IMPLEMENT MORE COMMANDS
|
// TODO: IMPLEMENT MORE COMMANDS
|
||||||
impl FromStr for Command {
|
impl FromStr for Command {
|
||||||
type Err = CommandError;
|
type Err = CommandError;
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub mod command;
|
||||||
|
pub mod wsmessage;
|
||||||
use actix::Message as ActixMessage;
|
use actix::Message as ActixMessage;
|
||||||
|
|
||||||
#[derive(ActixMessage)]
|
#[derive(ActixMessage)]
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
|
use actix::Message as ActixMessage;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::convert::Into;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, ActixMessage)]
|
||||||
|
#[rtype(result = "()")]
|
||||||
pub struct WsMessage {
|
pub struct WsMessage {
|
||||||
pub ty: MessageType,
|
pub ty: MessageType,
|
||||||
pub data: Option<String>,
|
pub data: Option<String>,
|
||||||
|
|
@ -13,6 +16,13 @@ impl WsMessage {
|
||||||
data: Some(msg),
|
data: Some(msg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn info(msg: String) -> Self {
|
||||||
|
WsMessage {
|
||||||
|
ty: MessageType::Info,
|
||||||
|
data: Some(msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
|
@ -22,10 +32,11 @@ pub enum MessageType {
|
||||||
Leave,
|
Leave,
|
||||||
Msg,
|
Msg,
|
||||||
Err,
|
Err,
|
||||||
|
Info,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<String> for WsMessage {
|
impl Into<String> for WsMessage {
|
||||||
fn into(self) -> String {
|
fn into(self) -> String {
|
||||||
serde_json::to_string(&self).unwrap()
|
serde_json::to_string(&self).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
pub mod commands;
|
|
||||||
pub mod ws;
|
|
||||||
use crate::actors::chat_server::ChatServer;
|
use crate::actors::chat_server::ChatServer;
|
||||||
use actix::Addr;
|
use actix::Addr;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
pub mod ws;
|
use crate::{actors::chat_session::WsChatSession, models::AppState};
|
||||||
|
use actix_web::{get, web, HttpRequest, Responder};
|
||||||
|
use actix_web_actors::ws;
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
pub async fn connect(
|
||||||
|
req: HttpRequest,
|
||||||
|
stream: web::Payload,
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
) -> impl Responder {
|
||||||
|
let chat = state.chat.clone();
|
||||||
|
ws::start(WsChatSession::new(chat), &req, stream)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
use crate::{actors::chat_session::WsChatSession, models::AppState};
|
|
||||||
use actix_web::{get, web, HttpRequest, Responder};
|
|
||||||
use actix_web_actors::ws;
|
|
||||||
|
|
||||||
#[get("/ws")]
|
|
||||||
pub async fn connect(
|
|
||||||
req: HttpRequest,
|
|
||||||
stream: web::Payload,
|
|
||||||
state: web::Data<AppState>,
|
|
||||||
) -> impl Responder {
|
|
||||||
let chat = state.chat.clone();
|
|
||||||
ws::start(WsChatSession::new(chat), &req, stream)
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue