module as service

This commit is contained in:
appflowy 2021-06-27 22:07:33 +08:00
parent 331115aa63
commit 6d2d24baf7
10 changed files with 195 additions and 78 deletions

View File

@ -20,7 +20,16 @@ env_logger = "0.8"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serde_with = "1.9.4" serde_with = "1.9.4"
thread-id = "3.3.0"
#optional crate
allo-isolate = {version = "^0.1", features = ["catch-unwind",], optional = true}
byteorder = {version = "1.3.4", optional = true}
ffi-support = {version = "0.4.2", optional = true}
[dev-dependencies] [dev-dependencies]
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
futures-util = "0.3.15" futures-util = "0.3.15"
[features]
dart_ffi = ["ffi-support", "allo-isolate", "byteorder"]

View File

@ -0,0 +1,34 @@
use crate::{response::EventResponse, rt::SystemCommand};
use futures_core::ready;
use std::{future::Future, task::Context};
use tokio::{
macros::support::{Pin, Poll},
sync::{mpsc::UnboundedReceiver, oneshot},
};
#[no_mangle]
pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {}
#[no_mangle]
pub extern "C" fn free_rust(ptr: *mut u8, length: u32) { reclaim_rust(ptr, length) }
#[no_mangle]
pub extern "C" fn init_stream(port: i64) -> i32 { return 0; }
struct SystemFFI {
resp_rx: UnboundedReceiver<EventResponse>,
}
impl Future for SystemFFI {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match ready!(Pin::new(&mut self.resp_rx).poll_recv(cx)) {
None => return Poll::Ready(()),
Some(resp) => {
log::trace!("Response: {:?}", resp);
},
}
}
}
}

View File

@ -0,0 +1,2 @@
#[cfg(feature = "dart_ffi")]
mod ffi;

View File

@ -9,6 +9,9 @@ mod rt;
mod service; mod service;
mod util; mod util;
#[cfg(feature = "dart_ffi")]
mod dart_ffi;
pub mod prelude { pub mod prelude {
pub use crate::{error::*, module::*, request::*, response::*, rt::*}; pub use crate::{error::*, module::*, request::*, response::*, rt::*};
} }

View File

