mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
receive revision from client
This commit is contained in:
@ -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();
|
||||
|
@ -1,6 +1,7 @@
|
||||
mod doc;
|
||||
pub mod router;
|
||||
mod sql_builder;
|
||||
pub mod ws_handler;
|
||||
|
||||
pub(crate) use doc::*;
|
||||
pub use router::*;
|
||||
|
17
backend/src/service/doc/ws_handler.rs
Normal file
17
backend/src/service/doc/ws_handler.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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)) }
|
||||
|
34
backend/src/service/ws/biz_handler.rs
Normal file
34
backend/src/service/ws/biz_handler.rs
Normal 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()),
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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()),
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user