mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
add system
This commit is contained in:
parent
f2f1bd3461
commit
85e8e4b8af
@ -14,6 +14,13 @@ futures = "0.3.15"
|
|||||||
futures-util = "0.3.15"
|
futures-util = "0.3.15"
|
||||||
bytes = "0.5"
|
bytes = "0.5"
|
||||||
tokio = { version = "1", features = ["sync"] }
|
tokio = { version = "1", features = ["sync"] }
|
||||||
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
|
log = "0.4.14"
|
||||||
|
env_logger = "0.8"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde_with = "1.9.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
futures-util = "0.3.15"
|
@ -3,5 +3,6 @@ mod error;
|
|||||||
mod module;
|
mod module;
|
||||||
mod request;
|
mod request;
|
||||||
mod response;
|
mod response;
|
||||||
|
mod rt;
|
||||||
mod service;
|
mod service;
|
||||||
mod util;
|
mod util;
|
||||||
|
@ -7,43 +7,52 @@ use crate::{
|
|||||||
service::{BoxService, Handler, Service, ServiceFactory, ServiceRequest, ServiceResponse},
|
service::{BoxService, Handler, Service, ServiceFactory, ServiceRequest, ServiceResponse},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
request::{payload::Payload, FlowyRequest},
|
||||||
|
response::{FlowyResponse, FlowyResponseBuilder},
|
||||||
|
service::{factory, BoxServiceFactory, HandlerService},
|
||||||
|
};
|
||||||
use futures_core::{future::LocalBoxFuture, ready};
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
|
use pin_project::pin_project;
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
fmt::Debug,
|
||||||
future::Future,
|
future::Future,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
sync::Arc,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use tokio::sync::{mpsc, mpsc::UnboundedReceiver};
|
use tokio::sync::{
|
||||||
|
mpsc,
|
||||||
use crate::{
|
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||||
request::{payload::Payload, FlowyRequest},
|
|
||||||
service::{factory, BoxServiceFactory, HandlerService},
|
|
||||||
};
|
};
|
||||||
use pin_project::pin_project;
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
pub type Command = String;
|
pub type Command = String;
|
||||||
pub type ModuleServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, SystemError>;
|
pub type CommandServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, SystemError>;
|
||||||
|
|
||||||
#[pin_project::pin_project]
|
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
name: String,
|
name: String,
|
||||||
data: DataContainer,
|
data: DataContainer,
|
||||||
fact_map: HashMap<Command, ModuleServiceFactory>,
|
factory_map: HashMap<Command, CommandServiceFactory>,
|
||||||
cmd_rx: UnboundedReceiver<FlowyRequest>,
|
req_tx: UnboundedSender<FlowyRequest>,
|
||||||
|
req_rx: UnboundedReceiver<FlowyRequest>,
|
||||||
|
resp_tx: UnboundedSender<FlowyResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn new(cmd_rx: UnboundedReceiver<FlowyRequest>) -> Self {
|
pub fn new(resp_tx: UnboundedSender<FlowyResponse>) -> Self {
|
||||||
|
let (req_tx, req_rx) = unbounded_channel::<FlowyRequest>();
|
||||||
Self {
|
Self {
|
||||||
name: "".to_owned(),
|
name: "".to_owned(),
|
||||||
data: DataContainer::new(),
|
data: DataContainer::new(),
|
||||||
fact_map: HashMap::new(),
|
factory_map: HashMap::new(),
|
||||||
cmd_rx,
|
req_tx,
|
||||||
|
req_rx,
|
||||||
|
resp_tx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,51 +74,111 @@ impl Module {
|
|||||||
R: Future + 'static,
|
R: Future + 'static,
|
||||||
R::Output: Responder + 'static,
|
R::Output: Responder + 'static,
|
||||||
{
|
{
|
||||||
self.fact_map.insert(command, factory(HandlerService::new(handler)));
|
self.factory_map.insert(command, factory(HandlerService::new(handler)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_handle(&self, cmd: &Command) -> bool { self.factory_map.contains_key(cmd) }
|
||||||
|
|
||||||
|
pub fn req_tx(&self) -> UnboundedSender<FlowyRequest> { self.req_tx.clone() }
|
||||||
|
|
||||||
|
pub fn handle(&self, request: FlowyRequest) {
|
||||||
|
match self.req_tx.send(request) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for Module {
|
impl Future for Module {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
loop {
|
loop {
|
||||||
match ready!(Pin::new(&mut self.cmd_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.fact_map.get(request.get_id()) {
|
Some(request) => match self.factory_map.get(request.get_cmd()) {
|
||||||
Some(factory) => {
|
Some(factory) => {
|
||||||
let service_future = factory.new_service(());
|
let fut = ModuleServiceFuture {
|
||||||
tokio::task::spawn_local(ModuleServiceFuture {
|
|
||||||
request,
|
request,
|
||||||
service_future,
|
fut: factory.new_service(()),
|
||||||
|
};
|
||||||
|
let resp_tx = self.resp_tx.clone();
|
||||||
|
tokio::task::spawn_local(async move {
|
||||||
|
let resp = fut.await.unwrap_or_else(|e| panic!());
|
||||||
|
if let Err(e) = resp_tx.send(resp) {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
None => {},
|
None => {
|
||||||
|
log::error!("Command: {} handler not found", request.get_cmd());
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project(project = HandlerServiceProj)]
|
type BoxModuleService = BoxService<ServiceRequest, ServiceResponse, SystemError>;
|
||||||
pub struct ModuleServiceFuture<Service, Error> {
|
#[pin_project]
|
||||||
|
pub struct ModuleServiceFuture {
|
||||||
request: FlowyRequest,
|
request: FlowyRequest,
|
||||||
#[pin]
|
#[pin]
|
||||||
service_future: LocalBoxFuture<'static, Result<Service, Error>>,
|
fut: LocalBoxFuture<'static, Result<BoxModuleService, SystemError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Service, Error> Future for ModuleServiceFuture<Service, Error> {
|
impl Future for ModuleServiceFuture {
|
||||||
type Output = ();
|
type Output = Result<FlowyResponse, SystemError>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { unimplemented!() }
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
loop {
|
||||||
|
let service = ready!(self.as_mut().project().fut.poll(cx))?;
|
||||||
|
let req = ServiceRequest::new(self.as_mut().request.clone(), Payload::None);
|
||||||
|
let (_, resp) = ready!(Pin::new(&mut service.call(req)).poll(cx))?.into_parts();
|
||||||
|
return Poll::Ready(Ok(resp));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceFactory<ServiceRequest> for Module {
|
#[cfg(test)]
|
||||||
type Response = ServiceResponse;
|
mod tests {
|
||||||
type Error = SystemError;
|
use super::*;
|
||||||
type Service = BoxService<ServiceRequest, ServiceResponse, SystemError>;
|
use crate::rt::Runtime;
|
||||||
type Config = ();
|
use futures_util::{future, pin_mut};
|
||||||
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::Error>>;
|
use tokio::sync::mpsc::unbounded_channel;
|
||||||
|
|
||||||
fn new_service(&self, cfg: Self::Config) -> Self::Future { unimplemented!() }
|
pub async fn hello_service() -> String {
|
||||||
|
println!("no params");
|
||||||
|
"hello".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[tokio::test]
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let mut runtime = Runtime::new().unwrap();
|
||||||
|
runtime.block_on(async {
|
||||||
|
let (resp_tx, mut resp_rx) = unbounded_channel::<FlowyResponse>();
|
||||||
|
let command = "hello".to_string();
|
||||||
|
let mut module = Module::new(resp_tx).event(command.clone(), hello_service);
|
||||||
|
assert_eq!(module.can_handle(&command), true);
|
||||||
|
let req_tx = module.req_tx();
|
||||||
|
let mut event = async move {
|
||||||
|
let request = FlowyRequest::new(command.clone());
|
||||||
|
req_tx.send(request).unwrap();
|
||||||
|
|
||||||
|
match resp_rx.recv().await {
|
||||||
|
Some(resp) => {
|
||||||
|
println!("{}", resp);
|
||||||
|
},
|
||||||
|
None => panic!(""),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pin_mut!(module, event);
|
||||||
|
future::select(module, event).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,23 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct FlowyRequest {
|
pub struct FlowyRequest {
|
||||||
id: String,
|
id: String,
|
||||||
|
cmd: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyRequest {
|
impl FlowyRequest {
|
||||||
pub fn get_id(&self) -> &str { &self.id }
|
pub fn new(cmd: String) -> FlowyRequest {
|
||||||
|
Self {
|
||||||
|
id: uuid::Uuid::new_v4().to_string(),
|
||||||
|
cmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for FlowyRequest {
|
impl FlowyRequest {
|
||||||
fn default() -> Self { Self { id: "".to_string() } }
|
pub fn get_cmd(&self) -> &str { &self.cmd }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromRequest: Sized {
|
pub trait FromRequest: Sized {
|
||||||
|
@ -1,8 +1,21 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{fmt, fmt::Formatter};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum ResponseData {
|
pub enum ResponseData {
|
||||||
Bytes(Vec<u8>),
|
Bytes(Vec<u8>),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ResponseData {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ResponseData::Bytes(bytes) => f.write_fmt(format_args!("{} bytes", bytes.len())),
|
||||||
|
ResponseData::None => f.write_str("Empty"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::convert::Into<ResponseData> for String {
|
impl std::convert::Into<ResponseData> for String {
|
||||||
fn into(self) -> ResponseData { ResponseData::Bytes(self.into_bytes()) }
|
fn into(self) -> ResponseData { ResponseData::Bytes(self.into_bytes()) }
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,22 @@ use crate::{
|
|||||||
request::FlowyRequest,
|
request::FlowyRequest,
|
||||||
response::{data::ResponseData, Responder},
|
response::{data::ResponseData, Responder},
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::skip_serializing_none;
|
||||||
|
use std::{fmt, fmt::Formatter};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum StatusCode {
|
pub enum StatusCode {
|
||||||
Success,
|
Success,
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct FlowyResponse<T = ResponseData> {
|
pub struct FlowyResponse<T = ResponseData> {
|
||||||
pub data: T,
|
pub data: T,
|
||||||
pub status: StatusCode,
|
pub status: StatusCode,
|
||||||
|
#[serde(skip)]
|
||||||
pub error: Option<SystemError>,
|
pub error: Option<SystemError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,6 +32,16 @@ impl FlowyResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for FlowyResponse {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match serde_json::to_string(self) {
|
||||||
|
Ok(json) => f.write_fmt(format_args!("{:?}", json))?,
|
||||||
|
Err(e) => f.write_fmt(format_args!("{:?}", e))?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Responder for FlowyResponse {
|
impl Responder for FlowyResponse {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse { self }
|
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse { self }
|
||||||
|
4
rust-lib/flowy-sys/src/rt/mod.rs
Normal file
4
rust-lib/flowy-sys/src/rt/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
mod runtime;
|
||||||
|
mod system;
|
||||||
|
|
||||||
|
pub use runtime::*;
|
34
rust-lib/flowy-sys/src/rt/runtime.rs
Normal file
34
rust-lib/flowy-sys/src/rt/runtime.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use std::{future::Future, io};
|
||||||
|
use tokio::{runtime, task::LocalSet};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Runtime {
|
||||||
|
local: LocalSet,
|
||||||
|
rt: runtime::Runtime,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Runtime {
|
||||||
|
pub fn new() -> io::Result<Runtime> {
|
||||||
|
let rt = runtime::Builder::new_multi_thread().enable_io().enable_time().build()?;
|
||||||
|
|
||||||
|
Ok(Runtime {
|
||||||
|
rt,
|
||||||
|
local: LocalSet::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn<F>(&self, future: F) -> &Self
|
||||||
|
where
|
||||||
|
F: Future<Output = ()> + 'static,
|
||||||
|
{
|
||||||
|
self.local.spawn_local(future);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_on<F>(&self, f: F) -> F::Output
|
||||||
|
where
|
||||||
|
F: Future + 'static,
|
||||||
|
{
|
||||||
|
self.local.block_on(&self.rt, f)
|
||||||
|
}
|
||||||
|
}
|
157
rust-lib/flowy-sys/src/rt/system.rs
Normal file
157
rust-lib/flowy-sys/src/rt/system.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
use crate::{
|
||||||
|
module::{Command, Module},
|
||||||
|
request::FlowyRequest,
|
||||||
|
response::FlowyResponse,
|
||||||
|
rt::Runtime,
|
||||||
|
};
|
||||||
|
use futures_core::{future::LocalBoxFuture, ready, task::Context};
|
||||||
|
use futures_util::{future, pin_mut};
|
||||||
|
use std::{cell::RefCell, future::Future, io, sync::Arc};
|
||||||
|
use tokio::{
|
||||||
|
macros::support::{Pin, Poll},
|
||||||
|
sync::{
|
||||||
|
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||||
|
oneshot,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
thread_local!(
|
||||||
|
static CURRENT: RefCell<Option<Arc<FlowySystem>>> = RefCell::new(None);
|
||||||
|
);
|
||||||
|
|
||||||
|
pub struct FlowySystem {
|
||||||
|
resp_tx: UnboundedSender<FlowyResponse>,
|
||||||
|
modules: Vec<Module>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowySystem {
|
||||||
|
pub fn construct<F>(module_factory: F) -> SystemRunner
|
||||||
|
where
|
||||||
|
F: FnOnce(UnboundedSender<FlowyResponse>) -> Vec<Module>,
|
||||||
|
{
|
||||||
|
let runtime = Runtime::new().unwrap();
|
||||||
|
let (resp_tx, mut resp_rx) = unbounded_channel::<FlowyResponse>();
|
||||||
|
let (stop_tx, stop_rx) = oneshot::channel();
|
||||||
|
let controller = SystemController { resp_rx, stop_tx };
|
||||||
|
runtime.spawn(controller);
|
||||||
|
|
||||||
|
let mut system = Self {
|
||||||
|
resp_tx: resp_tx.clone(),
|
||||||
|
modules: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let factory = module_factory(resp_tx.clone());
|
||||||
|
factory.into_iter().for_each(|m| {
|
||||||
|
runtime.spawn(m);
|
||||||
|
// system.add_module(m);
|
||||||
|
});
|
||||||
|
|
||||||
|
FlowySystem::set_current(system);
|
||||||
|
|
||||||
|
let runner = SystemRunner { rt: runtime, stop_rx };
|
||||||
|
runner
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_command(&self, cmd: Command, request: FlowyRequest) {
|
||||||
|
self.modules.iter().for_each(|m| {
|
||||||
|
if m.can_handle(&cmd) {
|
||||||
|
m.handle(request.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_module(&mut self, module: Module) { self.modules.push(module); }
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn set_current(sys: FlowySystem) {
|
||||||
|
CURRENT.with(|cell| {
|
||||||
|
*cell.borrow_mut() = Some(Arc::new(sys));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current() -> Arc<FlowySystem> {
|
||||||
|
CURRENT.with(|cell| match *cell.borrow() {
|
||||||
|
Some(ref sys) => sys.clone(),
|
||||||
|
None => panic!("System is not running"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resp_tx(&self) -> UnboundedSender<FlowyResponse> { self.resp_tx.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SystemController {
|
||||||
|
resp_rx: UnboundedReceiver<FlowyResponse>,
|
||||||
|
stop_tx: oneshot::Sender<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Future for SystemController {
|
||||||
|
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) => {
|
||||||
|
// FFI
|
||||||
|
println!("Receive response: {:?}", resp);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SystemRunner {
|
||||||
|
rt: Runtime,
|
||||||
|
stop_rx: oneshot::Receiver<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemRunner {
|
||||||
|
pub fn run(self) -> io::Result<()> {
|
||||||
|
let SystemRunner { rt, stop_rx } = self;
|
||||||
|
match rt.block_on(stop_rx) {
|
||||||
|
Ok(code) => {
|
||||||
|
if code != 0 {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("Non-zero exit code: {}", code),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn<F>(self, future: F) -> Self
|
||||||
|
where
|
||||||
|
F: Future<Output = ()> + 'static,
|
||||||
|
{
|
||||||
|
self.rt.spawn(future);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub async fn hello_service() -> String { "hello".to_string() }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let command = "Hello".to_string();
|
||||||
|
|
||||||
|
FlowySystem::construct(|tx| {
|
||||||
|
vec![
|
||||||
|
Module::new(tx.clone()).event(command.clone(), hello_service),
|
||||||
|
// Module::new(tx.clone()).event(command.clone(), hello_service),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.spawn(async {
|
||||||
|
let request = FlowyRequest::new(command.clone());
|
||||||
|
FlowySystem::current().handle_command(command, request);
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -125,8 +125,8 @@ where
|
|||||||
match self.as_mut().project() {
|
match self.as_mut().project() {
|
||||||
HandlerServiceProj::Extract(fut, req, handle) => {
|
HandlerServiceProj::Extract(fut, req, handle) => {
|
||||||
match ready!(fut.poll(cx)) {
|
match ready!(fut.poll(cx)) {
|
||||||
Ok(item) => {
|
Ok(params) => {
|
||||||
let fut = handle.call(item);
|
let fut = handle.call(params);
|
||||||
let state = HandlerServiceFuture::Handle(fut, req.take());
|
let state = HandlerServiceFuture::Handle(fut, req.take());
|
||||||
self.as_mut().set(state);
|
self.as_mut().set(state);
|
||||||
},
|
},
|
||||||
|
@ -42,4 +42,6 @@ pub struct ServiceResponse<T = ResponseData> {
|
|||||||
|
|
||||||
impl<T> ServiceResponse<T> {
|
impl<T> ServiceResponse<T> {
|
||||||
pub fn new(request: FlowyRequest, response: FlowyResponse<T>) -> Self { ServiceResponse { request, response } }
|
pub fn new(request: FlowyRequest, response: FlowyResponse<T>) -> Self { ServiceResponse { request, response } }
|
||||||
|
|
||||||
|
pub fn into_parts(self) -> (FlowyRequest, FlowyResponse<T>) { (self.request, self.response) }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user