@ -8,8 +8,10 @@ use crate::{
}; };
use crate::{ use crate::{
error::InternalError,
request::{payload::Payload, EventRequest}, request::{payload::Payload, EventRequest},
response::EventResponse, response::{EventResponse, EventResponseBuilder},
rt::SystemCommand,
service::{factory, BoxServiceFactory, HandlerService}, service::{factory, BoxServiceFactory, HandlerService},
}; };
use futures_core::{future::LocalBoxFuture, ready}; use futures_core::{future::LocalBoxFuture, ready};
@ -18,6 +20,7 @@ use std::{
collections::HashMap, collections::HashMap,
future::Future, future::Future,
pin::Pin, pin::Pin,
rc::Rc,
task::{Context, Poll}, task::{Context, Poll},
}; };
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
@ -28,22 +31,22 @@ pub type EventServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResp
pub struct Module { pub struct Module {
name: String, name: String,
data: DataContainer, data: DataContainer,
service_map: HashMap<Event, EventServiceFactory>, service_map: Rc<HashMap<Event, EventServiceFactory>>,
req_tx: UnboundedSender<EventRequest>, req_tx: UnboundedSender<EventRequest>,
req_rx: UnboundedReceiver<EventRequest>, req_rx: UnboundedReceiver<EventRequest>,
resp_tx: UnboundedSender<EventResponse>, sys_tx: UnboundedSender<SystemCommand>,
} }
impl Module { impl Module {
pub fn new(resp_tx: UnboundedSender<EventResponse>) -> Self { pub fn new(sys_tx: UnboundedSender<SystemCommand>) -> Self {
let (req_tx, req_rx) = unbounded_channel::<EventRequest>(); let (req_tx, req_rx) = unbounded_channel::<EventRequest>();
Self { Self {
name: "".to_owned(), name: "".to_owned(),
data: DataContainer::new(), data: DataContainer::new(),
service_map: HashMap::new(), service_map: Rc::new(HashMap::new()),
req_tx, req_tx,
req_rx, req_rx,
resp_tx, sys_tx,
} }
} }
@ -68,14 +71,16 @@ impl Module {
log::error!("Duplicate Event: {}", &event); log::error!("Duplicate Event: {}", &event);
} }
self.service_map.insert(event, factory(HandlerService::new(handler))); Rc::get_mut(&mut self.service_map)
.unwrap()
.insert(event, factory(HandlerService::new(handler)));
self self
} }
pub fn req_tx(&self) -> UnboundedSender<EventRequest> { self.req_tx.clone() } pub fn req_tx(&self) -> UnboundedSender<EventRequest> { self.req_tx.clone() }
pub fn handle(&self, request: EventRequest) { pub fn handle(&self, request: EventRequest) {
log::trace!("Module: {} receive request: {:?}", self.name, request); log::debug!("Module: {} receive request: {:?}", self.name, request);
match self.req_tx.send(request) { match self.req_tx.send(request) {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
@ -98,30 +103,72 @@ impl Future for Module {
loop { loop {
match ready!(Pin::new(&mut self.req_rx).poll_recv(cx)) { match ready!(Pin::new(&mut self.req_rx).poll_recv(cx)) {
None => return Poll::Ready(()), None => return Poll::Ready(()),
Some(request) => match self.service_map.get(request.get_event()) { Some(request) => {
Some(factory) => { let mut service = self.new_service(request.get_id().to_string());
let fut = ModuleServiceFuture { if let Ok(service) = ready!(Pin::new(&mut service).poll(cx)) {
request, log::trace!("Spawn module service for request {}", request.get_id());
fut: factory.new_service(()),
};
let resp_tx = self.resp_tx.clone();
tokio::task::spawn_local(async move { tokio::task::spawn_local(async move {
let resp = fut.await.unwrap_or_else(|_e| panic!()); let _ = service.call(request).await;
if let Err(e) = resp_tx.send(resp) {
log::error!("{:?}", e);
}
}); });
}, }
None => {
log::error!("Event: {} handler not found", request.get_event());
},
}, },
} }
} }
} }
} }
impl ServiceFactory<EventRequest> for Module {
type Response = ();
type Error = SystemError;
type Service = BoxService<EventRequest, Self::Response, Self::Error>;
type Config = String;
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::Error>>;
fn new_service(&self, cfg: Self::Config) -> Self::Future {
log::trace!("Create module service for request {}", cfg);
let sys_tx = self.sys_tx.clone();
let service_map = self.service_map.clone();
Box::pin(async move {
let service = ModuleService { service_map, sys_tx };
let module_service = Box::new(service) as Self::Service;
Ok(module_service)
})
}
}
pub struct ModuleService {
service_map: Rc<HashMap<Event, EventServiceFactory>>,
sys_tx: UnboundedSender<SystemCommand>,
}
impl Service<EventRequest> for ModuleService {
type Response = ();
type Error = SystemError;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
fn call(&self, request: EventRequest) -> Self::Future {
log::trace!("Call module service for request {}", request.get_id());
match self.service_map.get(request.get_event()) {
Some(factory) => {
let fut = ModuleServiceFuture {
request,
fut: factory.new_service(()),
};
let sys_tx = self.sys_tx.clone();
Box::pin(async move {
let resp = fut.await.unwrap_or_else(|e| e.into());
sys_tx.send(SystemCommand::EventResponse(resp));
Ok(())
})
},
None => Box::pin(async { Err(InternalError::new("".to_string()).into()) }),
}
}
}
type BoxModuleService = BoxService<ServiceRequest, ServiceResponse, SystemError>; type BoxModuleService = BoxService<ServiceRequest, ServiceResponse, SystemError>;
#[pin_project] #[pin_project]
pub struct ModuleServiceFuture { pub struct ModuleServiceFuture {
request: EventRequest, request: EventRequest,
@ -136,7 +183,7 @@ impl Future for ModuleServiceFuture {
loop { loop {
let service = ready!(self.as_mut().project().fut.poll(cx))?; let service = ready!(self.as_mut().project().fut.poll(cx))?;
let req = ServiceRequest::new(self.as_mut().request.clone(), Payload::None); let req = ServiceRequest::new(self.as_mut().request.clone(), Payload::None);
log::trace!("Call service to handle request {:?}", self.request); log::debug!("Call service to handle request {:?}", self.request);
let (_, resp) = ready!(Pin::new(&mut service.call(req)).poll(cx))?.into_parts(); let (_, resp) = ready!(Pin::new(&mut service.call(req)).poll(cx))?.into_parts();
return Poll::Ready(Ok(resp)); return Poll::Ready(Ok(resp));
} }
@ -149,24 +196,22 @@ mod tests {
use crate::rt::Runtime; use crate::rt::Runtime;
use futures_util::{future, pin_mut}; use futures_util::{future, pin_mut};
use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::unbounded_channel;
pub async fn hello_service() -> String { "hello".to_string() } pub async fn hello_service() -> String { "hello".to_string() }
#[test] #[test]
fn test() { fn test() {
let mut runtime = Runtime::new().unwrap(); let mut runtime = Runtime::new().unwrap();
runtime.block_on(async { runtime.block_on(async {
let (resp_tx, mut resp_rx) = unbounded_channel::<EventResponse>(); let (sys_tx, mut sys_rx) = unbounded_channel::<SystemCommand>();
let event = "hello".to_string(); let event = "hello".to_string();
let mut module = Module::new(resp_tx).event(event.clone(), hello_service); let mut module = Module::new(sys_tx).event(event.clone(), hello_service);
let req_tx = module.req_tx(); let req_tx = module.req_tx();
let mut event = async move { let mut event = async move {
let request = EventRequest::new(event.clone()); let request = EventRequest::new(event.clone());
req_tx.send(request).unwrap(); req_tx.send(request).unwrap();
match resp_rx.recv().await { match sys_rx.recv().await {
Some(resp) => { Some(cmd) => {
log::info!("{}", resp); log::info!("{:?}", cmd);
}, },
None => panic!(""), None => panic!(""),
} }

View File

@ -23,6 +23,7 @@ impl EventRequest {
impl EventRequest { impl EventRequest {
pub fn get_event(&self) -> &str { &self.event } pub fn get_event(&self) -> &str { &self.event }
pub fn get_id(&self) -> &str { &self.id }
} }
pub trait FromRequest: Sized { pub trait FromRequest: Sized {

View File

@ -1,4 +1,5 @@
use std::{future::Future, io}; use std::{future::Future, io, thread};
use thread_id;
use tokio::{runtime, task::LocalSet}; use tokio::{runtime, task::LocalSet};
#[derive(Debug)] #[derive(Debug)]
@ -9,7 +10,25 @@ pub struct Runtime {
impl Runtime { impl Runtime {
pub fn new() -> io::Result<Runtime> { pub fn new() -> io::Result<Runtime> {
let rt = runtime::Builder::new_multi_thread().enable_io().enable_time().build()?; let rt = runtime::Builder::new_multi_thread()
.thread_name("flowy-sys")
.enable_io()
.enable_time()
.on_thread_start(move || {
log::trace!(
"{:?} thread started: thread_id= {}",
thread::current(),
thread_id::get()
);
})
.on_thread_stop(move || {
log::trace!(
"{:?} thread stopping: thread_id= {}",
thread::current(),
thread_id::get(),
);
})
.build()?;
Ok(Runtime { Ok(Runtime {
rt, rt,

View File

@ -20,8 +20,10 @@ thread_local!(
static CURRENT: RefCell<Option<Arc<FlowySystem>>> = RefCell::new(None); static CURRENT: RefCell<Option<Arc<FlowySystem>>> = RefCell::new(None);
); );
enum SystemCommand { #[derive(Debug)]
pub enum SystemCommand {
Exit(i8), Exit(i8),
EventResponse(EventResponse),
} }
pub struct FlowySystem { pub struct FlowySystem {
@ -30,28 +32,26 @@ pub struct FlowySystem {
} }
impl FlowySystem { impl FlowySystem {
pub fn construct<F>(module_factory: F) -> SystemRunner pub fn construct<F>(module_factory: F, response_tx: Option<UnboundedSender<EventResponse>>) -> SystemRunner
where where
F: FnOnce(UnboundedSender<EventResponse>) -> Vec<Module>, F: FnOnce(UnboundedSender<SystemCommand>) -> Vec<Module>,
{ {
let runtime = Runtime::new().unwrap(); let runtime = Runtime::new().unwrap();
let (resp_tx, resp_rx) = unbounded_channel::<EventResponse>();
let (sys_tx, sys_rx) = unbounded_channel::<SystemCommand>(); let (sys_tx, sys_rx) = unbounded_channel::<SystemCommand>();
let (stop_tx, stop_rx) = oneshot::channel(); let (stop_tx, stop_rx) = oneshot::channel();
runtime.spawn(SystemFFI { resp_rx });
runtime.spawn(SystemController { runtime.spawn(SystemController {
stop_tx: Some(stop_tx), stop_tx: Some(stop_tx),
sys_rx, sys_rx,
response_tx,
}); });
let mut system = Self { let mut system = Self {
sys_tx, sys_tx: sys_tx.clone(),
forward_map: HashMap::default(), forward_map: HashMap::default(),
}; };
let factory = module_factory(resp_tx.clone()); let factory = module_factory(sys_tx.clone());
factory.into_iter().for_each(|m| { factory.into_iter().for_each(|m| {
system.forward_map.extend(m.forward_map()); system.forward_map.extend(m.forward_map());
runtime.spawn(m); runtime.spawn(m);
@ -63,11 +63,18 @@ impl FlowySystem {
} }
pub fn sink(&self, event: Event, request: EventRequest) -> Result<(), SystemError> { pub fn sink(&self, event: Event, request: EventRequest) -> Result<(), SystemError> {
log::trace!("Sink event: {}", event); log::debug!("Sink event: {}", event);
let _ = self.forward_map.get(&event)?.send(request)?; let _ = self.forward_map.get(&event)?.send(request)?;
Ok(()) Ok(())
} }
pub fn request_tx(&self, event: Event) -> Option<UnboundedSender<EventRequest>> {
match self.forward_map.get(&event) {
Some(tx) => Some(tx.clone()),
None => None,
}
}
pub fn stop(&self) { pub fn stop(&self) {
match self.sys_tx.send(SystemCommand::Exit(0)) { match self.sys_tx.send(SystemCommand::Exit(0)) {
Ok(_) => {}, Ok(_) => {},
@ -92,27 +99,10 @@ impl FlowySystem {
} }
} }
struct SystemFFI {
resp_rx: UnboundedReceiver<EventResponse>,
}
impl Future for SystemFFI {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match ready!(Pin::new(&mut self.resp_rx).poll_recv(cx)) {
None => return Poll::Ready(()),
Some(resp) => {
log::trace!("Response: {:?}", resp);
},
}
}
}
}
struct SystemController { struct SystemController {
stop_tx: Option<oneshot::Sender<i8>>, stop_tx: Option<oneshot::Sender<i8>>,
sys_rx: UnboundedReceiver<SystemCommand>, sys_rx: UnboundedReceiver<SystemCommand>,
response_tx: Option<UnboundedSender<EventResponse>>,
} }
impl Future for SystemController { impl Future for SystemController {
@ -127,6 +117,17 @@ impl Future for SystemController {
let _ = tx.send(code); let _ = tx.send(code);
} }
}, },
SystemCommand::EventResponse(resp) => {
log::debug!("Response: {:?}", resp);
if let Some(tx) = &self.response_tx {
match tx.send(resp) {
Ok(_) => {},
Err(e) => {
log::error!("Response tx send fail: {:?}", e);
},
}
}
},
}, },
} }
} }

View File

@ -13,6 +13,17 @@ where
BoxServiceFactory(Box::new(FactoryWrapper(factory))) BoxServiceFactory(Box::new(FactoryWrapper(factory)))
} }
type Inner<Cfg, Req, Res, Err> = Box<
dyn ServiceFactory<
Req,
Config = Cfg,
Response = Res,
Error = Err,
Service = BoxService<Req, Res, Err>,
Future = LocalBoxFuture<'static, Result<BoxService<Req, Res, Err>, Err>>,
>,
>;
pub struct BoxServiceFactory<Cfg, Req, Res, Err>(Inner<Cfg, Req, Res, Err>); pub struct BoxServiceFactory<Cfg, Req, Res, Err>(Inner<Cfg, Req, Res, Err>);
impl<Cfg, Req, Res, Err> ServiceFactory<Req> for BoxServiceFactory<Cfg, Req, Res, Err> impl<Cfg, Req, Res, Err> ServiceFactory<Req> for BoxServiceFactory<Cfg, Req, Res, Err>
where where
@ -29,17 +40,6 @@ where
fn new_service(&self, cfg: Cfg) -> Self::Future { self.0.new_service(cfg) } fn new_service(&self, cfg: Cfg) -> Self::Future { self.0.new_service(cfg) }
} }
type Inner<Cfg, Req, Res, Err> = Box<
dyn ServiceFactory<
Req,
Config = Cfg,
Response = Res,
Error = Err,
Service = BoxService<Req, Res, Err>,
Future = LocalBoxFuture<'static, Result<BoxService<Req, Res, Err>, Err>>,
>,
>;
pub type BoxService<Req, Res, Err> = pub type BoxService<Req, Res, Err> =
Box<dyn Service<Req, Response = Res, Error = Err, Future = LocalBoxFuture<'static, Result<Res, Err>>>>; Box<dyn Service<Req, Response = Res, Error = Err, Future = LocalBoxFuture<'static, Result<Res, Err>>>>;

View File

@ -12,12 +12,15 @@ fn test() {
let no_params_command = "no params".to_string(); let no_params_command = "no params".to_string();
let one_params_command = "one params".to_string(); let one_params_command = "one params".to_string();
let two_params_command = "two params".to_string(); let two_params_command = "two params".to_string();
FlowySystem::construct(|tx| { FlowySystem::construct(
vec![Module::new(tx.clone()) |tx| {
.event(no_params_command.clone(), no_params) vec![Module::new(tx.clone())
.event(one_params_command.clone(), one_params) .event(no_params_command.clone(), no_params)
.event(two_params_command.clone(), two_params)] .event(one_params_command.clone(), one_params)
}) .event(two_params_command.clone(), two_params)]
},
None,
)
.spawn(async { .spawn(async {
let request = EventRequest::new(no_params_command.clone()); let request = EventRequest::new(no_params_command.clone());
FlowySystem::current().sink(no_params_command, request); FlowySystem::current().sink(no_params_command, request);