mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
add tests module and stop the system
This commit is contained in:
parent
d2b53fe1f3
commit
331115aa63
@ -6,6 +6,7 @@
|
|||||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/tests" isTestSource="true" />
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/tests" isTestSource="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sys/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sys/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sys/tests" isTestSource="true" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />
|
<excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
use crate::response::{FlowyResponse, StatusCode};
|
use crate::{
|
||||||
use std::{cell::RefCell, fmt};
|
request::EventRequest,
|
||||||
|
response::{EventResponse, EventResponseBuilder, StatusCode},
|
||||||
|
};
|
||||||
|
use std::{fmt, option::NoneError};
|
||||||
|
use tokio::sync::mpsc::error::SendError;
|
||||||
|
|
||||||
pub trait Error: fmt::Debug + fmt::Display {
|
pub trait Error: fmt::Debug + fmt::Display {
|
||||||
fn status_code(&self) -> StatusCode;
|
fn status_code(&self) -> StatusCode;
|
||||||
|
|
||||||
fn as_response(&self) -> FlowyResponse { FlowyResponse::new(self.status_code()) }
|
fn as_response(&self) -> EventResponse { EventResponse::new(self.status_code()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Error + 'static> From<T> for SystemError {
|
impl<T: Error + 'static> From<T> for SystemError {
|
||||||
@ -33,6 +37,57 @@ impl std::error::Error for SystemError {
|
|||||||
fn cause(&self) -> Option<&dyn std::error::Error> { None }
|
fn cause(&self) -> Option<&dyn std::error::Error> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SystemError> for FlowyResponse {
|
impl<T> From<SendError<T>> for SystemError
|
||||||
|
where
|
||||||
|
T: fmt::Display + fmt::Debug + 'static,
|
||||||
|
{
|
||||||
|
fn from(err: SendError<T>) -> Self { InternalError { inner: err }.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SendError<EventRequest>> for SystemError {
|
||||||
|
fn from(err: SendError<EventRequest>) -> Self { InternalError { inner: err }.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NoneError> for SystemError {
|
||||||
|
fn from(s: NoneError) -> Self {
|
||||||
|
InternalError {
|
||||||
|
inner: format!("Unexpected none: {:?}", s),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SystemError> for EventResponse {
|
||||||
fn from(err: SystemError) -> Self { err.inner_error().as_response() }
|
fn from(err: SystemError) -> Self { err.inner_error().as_response() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InternalError<T> {
|
||||||
|
inner: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> InternalError<T> {
|
||||||
|
pub fn new(inner: T) -> Self { InternalError { inner } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Debug for InternalError<T>
|
||||||
|
where
|
||||||
|
T: fmt::Debug + 'static,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.inner, f) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Display for InternalError<T>
|
||||||
|
where
|
||||||
|
T: fmt::Display + 'static,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.inner, f) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Error for InternalError<T>
|
||||||
|
where
|
||||||
|
T: fmt::Debug + fmt::Display + 'static,
|
||||||
|
{
|
||||||
|
fn status_code(&self) -> StatusCode { StatusCode::Err }
|
||||||
|
|
||||||
|
fn as_response(&self) -> EventResponse { EventResponseBuilder::Err().data(format!("{}", self.inner)).build() }
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![feature(try_trait)]
|
||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
mod error;
|
mod error;
|
||||||
mod module;
|
mod module;
|
||||||
@ -6,3 +8,7 @@ mod response;
|
|||||||
mod rt;
|
mod rt;
|
||||||
mod service;
|
mod service;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::{error::*, module::*, request::*, response::*, rt::*};
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::SystemError,
|
error::SystemError,
|
||||||
request::{payload::Payload, FlowyRequest, FromRequest},
|
request::{payload::Payload, EventRequest, FromRequest},
|
||||||
util::ready::Ready,
|
util::ready::Ready,
|
||||||
};
|
};
|
||||||
use std::{ops::Deref, sync::Arc};
|
use std::{ops::Deref, sync::Arc};
|
||||||
@ -32,5 +32,5 @@ impl<T: ?Sized + 'static> FromRequest for ModuleData<T> {
|
|||||||
type Future = Ready<Result<Self, SystemError>>;
|
type Future = Ready<Result<Self, SystemError>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &FlowyRequest, _: &mut Payload) -> Self::Future { unimplemented!() }
|
fn from_request(_req: &EventRequest, _: &mut Payload) -> Self::Future { unimplemented!() }
|
||||||
}
|
}
|
||||||
|
@ -8,44 +8,35 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
request::{payload::Payload, FlowyRequest},
|
request::{payload::Payload, EventRequest},
|
||||||
response::{FlowyResponse, FlowyResponseBuilder},
|
response::EventResponse,
|
||||||
service::{factory, BoxServiceFactory, HandlerService},
|
service::{factory, BoxServiceFactory, HandlerService},
|
||||||
};
|
};
|
||||||
use futures_core::{future::LocalBoxFuture, ready};
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::Debug,
|
|
||||||
future::Future,
|
future::Future,
|
||||||
hash::Hash,
|
|
||||||
marker::PhantomData,
|
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
rc::Rc,
|
|
||||||
sync::Arc,
|
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use tokio::sync::{
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
mpsc,
|
|
||||||
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub type Command = String;
|
pub type Event = String;
|
||||||
pub type CommandServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, SystemError>;
|
pub type EventServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, SystemError>;
|
||||||
|
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
name: String,
|
name: String,
|
||||||
data: DataContainer,
|
data: DataContainer,
|
||||||
service_map: HashMap<Command, CommandServiceFactory>,
|
service_map: HashMap<Event, EventServiceFactory>,
|
||||||
req_tx: UnboundedSender<FlowyRequest>,
|
req_tx: UnboundedSender<EventRequest>,
|
||||||
req_rx: UnboundedReceiver<FlowyRequest>,
|
req_rx: UnboundedReceiver<EventRequest>,
|
||||||
resp_tx: UnboundedSender<FlowyResponse>,
|
resp_tx: UnboundedSender<EventResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn new(resp_tx: UnboundedSender<FlowyResponse>) -> Self {
|
pub fn new(resp_tx: UnboundedSender<EventResponse>) -> Self {
|
||||||
let (req_tx, req_rx) = unbounded_channel::<FlowyRequest>();
|
let (req_tx, req_rx) = unbounded_channel::<EventRequest>();
|
||||||
Self {
|
Self {
|
||||||
name: "".to_owned(),
|
name: "".to_owned(),
|
||||||
data: DataContainer::new(),
|
data: DataContainer::new(),
|
||||||
@ -62,36 +53,38 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn data<D: 'static>(mut self, data: D) -> Self {
|
pub fn data<D: 'static>(mut self, data: D) -> Self {
|
||||||
let module_data = ModuleData::new(data);
|
self.data.insert(ModuleData::new(data));
|
||||||
self.data.insert(module_data);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event<H, T, R>(mut self, command: Command, handler: H) -> Self
|
pub fn event<H, T, R>(mut self, event: Event, handler: H) -> Self
|
||||||
where
|
where
|
||||||
H: Handler<T, R>,
|
H: Handler<T, R>,
|
||||||
T: FromRequest + 'static,
|
T: FromRequest + 'static,
|
||||||
R: Future + 'static,
|
R: Future + 'static,
|
||||||
R::Output: Responder + 'static,
|
R::Output: Responder + 'static,
|
||||||
{
|
{
|
||||||
self.service_map.insert(command, factory(HandlerService::new(handler)));
|
if self.service_map.contains_key(&event) {
|
||||||
|
log::error!("Duplicate Event: {}", &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.service_map.insert(event, factory(HandlerService::new(handler)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_handle(&self, cmd: &Command) -> bool { self.service_map.contains_key(cmd) }
|
pub fn req_tx(&self) -> UnboundedSender<EventRequest> { self.req_tx.clone() }
|
||||||
|
|
||||||
pub fn req_tx(&self) -> UnboundedSender<FlowyRequest> { self.req_tx.clone() }
|
pub fn handle(&self, request: EventRequest) {
|
||||||
|
log::trace!("Module: {} receive request: {:?}", self.name, request);
|
||||||
pub fn handle(&self, request: FlowyRequest) {
|
|
||||||
match self.req_tx.send(request) {
|
match self.req_tx.send(request) {
|
||||||
Ok(_) => {},
|
Ok(_) => {},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{:?}", e);
|
log::error!("Module: {} with error: {:?}", self.name, e);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn service_sender_map(&self) -> HashMap<Command, UnboundedSender<FlowyRequest>> {
|
pub fn forward_map(&self) -> HashMap<Event, UnboundedSender<EventRequest>> {
|
||||||
self.service_map
|
self.service_map
|
||||||
.keys()
|
.keys()
|
||||||
.map(|key| (key.clone(), self.req_tx()))
|
.map(|key| (key.clone(), self.req_tx()))
|
||||||
@ -105,7 +98,7 @@ 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_cmd()) {
|
Some(request) => match self.service_map.get(request.get_event()) {
|
||||||
Some(factory) => {
|
Some(factory) => {
|
||||||
let fut = ModuleServiceFuture {
|
let fut = ModuleServiceFuture {
|
||||||
request,
|
request,
|
||||||
@ -113,14 +106,14 @@ impl Future for Module {
|
|||||||
};
|
};
|
||||||
let resp_tx = self.resp_tx.clone();
|
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 resp = fut.await.unwrap_or_else(|_e| panic!());
|
||||||
if let Err(e) = resp_tx.send(resp) {
|
if let Err(e) = resp_tx.send(resp) {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
log::error!("Command: {} handler not found", request.get_cmd());
|
log::error!("Event: {} handler not found", request.get_event());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -131,18 +124,19 @@ impl Future for Module {
|
|||||||
type BoxModuleService = BoxService<ServiceRequest, ServiceResponse, SystemError>;
|
type BoxModuleService = BoxService<ServiceRequest, ServiceResponse, SystemError>;
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
pub struct ModuleServiceFuture {
|
pub struct ModuleServiceFuture {
|
||||||
request: FlowyRequest,
|
request: EventRequest,
|
||||||
#[pin]
|
#[pin]
|
||||||
fut: LocalBoxFuture<'static, Result<BoxModuleService, SystemError>>,
|
fut: LocalBoxFuture<'static, Result<BoxModuleService, SystemError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for ModuleServiceFuture {
|
impl Future for ModuleServiceFuture {
|
||||||
type Output = Result<FlowyResponse, SystemError>;
|
type Output = Result<EventResponse, SystemError>;
|
||||||
|
|
||||||
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 {
|
||||||
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);
|
||||||
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));
|
||||||
}
|
}
|
||||||
@ -156,29 +150,23 @@ mod tests {
|
|||||||
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 {
|
pub async fn hello_service() -> String { "hello".to_string() }
|
||||||
println!("no params");
|
|
||||||
"hello".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[tokio::test]
|
|
||||||
|
|
||||||
#[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::<FlowyResponse>();
|
let (resp_tx, mut resp_rx) = unbounded_channel::<EventResponse>();
|
||||||
let command = "hello".to_string();
|
let event = "hello".to_string();
|
||||||
let mut module = Module::new(resp_tx).event(command.clone(), hello_service);
|
let mut module = Module::new(resp_tx).event(event.clone(), hello_service);
|
||||||
assert_eq!(module.can_handle(&command), true);
|
|
||||||
let req_tx = module.req_tx();
|
let req_tx = module.req_tx();
|
||||||
let mut event = async move {
|
let mut event = async move {
|
||||||
let request = FlowyRequest::new(command.clone());
|
let request = EventRequest::new(event.clone());
|
||||||
req_tx.send(request).unwrap();
|
req_tx.send(request).unwrap();
|
||||||
|
|
||||||
match resp_rx.recv().await {
|
match resp_rx.recv().await {
|
||||||
Some(resp) => {
|
Some(resp) => {
|
||||||
println!("{}", resp);
|
log::info!("{}", resp);
|
||||||
},
|
},
|
||||||
None => panic!(""),
|
None => panic!(""),
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub use request::*;
|
|
||||||
|
|
||||||
pub mod payload;
|
pub mod payload;
|
||||||
mod request;
|
mod request;
|
||||||
|
|
||||||
|
pub use payload::*;
|
||||||
|
pub use request::*;
|
||||||
|
@ -5,32 +5,31 @@ use crate::{
|
|||||||
request::payload::Payload,
|
request::payload::Payload,
|
||||||
util::ready::{ready, Ready},
|
util::ready::{ready, Ready},
|
||||||
};
|
};
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FlowyRequest {
|
pub struct EventRequest {
|
||||||
id: String,
|
id: String,
|
||||||
cmd: String,
|
event: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyRequest {
|
impl EventRequest {
|
||||||
pub fn new(cmd: String) -> FlowyRequest {
|
pub fn new(event: String) -> EventRequest {
|
||||||
Self {
|
Self {
|
||||||
id: uuid::Uuid::new_v4().to_string(),
|
id: uuid::Uuid::new_v4().to_string(),
|
||||||
cmd,
|
event,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyRequest {
|
impl EventRequest {
|
||||||
pub fn get_cmd(&self) -> &str { &self.cmd }
|
pub fn get_event(&self) -> &str { &self.event }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromRequest: Sized {
|
pub trait FromRequest: Sized {
|
||||||
type Error: Into<SystemError>;
|
type Error: Into<SystemError>;
|
||||||
type Future: Future<Output = Result<Self, Self::Error>>;
|
type Future: Future<Output = Result<Self, Self::Error>>;
|
||||||
|
|
||||||
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future;
|
fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -38,7 +37,7 @@ impl FromRequest for () {
|
|||||||
type Error = SystemError;
|
type Error = SystemError;
|
||||||
type Future = Ready<Result<(), SystemError>>;
|
type Future = Ready<Result<(), SystemError>>;
|
||||||
|
|
||||||
fn from_request(_req: &FlowyRequest, _payload: &mut Payload) -> Self::Future { ready(Ok(())) }
|
fn from_request(_req: &EventRequest, _payload: &mut Payload) -> Self::Future { ready(Ok(())) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -46,5 +45,5 @@ impl FromRequest for String {
|
|||||||
type Error = SystemError;
|
type Error = SystemError;
|
||||||
type Future = Ready<Result<String, SystemError>>;
|
type Future = Ready<Result<String, SystemError>>;
|
||||||
|
|
||||||
fn from_request(_req: &FlowyRequest, _payload: &mut Payload) -> Self::Future { ready(Ok("".to_string())) }
|
fn from_request(_req: &EventRequest, _payload: &mut Payload) -> Self::Future { ready(Ok("".to_string())) }
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::SystemError,
|
error::SystemError,
|
||||||
response::{data::ResponseData, FlowyResponse, StatusCode},
|
response::{data::ResponseData, EventResponse, StatusCode},
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! static_response {
|
macro_rules! static_response {
|
||||||
($name:ident, $status:expr) => {
|
($name:ident, $status:expr) => {
|
||||||
#[allow(non_snake_case, missing_docs)]
|
#[allow(non_snake_case, missing_docs)]
|
||||||
pub fn $name() -> FlowyResponseBuilder { FlowyResponseBuilder::new($status) }
|
pub fn $name() -> EventResponseBuilder { EventResponseBuilder::new($status) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FlowyResponseBuilder<T = ResponseData> {
|
pub struct EventResponseBuilder<T = ResponseData> {
|
||||||
pub data: T,
|
pub data: T,
|
||||||
pub status: StatusCode,
|
pub status: StatusCode,
|
||||||
pub error: Option<SystemError>,
|
pub error: Option<SystemError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyResponseBuilder {
|
impl EventResponseBuilder {
|
||||||
pub fn new(status: StatusCode) -> Self {
|
pub fn new(status: StatusCode) -> Self {
|
||||||
FlowyResponseBuilder {
|
EventResponseBuilder {
|
||||||
data: ResponseData::None,
|
data: ResponseData::None,
|
||||||
status,
|
status,
|
||||||
error: None,
|
error: None,
|
||||||
@ -35,13 +35,14 @@ impl FlowyResponseBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> FlowyResponse {
|
pub fn build(self) -> EventResponse {
|
||||||
FlowyResponse {
|
EventResponse {
|
||||||
data: self.data,
|
data: self.data,
|
||||||
status: self.status,
|
status: self.status,
|
||||||
error: self.error,
|
error: self.error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static_response!(Ok, StatusCode::Success);
|
static_response!(Ok, StatusCode::Ok);
|
||||||
|
static_response!(Err, StatusCode::Err);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
use crate::request::FlowyRequest;
|
use crate::{
|
||||||
use crate::response::FlowyResponse;
|
request::EventRequest,
|
||||||
use crate::response::FlowyResponseBuilder;
|
response::{EventResponse, EventResponseBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Responder {
|
pub trait Responder {
|
||||||
fn respond_to(self, req: &FlowyRequest) -> FlowyResponse;
|
fn respond_to(self, req: &EventRequest) -> EventResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_responder {
|
macro_rules! impl_responder {
|
||||||
($res: ty) => {
|
($res: ty) => {
|
||||||
impl Responder for $res {
|
impl Responder for $res {
|
||||||
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse {
|
fn respond_to(self, _: &EventRequest) -> EventResponse { EventResponseBuilder::Ok().data(self).build() }
|
||||||
FlowyResponseBuilder::Ok().data(self).build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,31 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::SystemError,
|
error::SystemError,
|
||||||
request::FlowyRequest,
|
request::EventRequest,
|
||||||
response::{data::ResponseData, Responder},
|
response::{data::ResponseData, Responder},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use serde_with::skip_serializing_none;
|
|
||||||
use std::{fmt, fmt::Formatter};
|
use std::{fmt, fmt::Formatter};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum StatusCode {
|
pub enum StatusCode {
|
||||||
Success,
|
Ok,
|
||||||
Error,
|
Err,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
// serde user guide: https://serde.rs/field-attrs.html
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub struct FlowyResponse<T = ResponseData> {
|
pub struct EventResponse {
|
||||||
pub data: T,
|
#[serde(serialize_with = "serialize_data")]
|
||||||
|
pub data: ResponseData,
|
||||||
pub status: StatusCode,
|
pub status: StatusCode,
|
||||||
#[serde(skip)]
|
#[serde(serialize_with = "serialize_error")]
|
||||||
pub error: Option<SystemError>,
|
pub error: Option<SystemError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowyResponse {
|
impl EventResponse {
|
||||||
pub fn new(status: StatusCode) -> Self {
|
pub fn new(status: StatusCode) -> Self {
|
||||||
FlowyResponse {
|
EventResponse {
|
||||||
data: ResponseData::None,
|
data: ResponseData::None,
|
||||||
status,
|
status,
|
||||||
error: None,
|
error: None,
|
||||||
@ -32,7 +33,7 @@ impl FlowyResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for FlowyResponse {
|
impl std::fmt::Display for EventResponse {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match serde_json::to_string(self) {
|
match serde_json::to_string(self) {
|
||||||
Ok(json) => f.write_fmt(format_args!("{:?}", json))?,
|
Ok(json) => f.write_fmt(format_args!("{:?}", json))?,
|
||||||
@ -42,7 +43,27 @@ impl std::fmt::Display for FlowyResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for FlowyResponse {
|
impl Responder for EventResponse {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, _: &FlowyRequest) -> FlowyResponse { self }
|
fn respond_to(self, _: &EventRequest) -> EventResponse { self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_error<S>(error: &Option<SystemError>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match error {
|
||||||
|
Some(e) => serializer.serialize_str(&format!("{:?}", e)),
|
||||||
|
None => serializer.serialize_str(""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_data<S>(data: &ResponseData, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match data {
|
||||||
|
ResponseData::Bytes(bytes) => serializer.serialize_str(&format!("{} bytes", bytes.len())),
|
||||||
|
ResponseData::None => serializer.serialize_str(""),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,3 +2,4 @@ mod runtime;
|
|||||||
mod system;
|
mod system;
|
||||||
|
|
||||||
pub use runtime::*;
|
pub use runtime::*;
|
||||||
|
pub use system::*;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
module::{Command, CommandServiceFactory, Module},
|
module::{Event, Module},
|
||||||
request::FlowyRequest,
|
request::EventRequest,
|
||||||
response::FlowyResponse,
|
response::EventResponse,
|
||||||
rt::Runtime,
|
rt::runtime::Runtime,
|
||||||
service::BoxServiceFactory,
|
|
||||||
};
|
};
|
||||||
use futures_core::{future::LocalBoxFuture, ready, task::Context};
|
use futures_core::{ready, task::Context};
|
||||||
use futures_util::{future, pin_mut};
|
|
||||||
|
use crate::error::{InternalError, SystemError};
|
||||||
use std::{cell::RefCell, collections::HashMap, future::Future, io, sync::Arc};
|
use std::{cell::RefCell, collections::HashMap, future::Future, io, sync::Arc};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
macros::support::{Pin, Poll},
|
macros::support::{Pin, Poll},
|
||||||
@ -20,30 +20,40 @@ thread_local!(
|
|||||||
static CURRENT: RefCell<Option<Arc<FlowySystem>>> = RefCell::new(None);
|
static CURRENT: RefCell<Option<Arc<FlowySystem>>> = RefCell::new(None);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
enum SystemCommand {
|
||||||
|
Exit(i8),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FlowySystem {
|
pub struct FlowySystem {
|
||||||
resp_tx: UnboundedSender<FlowyResponse>,
|
sys_tx: UnboundedSender<SystemCommand>,
|
||||||
sender_map: HashMap<Command, UnboundedSender<FlowyRequest>>,
|
forward_map: HashMap<Event, UnboundedSender<EventRequest>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowySystem {
|
impl FlowySystem {
|
||||||
pub fn construct<F>(module_factory: F) -> SystemRunner
|
pub fn construct<F>(module_factory: F) -> SystemRunner
|
||||||
where
|
where
|
||||||
F: FnOnce(UnboundedSender<FlowyResponse>) -> Vec<Module>,
|
F: FnOnce(UnboundedSender<EventResponse>) -> Vec<Module>,
|
||||||
{
|
{
|
||||||
let runtime = Runtime::new().unwrap();
|
let runtime = Runtime::new().unwrap();
|
||||||
let (resp_tx, mut resp_rx) = unbounded_channel::<FlowyResponse>();
|
let (resp_tx, resp_rx) = unbounded_channel::<EventResponse>();
|
||||||
|
|
||||||
|
let (sys_tx, sys_rx) = unbounded_channel::<SystemCommand>();
|
||||||
let (stop_tx, stop_rx) = oneshot::channel();
|
let (stop_tx, stop_rx) = oneshot::channel();
|
||||||
let controller = SystemController { resp_rx, stop_tx };
|
|
||||||
runtime.spawn(controller);
|
runtime.spawn(SystemFFI { resp_rx });
|
||||||
|
runtime.spawn(SystemController {
|
||||||
|
stop_tx: Some(stop_tx),
|
||||||
|
sys_rx,
|
||||||
|
});
|
||||||
|
|
||||||
let mut system = Self {
|
let mut system = Self {
|
||||||
resp_tx: resp_tx.clone(),
|
sys_tx,
|
||||||
sender_map: HashMap::default(),
|
forward_map: HashMap::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let factory = module_factory(resp_tx.clone());
|
let factory = module_factory(resp_tx.clone());
|
||||||
factory.into_iter().for_each(|m| {
|
factory.into_iter().for_each(|m| {
|
||||||
system.sender_map.extend(m.service_sender_map());
|
system.forward_map.extend(m.forward_map());
|
||||||
runtime.spawn(m);
|
runtime.spawn(m);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,9 +62,18 @@ impl FlowySystem {
|
|||||||
runner
|
runner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_command(&self, cmd: Command, request: FlowyRequest) {
|
pub fn sink(&self, event: Event, request: EventRequest) -> Result<(), SystemError> {
|
||||||
if let Some(sender) = self.sender_map.get(&cmd) {
|
log::trace!("Sink event: {}", event);
|
||||||
sender.send(request);
|
let _ = self.forward_map.get(&event)?.send(request)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&self) {
|
||||||
|
match self.sys_tx.send(SystemCommand::Exit(0)) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Stop system error: {}", e);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,24 +90,43 @@ impl FlowySystem {
|
|||||||
None => panic!("System is not running"),
|
None => panic!("System is not running"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resp_tx(&self) -> UnboundedSender<FlowyResponse> { self.resp_tx.clone() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SystemController {
|
struct SystemFFI {
|
||||||
resp_rx: UnboundedReceiver<FlowyResponse>,
|
resp_rx: UnboundedReceiver<EventResponse>,
|
||||||
stop_tx: oneshot::Sender<i32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for SystemController {
|
impl Future for SystemFFI {
|
||||||
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.resp_rx).poll_recv(cx)) {
|
match ready!(Pin::new(&mut self.resp_rx).poll_recv(cx)) {
|
||||||
None => return Poll::Ready(()),
|
None => return Poll::Ready(()),
|
||||||
Some(resp) => {
|
Some(resp) => {
|
||||||
// FF
|
log::trace!("Response: {:?}", resp);
|
||||||
println!("Receive response: {:?}", resp);
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SystemController {
|
||||||
|
stop_tx: Option<oneshot::Sender<i8>>,
|
||||||
|
sys_rx: UnboundedReceiver<SystemCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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.sys_rx).poll_recv(cx)) {
|
||||||
|
None => return Poll::Ready(()),
|
||||||
|
Some(cmd) => match cmd {
|
||||||
|
SystemCommand::Exit(code) => {
|
||||||
|
if let Some(tx) = self.stop_tx.take() {
|
||||||
|
let _ = tx.send(code);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +135,7 @@ impl Future for SystemController {
|
|||||||
|
|
||||||
pub struct SystemRunner {
|
pub struct SystemRunner {
|
||||||
rt: Runtime,
|
rt: Runtime,
|
||||||
stop_rx: oneshot::Receiver<i32>,
|
stop_rx: oneshot::Receiver<i8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemRunner {
|
impl SystemRunner {
|
||||||
@ -126,28 +164,3 @@ impl SystemRunner {
|
|||||||
self
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
use crate::{
|
use crate::service::{Service, ServiceFactory};
|
||||||
service::{Service, ServiceFactory, ServiceRequest, ServiceResponse},
|
|
||||||
util::ready::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
use futures_core::future::LocalBoxFuture;
|
use futures_core::future::LocalBoxFuture;
|
||||||
|
|
||||||
pub fn factory<SF, Req>(factory: SF) -> BoxServiceFactory<SF::Config, Req, SF::Response, SF::Error>
|
pub fn factory<SF, Req>(factory: SF) -> BoxServiceFactory<SF::Config, Req, SF::Response, SF::Error>
|
||||||
@ -47,6 +43,7 @@ type Inner<Cfg, Req, Res, Err> = Box<
|
|||||||
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>>>>;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
|
pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
|
||||||
where
|
where
|
||||||
S: Service<Req> + 'static,
|
S: Service<Req> + 'static,
|
||||||
|
@ -10,8 +10,8 @@ use pin_project::pin_project;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::SystemError,
|
error::SystemError,
|
||||||
request::{payload::Payload, FlowyRequest, FromRequest},
|
request::{payload::Payload, EventRequest, FromRequest},
|
||||||
response::{FlowyResponse, Responder},
|
response::{EventResponse, Responder},
|
||||||
service::{Service, ServiceFactory, ServiceRequest, ServiceResponse},
|
service::{Service, ServiceFactory, ServiceRequest, ServiceResponse},
|
||||||
util::ready::*,
|
util::ready::*,
|
||||||
};
|
};
|
||||||
@ -107,8 +107,8 @@ where
|
|||||||
R: Future,
|
R: Future,
|
||||||
R::Output: Responder,
|
R::Output: Responder,
|
||||||
{
|
{
|
||||||
Extract(#[pin] T::Future, Option<FlowyRequest>, H),
|
Extract(#[pin] T::Future, Option<EventRequest>, H),
|
||||||
Handle(#[pin] R, Option<FlowyRequest>),
|
Handle(#[pin] R, Option<EventRequest>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, T, R> Future for HandlerServiceFuture<F, T, R>
|
impl<F, T, R> Future for HandlerServiceFuture<F, T, R>
|
||||||
@ -133,7 +133,7 @@ where
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
let req = req.take().unwrap();
|
let req = req.take().unwrap();
|
||||||
let system_err: SystemError = err.into();
|
let system_err: SystemError = err.into();
|
||||||
let res: FlowyResponse = system_err.into();
|
let res: EventResponse = system_err.into();
|
||||||
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
|
return Poll::Ready(Ok(ServiceResponse::new(req, res)));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -178,7 +178,7 @@ macro_rules! tuple_from_req ({$tuple_type:ident, $(($n:tt, $T:ident)),+} => {
|
|||||||
type Error = SystemError;
|
type Error = SystemError;
|
||||||
type Future = $tuple_type<$($T),+>;
|
type Future = $tuple_type<$($T),+>;
|
||||||
|
|
||||||
fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(req: &EventRequest, payload: &mut Payload) -> Self::Future {
|
||||||
$tuple_type {
|
$tuple_type {
|
||||||
items: <($(Option<$T>,)+)>::default(),
|
items: <($(Option<$T>,)+)>::default(),
|
||||||
futs: FromRequestFutures($($T::from_request(req, payload),)+),
|
futs: FromRequestFutures($($T::from_request(req, payload),)+),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
request::{payload::Payload, FlowyRequest},
|
request::{payload::Payload, EventRequest},
|
||||||
response::{data::ResponseData, FlowyResponse},
|
response::EventResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Service<Request> {
|
pub trait Service<Request> {
|
||||||
@ -24,24 +24,24 @@ pub trait ServiceFactory<Request> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServiceRequest {
|
pub struct ServiceRequest {
|
||||||
req: FlowyRequest,
|
req: EventRequest,
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceRequest {
|
impl ServiceRequest {
|
||||||
pub fn new(req: FlowyRequest, payload: Payload) -> Self { Self { req, payload } }
|
pub fn new(req: EventRequest, payload: Payload) -> Self { Self { req, payload } }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_parts(self) -> (FlowyRequest, Payload) { (self.req, self.payload) }
|
pub fn into_parts(self) -> (EventRequest, Payload) { (self.req, self.payload) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServiceResponse<T = ResponseData> {
|
pub struct ServiceResponse {
|
||||||
request: FlowyRequest,
|
request: EventRequest,
|
||||||
response: FlowyResponse<T>,
|
response: EventResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ServiceResponse<T> {
|
impl ServiceResponse {
|
||||||
pub fn new(request: FlowyRequest, response: FlowyResponse<T>) -> Self { ServiceResponse { request, response } }
|
pub fn new(request: EventRequest, response: EventResponse) -> Self { ServiceResponse { request, response } }
|
||||||
|
|
||||||
pub fn into_parts(self) -> (FlowyRequest, FlowyResponse<T>) { (self.request, self.response) }
|
pub fn into_parts(self) -> (EventRequest, EventResponse) { (self.request, self.response) }
|
||||||
}
|
}
|
||||||
|
16
rust-lib/flowy-sys/tests/api/helper.rs
Normal file
16
rust-lib/flowy-sys/tests/api/helper.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn setup_env() {
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
INIT.call_once(|| {
|
||||||
|
std::env::set_var("RUST_LOG", "flowy_sys=trace,trace");
|
||||||
|
env_logger::init();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ExecutorAction {
|
||||||
|
command: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FlowySystemExecutor {}
|
2
rust-lib/flowy-sys/tests/api/main.rs
Normal file
2
rust-lib/flowy-sys/tests/api/main.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mod helper;
|
||||||
|
mod module_event;
|
29
rust-lib/flowy-sys/tests/api/module_event.rs
Normal file
29
rust-lib/flowy-sys/tests/api/module_event.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use crate::helper::*;
|
||||||
|
use flowy_sys::prelude::*;
|
||||||
|
|
||||||
|
pub async fn no_params() -> String { "no params function call".to_string() }
|
||||||
|
pub async fn one_params(s: String) -> String { "one params function call".to_string() }
|
||||||
|
pub async fn two_params(s1: String, s2: String) -> String { "two params function call".to_string() }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
setup_env();
|
||||||
|
|
||||||
|
let no_params_command = "no params".to_string();
|
||||||
|
let one_params_command = "one params".to_string();
|
||||||
|
let two_params_command = "two params".to_string();
|
||||||
|
FlowySystem::construct(|tx| {
|
||||||
|
vec![Module::new(tx.clone())
|
||||||
|
.event(no_params_command.clone(), no_params)
|
||||||
|
.event(one_params_command.clone(), one_params)
|
||||||
|
.event(two_params_command.clone(), two_params)]
|
||||||
|
})
|
||||||
|
.spawn(async {
|
||||||
|
let request = EventRequest::new(no_params_command.clone());
|
||||||
|
FlowySystem::current().sink(no_params_command, request);
|
||||||
|
|
||||||
|
FlowySystem::current().stop();
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
.unwrap();
|
||||||
|
}
|
@ -5,12 +5,14 @@ fn_single_line = true
|
|||||||
match_block_trailing_comma = true
|
match_block_trailing_comma = true
|
||||||
normalize_comments = true
|
normalize_comments = true
|
||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
merge_imports = true
|
|
||||||
use_field_init_shorthand = true
|
use_field_init_shorthand = true
|
||||||
use_try_shorthand = true
|
use_try_shorthand = true
|
||||||
normalize_doc_attributes = true
|
normalize_doc_attributes = true
|
||||||
report_todo = "Always"
|
report_todo = "Always"
|
||||||
report_fixme = "Always"
|
report_fixme = "Always"
|
||||||
imports_layout = "HorizontalVertical"
|
imports_layout = "HorizontalVertical"
|
||||||
|
merge_imports = true
|
||||||
|
reorder_modules = true
|
||||||
|
reorder_imports = true
|
||||||
enum_discrim_align_threshold = 20
|
enum_discrim_align_threshold = 20
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
Loading…
Reference in New Issue
Block a user