AppFlowy/backend/src/service/ws/ws_client.rs

153 lines
4.5 KiB
Rust
Raw Normal View History

2021-09-10 16:22:38 +08:00
use crate::{
config::{HEARTBEAT_INTERVAL, PING_TIMEOUT},
2021-09-23 16:10:24 +08:00
service::ws::{
2021-09-10 16:22:38 +08:00
entities::{Connect, Disconnect, SessionId},
ClientMessage,
MessageData,
WSServer,
2021-09-23 17:50:28 +08:00
WsBizHandler,
WsBizHandlers,
2021-09-10 16:22:38 +08:00
},
};
use actix::*;
2021-09-23 17:50:28 +08:00
use actix_web::web::Data;
2021-09-19 23:21:10 +08:00
use actix_web_actors::{ws, ws::Message::Text};
2021-09-23 17:50:28 +08:00
use bytes::Bytes;
use flowy_ws::WsMessage;
use std::{convert::TryFrom, time::Instant};
2021-08-19 08:36:30 +08:00
2021-08-19 14:08:24 +08:00
pub struct WSClient {
2021-09-19 23:21:10 +08:00
session_id: SessionId,
2021-08-19 08:36:30 +08:00
server: Addr<WSServer>,
2021-09-23 17:50:28 +08:00
biz_handlers: Data<WsBizHandlers>,
2021-08-19 08:36:30 +08:00
hb: Instant,
}
2021-08-19 14:08:24 +08:00
impl WSClient {
2021-09-23 17:50:28 +08:00
pub fn new<T: Into<SessionId>>(
session_id: T,
server: Addr<WSServer>,
biz_handlers: Data<WsBizHandlers>,
) -> Self {
2021-08-19 08:36:30 +08:00
Self {
2021-09-19 23:21:10 +08:00
session_id: session_id.into(),
2021-08-19 08:36:30 +08:00
server,
2021-09-23 17:50:28 +08:00
biz_handlers,
hb: Instant::now(),
2021-08-19 08:36:30 +08:00
}
}
fn hb(&self, ctx: &mut ws::WebsocketContext<Self>) {
2021-09-19 23:21:10 +08:00
ctx.run_interval(HEARTBEAT_INTERVAL, |client, ctx| {
if Instant::now().duration_since(client.hb) > PING_TIMEOUT {
client.server.do_send(Disconnect {
sid: client.session_id.clone(),
2021-08-19 08:36:30 +08:00
});
ctx.stop();
2021-09-19 23:21:10 +08:00
} else {
ctx.ping(b"");
2021-08-19 08:36:30 +08:00
}
});
}
2021-08-19 14:08:24 +08:00
fn send(&self, data: MessageData) {
2021-09-19 23:21:10 +08:00
let msg = ClientMessage::new(self.session_id.clone(), data);
2021-08-19 14:08:24 +08:00
self.server.do_send(msg);
}
fn handle_binary_message(&self, bytes: Bytes) {
// TODO: ok to unwrap?
let message: WsMessage = WsMessage::try_from(bytes).unwrap();
match self.biz_handlers.get(&message.module) {
None => {
log::error!("Can't find the handler for {:?}", message.module);
},
Some(handler) => handler.receive_data(Bytes::from(message.data)),
}
2021-08-19 08:36:30 +08:00
}
}
2021-08-19 14:08:24 +08:00
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSClient {
2021-08-19 08:36:30 +08:00
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
match msg {
Ok(ws::Message::Ping(msg)) => {
self.hb = Instant::now();
ctx.pong(&msg);
},
2021-09-22 14:42:14 +08:00
Ok(ws::Message::Pong(_msg)) => {
// log::debug!("Receive {} pong {:?}", &self.session_id, &msg);
2021-08-19 08:36:30 +08:00
self.hb = Instant::now();
},
2021-09-23 17:50:28 +08:00
Ok(ws::Message::Binary(bytes)) => {
2021-09-19 23:21:10 +08:00
log::debug!(" Receive {} binary", &self.session_id);
self.handle_binary_message(bytes);
2021-08-19 08:36:30 +08:00
},
2021-09-19 23:21:10 +08:00
Ok(Text(_)) => {
log::warn!("Receive unexpected text message");
},
2021-08-19 08:36:30 +08:00
Ok(ws::Message::Close(reason)) => {
2021-09-19 23:21:10 +08:00
self.send(MessageData::Disconnect(self.session_id.clone()));
2021-08-19 08:36:30 +08:00
ctx.close(reason);
ctx.stop();
},
2021-09-19 23:21:10 +08:00
Ok(ws::Message::Continuation(_)) => {},
Ok(ws::Message::Nop) => {},
2021-08-19 08:36:30 +08:00
Err(e) => {
2021-09-19 23:21:10 +08:00
log::error!(
"[{}]: WebSocketStream protocol error {:?}",
self.session_id,
e
);
2021-08-19 08:36:30 +08:00
ctx.stop();
},
}
}
}
2021-08-19 14:08:24 +08:00
impl Handler<ClientMessage> for WSClient {
2021-08-19 08:36:30 +08:00
type Result = ();
2021-08-19 14:08:24 +08:00
fn handle(&mut self, msg: ClientMessage, ctx: &mut Self::Context) {
match msg.data {
MessageData::Binary(binary) => {
2021-08-19 08:36:30 +08:00
ctx.binary(binary);
},
2021-09-19 23:21:10 +08:00
MessageData::Connect(_) => {},
MessageData::Disconnect(_) => {},
2021-08-19 08:36:30 +08:00
}
}
}
2021-09-23 17:50:28 +08:00
impl Actor for WSClient {
type Context = ws::WebsocketContext<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
self.hb(ctx);
let socket = ctx.address().recipient();
let connect = Connect {
socket,
sid: self.session_id.clone(),
};
self.server
.send(connect)
.into_actor(self)
.then(|res, _client, _ctx| {
match res {
Ok(Ok(_)) => log::trace!("Send connect message to server success"),
Ok(Err(e)) => log::error!("Send connect message to server failed: {:?}", e),
Err(e) => log::error!("Send connect message to server failed: {:?}", e),
}
fut::ready(())
})
.wait(ctx);
}
fn stopping(&mut self, _: &mut Self::Context) -> Running {
self.server.do_send(Disconnect {
sid: self.session_id.clone(),
});
Running::Stop
}
}