receive revision from client

This commit is contained in:
appflowy
2021-09-23 17:50:28 +08:00
parent d4b020b64f
commit 3e3e10b316
21 changed files with 320 additions and 149 deletions

View File

@ -16,6 +16,7 @@ use crate::{
service::{
app::router as app,
doc::router as doc,
make_ws_biz_handlers,
user::router as user,
view::router as view,
workspace::router as workspace,
@ -23,6 +24,7 @@ use crate::{
ws::WSServer,
},
};
use flowy_ws::WsSource;
pub struct Application {
port: u16,
@ -53,7 +55,7 @@ pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io
let pg_pool = Data::new(pg_pool);
let domain = domain();
let secret: String = secret();
let ws_biz_handlers = Data::new(make_ws_biz_handlers());
actix_rt::spawn(period_check(pg_pool.clone()));
let server = HttpServer::new(move || {
@ -67,6 +69,7 @@ pub fn run(listener: TcpListener, app_ctx: AppContext) -> Result<Server, std::io
.service(user_scope())
.app_data(ws_server.clone())
.app_data(pg_pool.clone())
.app_data(ws_biz_handlers.clone())
})
.listen(listener)?
.run();

View File

@ -1,6 +1,7 @@
mod doc;
pub mod router;
mod sql_builder;
pub mod ws_handler;
pub(crate) use doc::*;
pub use router::*;

View File

@ -0,0 +1,17 @@
use crate::service::{util::parse_from_bytes, ws::WsBizHandler};
use bytes::Bytes;
use flowy_document::protobuf::Revision;
use protobuf::Message;
pub struct DocWsBizHandler {}
impl DocWsBizHandler {
pub fn new() -> Self { Self {} }
}
impl WsBizHandler for DocWsBizHandler {
fn receive_data(&self, data: Bytes) {
let revision: Revision = parse_from_bytes(&data).unwrap();
log::warn!("{:?}", revision);
}
}

View File

@ -1,3 +1,8 @@
use crate::service::{doc::ws_handler::DocWsBizHandler, ws::WsBizHandlers};
use flowy_ws::WsSource;
use std::sync::Arc;
use tokio::sync::RwLock;
pub mod app;
pub mod doc;
pub(crate) mod log;
@ -6,3 +11,16 @@ pub(crate) mod util;
pub mod view;
pub mod workspace;
pub mod ws;
pub fn make_ws_biz_handlers() -> WsBizHandlers {
let mut ws_biz_handlers = WsBizHandlers::new();
// doc
let doc_biz_handler = DocWsBizHandler::new();
ws_biz_handlers.register(WsSource::Doc, wrap(doc_biz_handler));
//
ws_biz_handlers
}
fn wrap<T>(val: T) -> Arc<RwLock<T>> { Arc::new(RwLock::new(val)) }

View File

@ -0,0 +1,34 @@
use bytes::Bytes;
use dashmap::{mapref::one::Ref, DashMap};
use flowy_ws::WsSource;
use std::sync::Arc;
use tokio::sync::RwLock;
pub trait WsBizHandler: Send + Sync {
fn receive_data(&self, data: Bytes);
}
pub type BizHandler = Arc<RwLock<dyn WsBizHandler>>;
pub struct WsBizHandlers {
inner: DashMap<WsSource, BizHandler>,
}
impl WsBizHandlers {
pub fn new() -> Self {
Self {
inner: DashMap::new(),
}
}
pub fn register(&self, source: WsSource, handler: BizHandler) {
self.inner.insert(source, handler);
}
pub fn get(&self, source: &WsSource) -> Option<BizHandler> {
match self.inner.get(source) {
None => None,
Some(handler) => Some(handler.clone()),
}
}
}

View File

@ -1,7 +1,9 @@
pub use biz_handler::*;
pub use entities::message::*;
pub use ws_client::*;
pub use ws_server::*;
mod biz_handler;
pub(crate) mod entities;
pub mod router;
mod ws_client;

View File

@ -1,4 +1,4 @@
use crate::service::ws::{WSClient, WSServer};
use crate::service::ws::{WSClient, WSServer, WsBizHandlers};
use actix::Addr;
use crate::service::user::LoggedUser;
@ -17,10 +17,11 @@ pub async fn establish_ws_connection(
payload: Payload,
token: Path<String>,
server: Data<Addr<WSServer>>,
biz_handlers: Data<WsBizHandlers>,
) -> Result<HttpResponse, Error> {
match LoggedUser::from_token(token.clone()) {
Ok(user) => {
let client = WSClient::new(&user.user_id, server.get_ref().clone());
let client = WSClient::new(&user.user_id, server.get_ref().clone(), biz_handlers);
let result = ws::start(client, &request, payload);
match result {
Ok(response) => Ok(response.into()),

View File

@ -5,41 +5,36 @@ use crate::{
ClientMessage,
MessageData,
WSServer,
WsBizHandler,
WsBizHandlers,
},
};
use actix::*;
use actix::{fut::wrap_future, *};
use actix_web::web::Data;
use actix_web_actors::{ws, ws::Message::Text};
use std::time::Instant;
use bytes::Bytes;
use flowy_ws::{WsMessage, WsSource};
use std::{convert::TryFrom, pin::Pin, time::Instant};
use tokio::sync::RwLock;
// Frontend │ Backend
//
// │
// ┌──────────┐ WsMessage ┌───────────┐ ClientMessage ┌──────────┐
// │ user 1 │─────────┼────▶│ws_client_1│──────────────────▶│ws_server │
// └──────────┘ └───────────┘ └──────────┘
// │ │
// WsMessage ▼
// ┌──────────┐ │ ┌───────────┐ ClientMessage Group
// │ user 2 │◀──────────────│ws_client_2│◀───────┐ ┌───────────────┐
// └──────────┘ │ └───────────┘ │ │ ws_user_1 │
// │ │ │
// │ └────────│ ws_user_2 │
// ┌──────────┐ ┌───────────┐ │ │
// │ user 3 │─────────┼────▶│ws_client_3│ └───────────────┘
// └──────────┘ └───────────┘
// │
pub struct WSClient {
session_id: SessionId,
server: Addr<WSServer>,
biz_handlers: Data<WsBizHandlers>,
hb: Instant,
}
impl WSClient {
pub fn new<T: Into<SessionId>>(session_id: T, server: Addr<WSServer>) -> Self {
pub fn new<T: Into<SessionId>>(
session_id: T,
server: Addr<WSServer>,
biz_handlers: Data<WsBizHandlers>,
) -> Self {
Self {
session_id: session_id.into(),
hb: Instant::now(),
server,
biz_handlers,
hb: Instant::now(),
}
}
@ -62,36 +57,16 @@ impl WSClient {
}
}
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
async fn handle_binary_message(biz_handlers: Data<WsBizHandlers>, bytes: Bytes) {
let message: WsMessage = WsMessage::try_from(bytes).unwrap();
match biz_handlers.get(&message.source) {
None => {
log::error!("Can't find the handler for {:?}", message.source);
},
Some(handler) => handler
.write()
.await
.receive_data(Bytes::from(message.data)),
}
}
@ -106,9 +81,10 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSClient {
// log::debug!("Receive {} pong {:?}", &self.session_id, &msg);
self.hb = Instant::now();
},
Ok(ws::Message::Binary(bin)) => {
Ok(ws::Message::Binary(bytes)) => {
log::debug!(" Receive {} binary", &self.session_id);
self.send(MessageData::Binary(bin));
let biz_handlers = self.biz_handlers.clone();
ctx.spawn(wrap_future(handle_binary_message(biz_handlers, bytes)));
},
Ok(Text(_)) => {
log::warn!("Receive unexpected text message");
@ -145,3 +121,36 @@ impl Handler<ClientMessage> for WSClient {
}
}
}
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
}
}