mirror of
				https://github.com/AppFlowy-IO/AppFlowy.git
				synced 2025-10-31 01:54:37 +00:00 
			
		
		
		
	setup actix-web server
This commit is contained in:
		
							parent
							
								
									48c3436ada
								
							
						
					
					
						commit
						7adb75e85d
					
				| @ -39,7 +39,7 @@ impl RustStreamSender { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn post(observable_subject: ObservableSubject) -> Result<(), String> { | ||||
|     pub fn post(_observable_subject: ObservableSubject) -> Result<(), String> { | ||||
|         #[cfg(feature = "dart")] | ||||
|         match R2F_STREAM_SENDER.read() { | ||||
|             Ok(stream) => stream.inner_post(observable_subject), | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| use crate::{client::DocumentData, errors::OTError}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use serde_json::Error; | ||||
| 
 | ||||
| impl<T: AsRef<str>> DocumentData for T { | ||||
|     fn into_string(self) -> Result<String, OTError> { Ok(self.as_ref().to_string()) } | ||||
|  | ||||
							
								
								
									
										30
									
								
								server/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								server/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| [package] | ||||
| name = "server" | ||||
| version = "0.1.0" | ||||
| edition = "2018" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| actix = "0.10" | ||||
| actix-web = "3" | ||||
| actix-http = "2.2.1" | ||||
| actix-web-actors = "3" | ||||
| actix-codec = "0.3" | ||||
| 
 | ||||
| 
 | ||||
| futures = "0.3.15" | ||||
| bytes = "0.5" | ||||
| toml = "0.5.8" | ||||
| dashmap = "4.0" | ||||
| log = "0.4.14" | ||||
| serde_json = "1.0" | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
| serde_repr = "0.1" | ||||
| 
 | ||||
| [lib] | ||||
| path = "src/lib.rs" | ||||
| 
 | ||||
| [[bin]] | ||||
| name = "flowy_server" | ||||
| path = "src/main.rs" | ||||
							
								
								
									
										18
									
								
								server/rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								server/rustfmt.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| # https://rust-lang.github.io/rustfmt/?version=master&search= | ||||
| max_width = 100 | ||||
| tab_spaces = 4 | ||||
| fn_single_line = true | ||||
| match_block_trailing_comma = true | ||||
| normalize_comments = true | ||||
| wrap_comments = true | ||||
| use_field_init_shorthand = true | ||||
| use_try_shorthand = true | ||||
| normalize_doc_attributes = true | ||||
| report_todo = "Always" | ||||
| report_fixme = "Always" | ||||
| imports_layout = "HorizontalVertical" | ||||
| merge_imports = true | ||||
| reorder_modules = true | ||||
| reorder_imports = true | ||||
| enum_discrim_align_threshold = 20 | ||||
| edition = "2018" | ||||
							
								
								
									
										41
									
								
								server/src/config/config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								server/src/config/config.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| use std::convert::TryFrom; | ||||
| 
 | ||||
| pub struct Config { | ||||
|     pub http_port: u16, | ||||
| } | ||||
| 
 | ||||
| impl Config { | ||||
|     pub fn new() -> Self { Config { http_port: 3030 } } | ||||
| 
 | ||||
|     pub fn server_addr(&self) -> String { format!("0.0.0.0:{}", self.http_port) } | ||||
| } | ||||
| 
 | ||||
| pub enum Environment { | ||||
|     Local, | ||||
|     Production, | ||||
| } | ||||
| 
 | ||||
| impl Environment { | ||||
|     #[allow(dead_code)] | ||||
|     pub fn as_str(&self) -> &'static str { | ||||
|         match self { | ||||
|             Environment::Local => "local", | ||||
|             Environment::Production => "production", | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<String> for Environment { | ||||
|     type Error = String; | ||||
| 
 | ||||
|     fn try_from(s: String) -> Result<Self, Self::Error> { | ||||
|         match s.to_lowercase().as_str() { | ||||
|             "local" => Ok(Self::Local), | ||||
|             "production" => Ok(Self::Production), | ||||
|             other => Err(format!( | ||||
|                 "{} is not a supported environment. Use either `local` or `production`.", | ||||
|                 other | ||||
|             )), | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										4
									
								
								server/src/config/const_define.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								server/src/config/const_define.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| use std::time::Duration; | ||||
| 
 | ||||
| pub const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(8); | ||||
| pub const PING_TIMEOUT: Duration = Duration::from_secs(60); | ||||
							
								
								
									
										5
									
								
								server/src/config/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								server/src/config/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| mod config; | ||||
| mod const_define; | ||||
| 
 | ||||
| pub use config::*; | ||||
| pub use const_define::*; | ||||
							
								
								
									
										19
									
								
								server/src/context.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								server/src/context.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| use crate::{config::Config, ws::WSServer}; | ||||
| use actix::Addr; | ||||
| use std::sync::Arc; | ||||
| 
 | ||||
| pub struct AppContext { | ||||
|     pub config: Arc<Config>, | ||||
|     pub server: Addr<WSServer>, | ||||
| } | ||||
| 
 | ||||
| impl AppContext { | ||||
|     pub fn new(server: Addr<WSServer>) -> Self { | ||||
|         AppContext { | ||||
|             config: Arc::new(Config::new()), | ||||
|             server, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn ws_server(&self) -> Addr<WSServer> { self.server.clone() } | ||||
| } | ||||
							
								
								
									
										3
									
								
								server/src/errors.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								server/src/errors.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| pub struct ServerError {} | ||||
| 
 | ||||
| // pub enum ErrorCode {}
 | ||||
							
								
								
									
										6
									
								
								server/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								server/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| mod config; | ||||
| mod context; | ||||
| mod errors; | ||||
| mod routers; | ||||
| pub mod startup; | ||||
| mod ws; | ||||
							
								
								
									
										10
									
								
								server/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								server/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| use server::startup::{init_app_context, run}; | ||||
| use std::net::TcpListener; | ||||
| 
 | ||||
| #[actix_web::main] | ||||
| async fn main() -> std::io::Result<()> { | ||||
|     let app_ctx = init_app_context().await; | ||||
|     let listener = | ||||
|         TcpListener::bind(app_ctx.config.server_addr()).expect("Failed to bind server address"); | ||||
|     run(app_ctx, listener)?.await | ||||
| } | ||||
							
								
								
									
										3
									
								
								server/src/routers/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								server/src/routers/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| pub(crate) mod ws; | ||||
| 
 | ||||
| pub use ws::*; | ||||
							
								
								
									
										22
									
								
								server/src/routers/ws.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								server/src/routers/ws.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| use crate::ws::{entities::SessionId, WSServer, WSSession}; | ||||
| use actix::Addr; | ||||
| use actix_web::{ | ||||
|     get, | ||||
|     web::{Data, Path, Payload}, | ||||
|     Error, | ||||
|     HttpRequest, | ||||
|     HttpResponse, | ||||
| }; | ||||
| use actix_web_actors::ws; | ||||
| 
 | ||||
| #[get("/{token}")] | ||||
| pub async fn start_connection( | ||||
|     request: HttpRequest, | ||||
|     payload: Payload, | ||||
|     Path(token): Path<String>, | ||||
|     server: Data<Addr<WSServer>>, | ||||
| ) -> Result<HttpResponse, Error> { | ||||
|     let ws = WSSession::new(SessionId::new(token), server.get_ref().clone()); | ||||
|     let response = ws::start(ws, &request, payload)?; | ||||
|     Ok(response.into()) | ||||
| } | ||||
							
								
								
									
										25
									
								
								server/src/startup.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								server/src/startup.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| use crate::{context::AppContext, routers::*, ws::WSServer}; | ||||
| use actix::Actor; | ||||
| use actix_web::{dev::Server, middleware, web, App, HttpServer, Scope}; | ||||
| use std::{net::TcpListener, sync::Arc}; | ||||
| 
 | ||||
| pub fn run(app_ctx: Arc<AppContext>, listener: TcpListener) -> Result<Server, std::io::Error> { | ||||
|     let server = HttpServer::new(move || { | ||||
|         App::new() | ||||
|             .wrap(middleware::Logger::default()) | ||||
|             .data(web::JsonConfig::default().limit(4096)) | ||||
|             .service(ws_scope()) | ||||
|             .data(app_ctx.ws_server()) | ||||
|     }) | ||||
|     .listen(listener)? | ||||
|     .run(); | ||||
|     Ok(server) | ||||
| } | ||||
| 
 | ||||
| fn ws_scope() -> Scope { web::scope("/ws").service(ws::start_connection) } | ||||
| 
 | ||||
| pub async fn init_app_context() -> Arc<AppContext> { | ||||
|     let ws_server = WSServer::new().start(); | ||||
|     let ctx = AppContext::new(ws_server); | ||||
|     Arc::new(ctx) | ||||
| } | ||||
							
								
								
									
										33
									
								
								server/src/ws/entities/connect.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								server/src/ws/entities/connect.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| use crate::{errors::ServerError, ws::Packet}; | ||||
| use actix::{Message, Recipient}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::fmt::Formatter; | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)] | ||||
| pub struct SessionId { | ||||
|     pub id: String, | ||||
| } | ||||
| 
 | ||||
| impl SessionId { | ||||
|     pub fn new(id: String) -> Self { SessionId { id } } | ||||
| } | ||||
| 
 | ||||
| impl std::fmt::Display for SessionId { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||
|         let desc = format!("{}", &self.id); | ||||
|         f.write_str(&desc) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Message, Clone)] | ||||
| #[rtype(result = "Result<(), ServerError>")] | ||||
| pub struct Connect { | ||||
|     pub socket: Recipient<Packet>, | ||||
|     pub sid: SessionId, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Message, Clone)] | ||||
| #[rtype(result = "Result<(), ServerError>")] | ||||
| pub struct Disconnect { | ||||
|     pub sid: SessionId, | ||||
| } | ||||
							
								
								
									
										5
									
								
								server/src/ws/entities/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								server/src/ws/entities/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| pub use connect::*; | ||||
| pub use packet::*; | ||||
| 
 | ||||
| mod connect; | ||||
| pub mod packet; | ||||
							
								
								
									
										37
									
								
								server/src/ws/entities/packet.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								server/src/ws/entities/packet.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| use crate::ws::entities::SessionId; | ||||
| use actix::Message; | ||||
| use bytes::Bytes; | ||||
| use std::fmt::Formatter; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Frame { | ||||
|     Text(String), | ||||
|     Binary(Bytes), | ||||
|     Connect(SessionId), | ||||
|     Disconnect(String), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Message, Clone)] | ||||
| #[rtype(result = "()")] | ||||
| pub struct Packet { | ||||
|     pub sid: SessionId, | ||||
|     pub frame: Frame, | ||||
| } | ||||
| 
 | ||||
| impl Packet { | ||||
|     pub fn new(sid: SessionId, frame: Frame) -> Self { Packet { sid, frame } } | ||||
| } | ||||
| 
 | ||||
| impl std::fmt::Display for Packet { | ||||
|     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||||
|         let content = match &self.frame { | ||||
|             Frame::Text(t) => format!("[Text]: {}", t), | ||||
|             Frame::Binary(_) => "[Binary message]".to_owned(), | ||||
|             Frame::Connect(_) => "Connect".to_owned(), | ||||
|             Frame::Disconnect(_) => "Disconnect".to_owned(), | ||||
|         }; | ||||
| 
 | ||||
|         let desc = format!("{}:{}", &self.sid, content); | ||||
|         f.write_str(&desc) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								server/src/ws/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								server/src/ws/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| pub use entities::packet::*; | ||||
| pub use ws_server::*; | ||||
| pub use ws_session::*; | ||||
| 
 | ||||
| pub(crate) mod entities; | ||||
| mod ws_server; | ||||
| mod ws_session; | ||||
							
								
								
									
										57
									
								
								server/src/ws/ws_server.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								server/src/ws/ws_server.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| use crate::{ | ||||
|     errors::ServerError, | ||||
|     ws::{ | ||||
|         entities::{Connect, Disconnect, SessionId}, | ||||
|         Packet, | ||||
|         WSSession, | ||||
|     }, | ||||
| }; | ||||
| use actix::{Actor, Context, Handler}; | ||||
| use dashmap::DashMap; | ||||
| 
 | ||||
| pub struct WSServer { | ||||
|     session_map: DashMap<SessionId, WSSession>, | ||||
| } | ||||
| 
 | ||||
| impl WSServer { | ||||
|     pub fn new() -> Self { | ||||
|         Self { | ||||
|             session_map: DashMap::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn send(&self, _packet: Packet) { unimplemented!() } | ||||
| } | ||||
| 
 | ||||
| impl Actor for WSServer { | ||||
|     type Context = Context<Self>; | ||||
|     fn started(&mut self, _ctx: &mut Self::Context) {} | ||||
| } | ||||
| 
 | ||||
| impl Handler<Connect> for WSServer { | ||||
|     type Result = Result<(), ServerError>; | ||||
|     fn handle(&mut self, _msg: Connect, _ctx: &mut Context<Self>) -> Self::Result { | ||||
|         unimplemented!() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Handler<Disconnect> for WSServer { | ||||
|     type Result = Result<(), ServerError>; | ||||
|     fn handle(&mut self, _msg: Disconnect, _: &mut Context<Self>) -> Self::Result { | ||||
|         unimplemented!() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Handler<Packet> for WSServer { | ||||
|     type Result = (); | ||||
| 
 | ||||
|     fn handle(&mut self, _packet: Packet, _ctx: &mut Context<Self>) -> Self::Result { | ||||
|         unimplemented!() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl actix::Supervised for WSServer { | ||||
|     fn restarting(&mut self, _ctx: &mut Context<WSServer>) { | ||||
|         log::warn!("restarting"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										163
									
								
								server/src/ws/ws_session.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								server/src/ws/ws_session.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,163 @@ | ||||
| use crate::{ | ||||
|     config::{HEARTBEAT_INTERVAL, PING_TIMEOUT}, | ||||
|     ws::{ | ||||
|         entities::{Connect, Disconnect, SessionId}, | ||||
|         Frame, | ||||
|         Packet, | ||||
|         WSServer, | ||||
|     }, | ||||
| }; | ||||
| use actix::{ | ||||
|     fut, | ||||
|     Actor, | ||||
|     ActorContext, | ||||
|     ActorFuture, | ||||
|     Addr, | ||||
|     AsyncContext, | ||||
|     ContextFutureSpawner, | ||||
|     Handler, | ||||
|     Running, | ||||
|     StreamHandler, | ||||
|     WrapFuture, | ||||
| }; | ||||
| 
 | ||||
| use actix_web_actors::{ws, ws::Message::Text}; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| pub struct WSSession { | ||||
|     sid: SessionId, | ||||
|     server: Addr<WSServer>, | ||||
|     hb: Instant, | ||||
| } | ||||
| 
 | ||||
| impl WSSession { | ||||
|     pub fn new(sid: SessionId, server: Addr<WSServer>) -> Self { | ||||
|         Self { | ||||
|             sid, | ||||
|             hb: Instant::now(), | ||||
|             server, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn hb(&self, ctx: &mut ws::WebsocketContext<Self>) { | ||||
|         ctx.run_interval(HEARTBEAT_INTERVAL, |ws_session, ctx| { | ||||
|             if Instant::now().duration_since(ws_session.hb) > PING_TIMEOUT { | ||||
|                 ws_session.server.do_send(Disconnect { | ||||
|                     sid: ws_session.sid.clone(), | ||||
|                 }); | ||||
|                 ctx.stop(); | ||||
|                 return; | ||||
|             } | ||||
|             ctx.ping(b""); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     fn connect(&self, ctx: &mut ws::WebsocketContext<Self>) { | ||||
|         self.hb(ctx); | ||||
|         let socket = ctx.address().recipient(); | ||||
|         let connect = Connect { | ||||
|             socket, | ||||
|             sid: self.sid.clone(), | ||||
|         }; | ||||
|         self.server | ||||
|             .send(connect) | ||||
|             .into_actor(self) | ||||
|             .then(|res, _ws_session, _ctx| { | ||||
|                 match res { | ||||
|                     Ok(Ok(_)) => {}, | ||||
|                     Ok(Err(_e)) => { | ||||
|                         unimplemented!() | ||||
|                     }, | ||||
|                     Err(_e) => unimplemented!(), | ||||
|                 } | ||||
|                 fut::ready(()) | ||||
|             }) | ||||
|             .wait(ctx); | ||||
|     } | ||||
| 
 | ||||
|     fn send(&self, frame: Frame) { | ||||
|         let msg = Packet::new(self.sid.clone(), frame); | ||||
|         self.server.do_send(msg); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Actor for WSSession { | ||||
|     type Context = ws::WebsocketContext<Self>; | ||||
| 
 | ||||
|     fn started(&mut self, ctx: &mut Self::Context) { self.connect(ctx); } | ||||
| 
 | ||||
|     fn stopping(&mut self, _: &mut Self::Context) -> Running { | ||||
|         self.server.do_send(Disconnect { | ||||
|             sid: self.sid.clone(), | ||||
|         }); | ||||
| 
 | ||||
|         Running::Stop | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSSession { | ||||
|     fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) { | ||||
|         match msg { | ||||
|             Ok(ws::Message::Ping(msg)) => { | ||||
|                 log::debug!("Receive {} ping {:?}", &self.sid, &msg); | ||||
|                 self.hb = Instant::now(); | ||||
|                 ctx.pong(&msg); | ||||
|             }, | ||||
|             Ok(ws::Message::Pong(msg)) => { | ||||
|                 log::debug!("Receive {} pong {:?}", &self.sid, &msg); | ||||
|                 self.send(Frame::Connect(self.sid.clone())); | ||||
|                 self.hb = Instant::now(); | ||||
|             }, | ||||
|             Ok(ws::Message::Binary(bin)) => { | ||||
|                 log::debug!(" Receive {} binary", &self.sid); | ||||
|                 self.send(Frame::Binary(bin)); | ||||
|             }, | ||||
|             Ok(ws::Message::Close(reason)) => { | ||||
|                 log::debug!("Receive {} close {:?}", &self.sid, &reason); | ||||
|                 ctx.close(reason); | ||||
|                 ctx.stop(); | ||||
|             }, | ||||
|             Ok(ws::Message::Continuation(c)) => { | ||||
|                 log::debug!("Receive {} continues message {:?}", &self.sid, &c); | ||||
|             }, | ||||
|             Ok(ws::Message::Nop) => { | ||||
|                 log::debug!("Receive Nop message"); | ||||
|             }, | ||||
|             Ok(Text(s)) => { | ||||
|                 log::debug!("Receive {} text {:?}", &self.sid, &s); | ||||
|                 self.send(Frame::Text(s)); | ||||
|             }, | ||||
| 
 | ||||
|             Err(e) => { | ||||
|                 let msg = format!("{} error: {:?}", &self.sid, e); | ||||
|                 ctx.text(&msg); | ||||
|                 log::error!("stream {}", msg); | ||||
|                 ctx.stop(); | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Handler<Packet> for WSSession { | ||||
|     type Result = (); | ||||
| 
 | ||||
|     fn handle(&mut self, msg: Packet, ctx: &mut Self::Context) { | ||||
|         match msg.frame { | ||||
|             Frame::Text(text) => { | ||||
|                 ctx.text(text); | ||||
|             }, | ||||
|             Frame::Binary(binary) => { | ||||
|                 ctx.binary(binary); | ||||
|             }, | ||||
|             Frame::Connect(sid) => { | ||||
|                 let connect_msg = format!("{} connect", &sid); | ||||
|                 ctx.text(connect_msg); | ||||
|             }, | ||||
|             Frame::Disconnect(text) => { | ||||
|                 log::debug!("Session start disconnecting {}", self.sid); | ||||
|                 ctx.text(text); | ||||
|                 ctx.stop(); | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 appflowy
						appflowy