mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: enable dispatch event using single thread (#3828)
* refactor: lib dispatch * chore: type def * chore: type def * fix: local set spawn * chore: replace tokio spawn * chore: update log * chore: boxed event * chore: tauri lock
This commit is contained in:
@ -22,17 +22,18 @@ serde_json = {version = "1.0", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
serde_repr = { version = "0.1", optional = true }
|
||||
validator = "0.16.1"
|
||||
tracing = { version = "0.1"}
|
||||
|
||||
#optional crate
|
||||
bincode = { version = "1.3", optional = true}
|
||||
protobuf = {version = "2.28.0", optional = true}
|
||||
tracing = { version = "0.1"}
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.26", features = ["full"] }
|
||||
futures-util = "0.3.26"
|
||||
|
||||
[features]
|
||||
default = ["use_protobuf"]
|
||||
default = ["use_protobuf", ]
|
||||
use_serde = ["bincode", "serde_json", "serde", "serde_repr"]
|
||||
use_protobuf= ["protobuf"]
|
||||
single_thread = []
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::errors::{DispatchError, InternalError};
|
||||
use bytes::Bytes;
|
||||
|
||||
use crate::errors::{DispatchError, InternalError};
|
||||
|
||||
// To bytes
|
||||
pub trait ToBytes {
|
||||
fn into_bytes(self) -> Result<Bytes, DispatchError>;
|
||||
@ -26,21 +27,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(feature = "use_serde")]
|
||||
// impl<T> ToBytes for T
|
||||
// where
|
||||
// T: serde::Serialize,
|
||||
// {
|
||||
// fn into_bytes(self) -> Result<Bytes, DispatchError> {
|
||||
// match serde_json::to_string(&self.0) {
|
||||
// Ok(s) => Ok(Bytes::from(s)),
|
||||
// Err(e) => Err(InternalError::SerializeToBytes(format!("{:?}", e)).into()),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// From bytes
|
||||
|
||||
pub trait AFPluginFromBytes: Sized {
|
||||
fn parse_from_bytes(bytes: Bytes) -> Result<Self, DispatchError>;
|
||||
}
|
||||
|
@ -1,3 +1,13 @@
|
||||
use std::any::Any;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{future::Future, sync::Arc};
|
||||
|
||||
use derivative::*;
|
||||
use pin_project::pin_project;
|
||||
use tracing::event;
|
||||
|
||||
use crate::module::AFPluginStateMap;
|
||||
use crate::runtime::AFPluginRuntime;
|
||||
use crate::{
|
||||
errors::{DispatchError, Error, InternalError},
|
||||
@ -5,20 +15,76 @@ use crate::{
|
||||
response::AFPluginEventResponse,
|
||||
service::{AFPluginServiceFactory, Service},
|
||||
};
|
||||
use derivative::*;
|
||||
use futures_core::future::BoxFuture;
|
||||
use futures_util::task::Context;
|
||||
use pin_project::pin_project;
|
||||
use std::{future::Future, sync::Arc};
|
||||
use tokio::macros::support::{Pin, Poll};
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub trait AFConcurrent {}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
impl<T> AFConcurrent for T where T: ?Sized {}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub trait AFConcurrent: Send + Sync {}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
impl<T> AFConcurrent for T where T: Send + Sync {}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub type AFBoxFuture<'a, T> = futures_core::future::LocalBoxFuture<'a, T>;
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub type AFBoxFuture<'a, T> = futures_core::future::BoxFuture<'a, T>;
|
||||
|
||||
pub type AFStateMap = std::sync::Arc<AFPluginStateMap>;
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub(crate) fn downcast_owned<T: 'static>(boxed: AFBox) -> Option<T> {
|
||||
boxed.downcast().ok().map(|boxed| *boxed)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub(crate) fn downcast_owned<T: 'static + Send + Sync>(boxed: AFBox) -> Option<T> {
|
||||
boxed.downcast().ok().map(|boxed| *boxed)
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub(crate) type AFBox = Box<dyn Any>;
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub(crate) type AFBox = Box<dyn Any + Send + Sync>;
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub type BoxFutureCallback =
|
||||
Box<dyn FnOnce(AFPluginEventResponse) -> AFBoxFuture<'static, ()> + 'static>;
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub type BoxFutureCallback =
|
||||
Box<dyn FnOnce(AFPluginEventResponse) -> AFBoxFuture<'static, ()> + Send + Sync + 'static>;
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub fn af_spawn<T>(future: T) -> tokio::task::JoinHandle<T::Output>
|
||||
where
|
||||
T: Future + Send + 'static,
|
||||
T::Output: Send + 'static,
|
||||
{
|
||||
tokio::spawn(future)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub fn af_spawn<T>(future: T) -> tokio::task::JoinHandle<T::Output>
|
||||
where
|
||||
T: Future + Send + 'static,
|
||||
T::Output: Send + 'static,
|
||||
{
|
||||
tokio::spawn(future)
|
||||
}
|
||||
|
||||
pub struct AFPluginDispatcher {
|
||||
plugins: AFPluginMap,
|
||||
runtime: AFPluginRuntime,
|
||||
runtime: Arc<AFPluginRuntime>,
|
||||
}
|
||||
|
||||
impl AFPluginDispatcher {
|
||||
pub fn construct<F>(runtime: AFPluginRuntime, module_factory: F) -> AFPluginDispatcher
|
||||
pub fn construct<F>(runtime: Arc<AFPluginRuntime>, module_factory: F) -> AFPluginDispatcher
|
||||
where
|
||||
F: FnOnce() -> Vec<AFPlugin>,
|
||||
{
|
||||
@ -30,24 +96,24 @@ impl AFPluginDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn async_send<Req>(
|
||||
pub async fn async_send<Req>(
|
||||
dispatch: Arc<AFPluginDispatcher>,
|
||||
request: Req,
|
||||
) -> DispatchFuture<AFPluginEventResponse>
|
||||
) -> AFPluginEventResponse
|
||||
where
|
||||
Req: std::convert::Into<AFPluginRequest>,
|
||||
Req: Into<AFPluginRequest>,
|
||||
{
|
||||
AFPluginDispatcher::async_send_with_callback(dispatch, request, |_| Box::pin(async {}))
|
||||
AFPluginDispatcher::async_send_with_callback(dispatch, request, |_| Box::pin(async {})).await
|
||||
}
|
||||
|
||||
pub fn async_send_with_callback<Req, Callback>(
|
||||
pub async fn async_send_with_callback<Req, Callback>(
|
||||
dispatch: Arc<AFPluginDispatcher>,
|
||||
request: Req,
|
||||
callback: Callback,
|
||||
) -> DispatchFuture<AFPluginEventResponse>
|
||||
) -> AFPluginEventResponse
|
||||
where
|
||||
Req: std::convert::Into<AFPluginRequest>,
|
||||
Callback: FnOnce(AFPluginEventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync,
|
||||
Req: Into<AFPluginRequest>,
|
||||
Callback: FnOnce(AFPluginEventResponse) -> AFBoxFuture<'static, ()> + AFConcurrent + 'static,
|
||||
{
|
||||
let request: AFPluginRequest = request.into();
|
||||
let plugins = dispatch.plugins.clone();
|
||||
@ -57,7 +123,70 @@ impl AFPluginDispatcher {
|
||||
request,
|
||||
callback: Some(Box::new(callback)),
|
||||
};
|
||||
let join_handle = dispatch.runtime.spawn(async move {
|
||||
|
||||
// Spawns a future onto the runtime.
|
||||
//
|
||||
// This spawns the given future onto the runtime's executor, usually a
|
||||
// thread pool. The thread pool is then responsible for polling the future
|
||||
// until it completes.
|
||||
//
|
||||
// The provided future will start running in the background immediately
|
||||
// when `spawn` is called, even if you don't await the returned
|
||||
// `JoinHandle`.
|
||||
let handle = dispatch.runtime.spawn(async move {
|
||||
service.call(service_ctx).await.unwrap_or_else(|e| {
|
||||
tracing::error!("Dispatch runtime error: {:?}", e);
|
||||
InternalError::Other(format!("{:?}", e)).as_response()
|
||||
})
|
||||
});
|
||||
|
||||
let result = dispatch.runtime.run_until(handle).await;
|
||||
result.unwrap_or_else(|e| {
|
||||
let msg = format!("EVENT_DISPATCH join error: {:?}", e);
|
||||
tracing::error!("{}", msg);
|
||||
let error = InternalError::JoinError(msg);
|
||||
error.as_response()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn box_async_send<Req>(
|
||||
dispatch: Arc<AFPluginDispatcher>,
|
||||
request: Req,
|
||||
) -> DispatchFuture<AFPluginEventResponse>
|
||||
where
|
||||
Req: Into<AFPluginRequest> + 'static,
|
||||
{
|
||||
AFPluginDispatcher::boxed_async_send_with_callback(dispatch, request, |_| Box::pin(async {}))
|
||||
}
|
||||
|
||||
pub fn boxed_async_send_with_callback<Req, Callback>(
|
||||
dispatch: Arc<AFPluginDispatcher>,
|
||||
request: Req,
|
||||
callback: Callback,
|
||||
) -> DispatchFuture<AFPluginEventResponse>
|
||||
where
|
||||
Req: Into<AFPluginRequest> + 'static,
|
||||
Callback: FnOnce(AFPluginEventResponse) -> AFBoxFuture<'static, ()> + AFConcurrent + 'static,
|
||||
{
|
||||
let request: AFPluginRequest = request.into();
|
||||
let plugins = dispatch.plugins.clone();
|
||||
let service = Box::new(DispatchService { plugins });
|
||||
tracing::trace!("Async event: {:?}", &request.event);
|
||||
let service_ctx = DispatchContext {
|
||||
request,
|
||||
callback: Some(Box::new(callback)),
|
||||
};
|
||||
|
||||
// Spawns a future onto the runtime.
|
||||
//
|
||||
// This spawns the given future onto the runtime's executor, usually a
|
||||
// thread pool. The thread pool is then responsible for polling the future
|
||||
// until it completes.
|
||||
//
|
||||
// The provided future will start running in the background immediately
|
||||
// when `spawn` is called, even if you don't await the returned
|
||||
// `JoinHandle`.
|
||||
let handle = dispatch.runtime.spawn(async move {
|
||||
service.call(service_ctx).await.unwrap_or_else(|e| {
|
||||
tracing::error!("Dispatch runtime error: {:?}", e);
|
||||
InternalError::Other(format!("{:?}", e)).as_response()
|
||||
@ -66,7 +195,8 @@ impl AFPluginDispatcher {
|
||||
|
||||
DispatchFuture {
|
||||
fut: Box::pin(async move {
|
||||
join_handle.await.unwrap_or_else(|e| {
|
||||
let result = dispatch.runtime.run_until(handle).await;
|
||||
result.unwrap_or_else(|e| {
|
||||
let msg = format!("EVENT_DISPATCH join error: {:?}", e);
|
||||
tracing::error!("{}", msg);
|
||||
let error = InternalError::JoinError(msg);
|
||||
@ -76,44 +206,56 @@ impl AFPluginDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub fn sync_send(
|
||||
dispatch: Arc<AFPluginDispatcher>,
|
||||
request: AFPluginRequest,
|
||||
) -> AFPluginEventResponse {
|
||||
futures::executor::block_on(async {
|
||||
AFPluginDispatcher::async_send_with_callback(dispatch, request, |_| Box::pin(async {})).await
|
||||
})
|
||||
futures::executor::block_on(AFPluginDispatcher::async_send_with_callback(
|
||||
dispatch,
|
||||
request,
|
||||
|_| Box::pin(async {}),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn spawn<F>(&self, f: F)
|
||||
#[cfg(feature = "single_thread")]
|
||||
#[track_caller]
|
||||
pub fn spawn<F>(&self, future: F) -> tokio::task::JoinHandle<F::Output>
|
||||
where
|
||||
F: Future<Output = ()> + Send + 'static,
|
||||
F: Future + 'static,
|
||||
{
|
||||
self.runtime.spawn(f);
|
||||
self.runtime.spawn(future)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
#[track_caller]
|
||||
pub fn spawn<F>(&self, future: F) -> tokio::task::JoinHandle<F::Output>
|
||||
where
|
||||
F: Future + Send + 'static,
|
||||
<F as Future>::Output: Send + 'static,
|
||||
{
|
||||
self.runtime.spawn(future)
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub async fn run_until<F>(&self, future: F) -> F::Output
|
||||
where
|
||||
F: Future + 'static,
|
||||
{
|
||||
let handle = self.runtime.spawn(future);
|
||||
self.runtime.run_until(handle).await.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub async fn run_until<'a, F>(&self, future: F) -> F::Output
|
||||
where
|
||||
F: Future + Send + 'a,
|
||||
<F as Future>::Output: Send + 'a,
|
||||
{
|
||||
self.runtime.run_until(future).await
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct DispatchFuture<T: Send + Sync> {
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = T> + Sync + Send>>,
|
||||
}
|
||||
|
||||
impl<T> Future for DispatchFuture<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
Poll::Ready(futures_core::ready!(this.fut.poll(cx)))
|
||||
}
|
||||
}
|
||||
|
||||
pub type BoxFutureCallback =
|
||||
Box<dyn FnOnce(AFPluginEventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync>;
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct DispatchContext {
|
||||
@ -136,36 +278,37 @@ pub(crate) struct DispatchService {
|
||||
impl Service<DispatchContext> for DispatchService {
|
||||
type Response = AFPluginEventResponse;
|
||||
type Error = DispatchError;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
type Future = AFBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "use_tracing",
|
||||
tracing::instrument(name = "DispatchService", level = "debug", skip(self, ctx))
|
||||
)]
|
||||
#[tracing::instrument(name = "DispatchService", level = "debug", skip(self, ctx))]
|
||||
fn call(&self, ctx: DispatchContext) -> Self::Future {
|
||||
let module_map = self.plugins.clone();
|
||||
let (request, callback) = ctx.into_parts();
|
||||
|
||||
Box::pin(async move {
|
||||
let result = {
|
||||
// print_module_map_info(&module_map);
|
||||
match module_map.get(&request.event) {
|
||||
Some(module) => {
|
||||
tracing::trace!("Handle event: {:?} by {:?}", &request.event, module.name);
|
||||
event!(
|
||||
tracing::Level::TRACE,
|
||||
"Handle event: {:?} by {:?}",
|
||||
&request.event,
|
||||
module.name
|
||||
);
|
||||
let fut = module.new_service(());
|
||||
let service_fut = fut.await?.call(request);
|
||||
service_fut.await
|
||||
},
|
||||
None => {
|
||||
let msg = format!("Can not find the event handler. {:?}", request);
|
||||
tracing::error!("{}", msg);
|
||||
event!(tracing::Level::ERROR, "{}", msg);
|
||||
Err(InternalError::HandleNotFound(msg).into())
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let response = result.unwrap_or_else(|e| e.into());
|
||||
tracing::trace!("Dispatch result: {:?}", response);
|
||||
event!(tracing::Level::TRACE, "Dispatch result: {:?}", response);
|
||||
if let Some(callback) = callback {
|
||||
callback(response.clone()).await;
|
||||
}
|
||||
@ -190,3 +333,21 @@ fn print_plugins(plugins: &AFPluginMap) {
|
||||
tracing::info!("Event: {:?} plugin : {:?}", k, v.name);
|
||||
})
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct DispatchFuture<T: AFConcurrent> {
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = T> + 'static>>,
|
||||
}
|
||||
|
||||
impl<T> Future for DispatchFuture<T>
|
||||
where
|
||||
T: AFConcurrent + 'static,
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.as_mut().project();
|
||||
Poll::Ready(futures_core::ready!(this.fut.poll(cx)))
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
use std::fmt;
|
||||
|
||||
use bytes::Bytes;
|
||||
use dyn_clone::DynClone;
|
||||
use tokio::{sync::mpsc::error::SendError, task::JoinError};
|
||||
|
||||
use crate::prelude::AFConcurrent;
|
||||
use crate::{
|
||||
byte_trait::AFPluginFromBytes,
|
||||
request::AFPluginEventRequest,
|
||||
response::{AFPluginEventResponse, ResponseBuilder},
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use dyn_clone::DynClone;
|
||||
|
||||
use std::fmt;
|
||||
use tokio::{sync::mpsc::error::SendError, task::JoinError};
|
||||
|
||||
pub trait Error: fmt::Debug + DynClone + Send + Sync {
|
||||
pub trait Error: fmt::Debug + DynClone + AFConcurrent {
|
||||
fn as_response(&self) -> AFPluginEventResponse;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
collections::HashMap,
|
||||
};
|
||||
use std::{any::TypeId, collections::HashMap};
|
||||
|
||||
use crate::prelude::{downcast_owned, AFBox, AFConcurrent};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct AFPluginStateMap(HashMap<TypeId, Box<dyn Any + Sync + Send>>);
|
||||
pub struct AFPluginStateMap(HashMap<TypeId, AFBox>);
|
||||
|
||||
impl AFPluginStateMap {
|
||||
#[inline]
|
||||
@ -14,7 +13,7 @@ impl AFPluginStateMap {
|
||||
|
||||
pub fn insert<T>(&mut self, val: T) -> Option<T>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
T: 'static + AFConcurrent,
|
||||
{
|
||||
self
|
||||
.0
|
||||
@ -24,14 +23,14 @@ impl AFPluginStateMap {
|
||||
|
||||
pub fn remove<T>(&mut self) -> Option<T>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
T: 'static + AFConcurrent,
|
||||
{
|
||||
self.0.remove(&TypeId::of::<T>()).and_then(downcast_owned)
|
||||
}
|
||||
|
||||
pub fn get<T>(&self) -> Option<&T>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
T: 'static,
|
||||
{
|
||||
self
|
||||
.0
|
||||
@ -41,7 +40,7 @@ impl AFPluginStateMap {
|
||||
|
||||
pub fn get_mut<T>(&mut self) -> Option<&mut T>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
T: 'static + AFConcurrent,
|
||||
{
|
||||
self
|
||||
.0
|
||||
@ -51,7 +50,7 @@ impl AFPluginStateMap {
|
||||
|
||||
pub fn contains<T>(&self) -> bool
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
T: 'static + AFConcurrent,
|
||||
{
|
||||
self.0.contains_key(&TypeId::of::<T>())
|
||||
}
|
||||
@ -60,7 +59,3 @@ impl AFPluginStateMap {
|
||||
self.0.extend(other.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn downcast_owned<T: 'static + Send + Sync>(boxed: Box<dyn Any + Send + Sync>) -> Option<T> {
|
||||
boxed.downcast().ok().map(|boxed| *boxed)
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
use std::{any::type_name, ops::Deref, sync::Arc};
|
||||
|
||||
use crate::prelude::AFConcurrent;
|
||||
use crate::{
|
||||
errors::{DispatchError, InternalError},
|
||||
request::{payload::Payload, AFPluginEventRequest, FromAFPluginRequest},
|
||||
util::ready::{ready, Ready},
|
||||
};
|
||||
use std::{any::type_name, ops::Deref, sync::Arc};
|
||||
|
||||
pub struct AFPluginState<T: ?Sized + Send + Sync>(Arc<T>);
|
||||
pub struct AFPluginState<T: ?Sized + AFConcurrent>(Arc<T>);
|
||||
|
||||
impl<T> AFPluginState<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
T: AFConcurrent,
|
||||
{
|
||||
pub fn new(data: T) -> Self {
|
||||
AFPluginState(Arc::new(data))
|
||||
@ -22,7 +24,7 @@ where
|
||||
|
||||
impl<T> Deref for AFPluginState<T>
|
||||
where
|
||||
T: ?Sized + Send + Sync,
|
||||
T: ?Sized + AFConcurrent,
|
||||
{
|
||||
type Target = Arc<T>;
|
||||
|
||||
@ -33,7 +35,7 @@ where
|
||||
|
||||
impl<T> Clone for AFPluginState<T>
|
||||
where
|
||||
T: ?Sized + Send + Sync,
|
||||
T: ?Sized + AFConcurrent,
|
||||
{
|
||||
fn clone(&self) -> AFPluginState<T> {
|
||||
AFPluginState(self.0.clone())
|
||||
@ -42,7 +44,7 @@ where
|
||||
|
||||
impl<T> From<Arc<T>> for AFPluginState<T>
|
||||
where
|
||||
T: ?Sized + Send + Sync,
|
||||
T: ?Sized + AFConcurrent,
|
||||
{
|
||||
fn from(arc: Arc<T>) -> Self {
|
||||
AFPluginState(arc)
|
||||
@ -51,7 +53,7 @@ where
|
||||
|
||||
impl<T> FromAFPluginRequest for AFPluginState<T>
|
||||
where
|
||||
T: ?Sized + Send + Sync + 'static,
|
||||
T: ?Sized + AFConcurrent + 'static,
|
||||
{
|
||||
type Error = DispatchError;
|
||||
type Future = Ready<Result<Self, DispatchError>>;
|
||||
@ -59,7 +61,7 @@ where
|
||||
#[inline]
|
||||
fn from_request(req: &AFPluginEventRequest, _: &mut Payload) -> Self::Future {
|
||||
if let Some(state) = req.get_state::<AFPluginState<T>>() {
|
||||
ready(Ok(state.clone()))
|
||||
ready(Ok(state))
|
||||
} else {
|
||||
let msg = format!(
|
||||
"Failed to get the plugin state of type: {}",
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
pub use container::*;
|
||||
pub use data::*;
|
||||
pub use module::*;
|
||||
|
@ -9,15 +9,15 @@ use std::{
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use futures_core::future::BoxFuture;
|
||||
use futures_core::ready;
|
||||
use nanoid::nanoid;
|
||||
use pin_project::pin_project;
|
||||
|
||||
use crate::dispatcher::AFConcurrent;
|
||||
use crate::prelude::{AFBoxFuture, AFStateMap};
|
||||
use crate::service::AFPluginHandler;
|
||||
use crate::{
|
||||
errors::{DispatchError, InternalError},
|
||||
module::{container::AFPluginStateMap, AFPluginState},
|
||||
request::{payload::Payload, AFPluginEventRequest, FromAFPluginRequest},
|
||||
response::{AFPluginEventResponse, AFPluginResponder},
|
||||
service::{
|
||||
@ -58,7 +58,7 @@ pub struct AFPlugin {
|
||||
pub name: String,
|
||||
|
||||
/// a list of `AFPluginState` that the plugin registers. The state can be read by the plugin's handler.
|
||||
states: Arc<AFPluginStateMap>,
|
||||
states: AFStateMap,
|
||||
|
||||
/// Contains a list of factories that are used to generate the services used to handle the passed-in
|
||||
/// `ServiceRequest`.
|
||||
@ -72,7 +72,7 @@ impl std::default::Default for AFPlugin {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "".to_owned(),
|
||||
states: Arc::new(AFPluginStateMap::new()),
|
||||
states: Default::default(),
|
||||
event_service_factory: Arc::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
@ -88,11 +88,10 @@ impl AFPlugin {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn state<D: 'static + Send + Sync>(mut self, data: D) -> Self {
|
||||
pub fn state<D: AFConcurrent + 'static>(mut self, data: D) -> Self {
|
||||
Arc::get_mut(&mut self.states)
|
||||
.unwrap()
|
||||
.insert(AFPluginState::new(data));
|
||||
|
||||
.insert(crate::module::AFPluginState::new(data));
|
||||
self
|
||||
}
|
||||
|
||||
@ -100,9 +99,9 @@ impl AFPlugin {
|
||||
pub fn event<E, H, T, R>(mut self, event: E, handler: H) -> Self
|
||||
where
|
||||
H: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest + 'static + Send + Sync,
|
||||
<T as FromAFPluginRequest>::Future: Sync + Send,
|
||||
R: Future + 'static + Send + Sync,
|
||||
T: FromAFPluginRequest + 'static + AFConcurrent,
|
||||
<T as FromAFPluginRequest>::Future: AFConcurrent,
|
||||
R: Future + AFConcurrent + 'static,
|
||||
R::Output: AFPluginResponder + 'static,
|
||||
E: Eq + Hash + Debug + Clone + Display,
|
||||
{
|
||||
@ -169,7 +168,7 @@ impl AFPluginServiceFactory<AFPluginRequest> for AFPlugin {
|
||||
type Error = DispatchError;
|
||||
type Service = BoxService<AFPluginRequest, Self::Response, Self::Error>;
|
||||
type Context = ();
|
||||
type Future = BoxFuture<'static, Result<Self::Service, Self::Error>>;
|
||||
type Future = AFBoxFuture<'static, Result<Self::Service, Self::Error>>;
|
||||
|
||||
fn new_service(&self, _cfg: Self::Context) -> Self::Future {
|
||||
let services = self.event_service_factory.clone();
|
||||
@ -185,13 +184,14 @@ pub struct AFPluginService {
|
||||
services: Arc<
|
||||
HashMap<AFPluginEvent, BoxServiceFactory<(), ServiceRequest, ServiceResponse, DispatchError>>,
|
||||
>,
|
||||
states: Arc<AFPluginStateMap>,
|
||||
states: AFStateMap,
|
||||
}
|
||||
|
||||
impl Service<AFPluginRequest> for AFPluginService {
|
||||
type Response = AFPluginEventResponse;
|
||||
type Error = DispatchError;
|
||||
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
type Future = AFBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn call(&self, request: AFPluginRequest) -> Self::Future {
|
||||
let AFPluginRequest { id, event, payload } = request;
|
||||
@ -224,7 +224,7 @@ impl Service<AFPluginRequest> for AFPluginService {
|
||||
#[pin_project]
|
||||
pub struct AFPluginServiceFuture {
|
||||
#[pin]
|
||||
fut: BoxFuture<'static, Result<ServiceResponse, DispatchError>>,
|
||||
fut: AFBoxFuture<'static, Result<ServiceResponse, DispatchError>>,
|
||||
}
|
||||
|
||||
impl Future for AFPluginServiceFuture {
|
||||
|
@ -1,9 +1,7 @@
|
||||
use bytes::Bytes;
|
||||
use std::{fmt, fmt::Formatter};
|
||||
|
||||
pub enum PayloadError {}
|
||||
use bytes::Bytes;
|
||||
|
||||
// TODO: support stream data
|
||||
#[derive(Clone)]
|
||||
#[cfg_attr(feature = "use_serde", derive(serde::Serialize))]
|
||||
pub enum Payload {
|
||||
|
@ -1,47 +1,48 @@
|
||||
use std::future::Future;
|
||||
|
||||
use crate::{
|
||||
errors::{DispatchError, InternalError},
|
||||
module::{AFPluginEvent, AFPluginStateMap},
|
||||
request::payload::Payload,
|
||||
util::ready::{ready, Ready},
|
||||
};
|
||||
use derivative::*;
|
||||
use futures_core::ready;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use derivative::*;
|
||||
use futures_core::ready;
|
||||
|
||||
use crate::prelude::{AFConcurrent, AFStateMap};
|
||||
use crate::{
|
||||
errors::{DispatchError, InternalError},
|
||||
module::AFPluginEvent,
|
||||
request::payload::Payload,
|
||||
util::ready::{ready, Ready},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Derivative)]
|
||||
pub struct AFPluginEventRequest {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) id: String,
|
||||
pub(crate) event: AFPluginEvent,
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub(crate) states: Arc<AFPluginStateMap>,
|
||||
pub(crate) states: AFStateMap,
|
||||
}
|
||||
|
||||
impl AFPluginEventRequest {
|
||||
pub fn new<E>(id: String, event: E, module_data: Arc<AFPluginStateMap>) -> AFPluginEventRequest
|
||||
pub fn new<E>(id: String, event: E, states: AFStateMap) -> AFPluginEventRequest
|
||||
where
|
||||
E: Into<AFPluginEvent>,
|
||||
{
|
||||
Self {
|
||||
id,
|
||||
event: event.into(),
|
||||
states: module_data,
|
||||
states,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_state<T: 'static>(&self) -> Option<&T>
|
||||
pub fn get_state<T>(&self) -> Option<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
T: AFConcurrent + 'static + Clone,
|
||||
{
|
||||
if let Some(data) = self.states.get::<T>() {
|
||||
return Some(data);
|
||||
return Some(data.clone());
|
||||
}
|
||||
|
||||
None
|
||||
|
@ -1,24 +1,117 @@
|
||||
use std::{io, thread};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
|
||||
use tokio::runtime;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
pub type AFPluginRuntime = tokio::runtime::Runtime;
|
||||
pub struct AFPluginRuntime {
|
||||
inner: Runtime,
|
||||
#[cfg(feature = "single_thread")]
|
||||
local: tokio::task::LocalSet,
|
||||
}
|
||||
|
||||
pub fn tokio_default_runtime() -> io::Result<AFPluginRuntime> {
|
||||
impl Display for AFPluginRuntime {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
if cfg!(feature = "single_thread") {
|
||||
write!(f, "Runtime(single_thread)")
|
||||
} else {
|
||||
write!(f, "Runtime(multi_thread)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AFPluginRuntime {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let inner = default_tokio_runtime()?;
|
||||
Ok(Self {
|
||||
inner,
|
||||
#[cfg(feature = "single_thread")]
|
||||
local: tokio::task::LocalSet::new(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
#[track_caller]
|
||||
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
|
||||
where
|
||||
F: Future + 'static,
|
||||
{
|
||||
self.local.spawn_local(future)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
#[track_caller]
|
||||
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
|
||||
where
|
||||
F: Future + Send + 'static,
|
||||
<F as Future>::Output: Send + 'static,
|
||||
{
|
||||
self.inner.spawn(future)
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub async fn run_until<F>(&self, future: F) -> F::Output
|
||||
where
|
||||
F: Future,
|
||||
{
|
||||
self.local.run_until(future).await
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub async fn run_until<F>(&self, future: F) -> F::Output
|
||||
where
|
||||
F: Future,
|
||||
{
|
||||
future.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
#[track_caller]
|
||||
pub fn block_on<F>(&self, f: F) -> F::Output
|
||||
where
|
||||
F: Future,
|
||||
{
|
||||
self.local.block_on(&self.inner, f)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
#[track_caller]
|
||||
pub fn block_on<F>(&self, f: F) -> F::Output
|
||||
where
|
||||
F: Future,
|
||||
{
|
||||
self.inner.block_on(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub fn default_tokio_runtime() -> io::Result<Runtime> {
|
||||
runtime::Builder::new_current_thread()
|
||||
.thread_name("dispatch-rt-st")
|
||||
.enable_io()
|
||||
.enable_time()
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub fn default_tokio_runtime() -> io::Result<Runtime> {
|
||||
runtime::Builder::new_multi_thread()
|
||||
.thread_name("dispatch-rt")
|
||||
.thread_name("dispatch-rt-mt")
|
||||
.enable_io()
|
||||
.enable_time()
|
||||
.on_thread_start(move || {
|
||||
tracing::trace!(
|
||||
"{:?} thread started: thread_id= {}",
|
||||
thread::current(),
|
||||
std::thread::current(),
|
||||
thread_id::get()
|
||||
);
|
||||
})
|
||||
.on_thread_stop(move || {
|
||||
tracing::trace!(
|
||||
"{:?} thread stopping: thread_id= {}",
|
||||
thread::current(),
|
||||
std::thread::current(),
|
||||
thread_id::get(),
|
||||
);
|
||||
})
|
||||
|
@ -1,21 +1,33 @@
|
||||
use crate::prelude::{AFBoxFuture, AFConcurrent};
|
||||
use crate::service::{AFPluginServiceFactory, Service};
|
||||
use futures_core::future::BoxFuture;
|
||||
|
||||
pub fn factory<SF, Req>(factory: SF) -> BoxServiceFactory<SF::Context, Req, SF::Response, SF::Error>
|
||||
where
|
||||
SF: AFPluginServiceFactory<Req> + 'static + Sync + Send,
|
||||
SF: AFPluginServiceFactory<Req> + 'static + AFConcurrent,
|
||||
Req: 'static,
|
||||
SF::Response: 'static,
|
||||
SF::Service: 'static,
|
||||
SF::Future: 'static,
|
||||
SF::Error: 'static + Send + Sync,
|
||||
<SF as AFPluginServiceFactory<Req>>::Service: Sync + Send,
|
||||
<<SF as AFPluginServiceFactory<Req>>::Service as Service<Req>>::Future: Send + Sync,
|
||||
<SF as AFPluginServiceFactory<Req>>::Future: Send + Sync,
|
||||
SF::Error: 'static,
|
||||
<SF as AFPluginServiceFactory<Req>>::Service: AFConcurrent,
|
||||
<<SF as AFPluginServiceFactory<Req>>::Service as Service<Req>>::Future: AFConcurrent,
|
||||
<SF as AFPluginServiceFactory<Req>>::Future: AFConcurrent,
|
||||
{
|
||||
BoxServiceFactory(Box::new(FactoryWrapper(factory)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
type Inner<Cfg, Req, Res, Err> = Box<
|
||||
dyn AFPluginServiceFactory<
|
||||
Req,
|
||||
Context = Cfg,
|
||||
Response = Res,
|
||||
Error = Err,
|
||||
Service = BoxService<Req, Res, Err>,
|
||||
Future = AFBoxFuture<'static, Result<BoxService<Req, Res, Err>, Err>>,
|
||||
>,
|
||||
>;
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
type Inner<Cfg, Req, Res, Err> = Box<
|
||||
dyn AFPluginServiceFactory<
|
||||
Req,
|
||||
@ -23,9 +35,9 @@ type Inner<Cfg, Req, Res, Err> = Box<
|
||||
Response = Res,
|
||||
Error = Err,
|
||||
Service = BoxService<Req, Res, Err>,
|
||||
Future = BoxFuture<'static, Result<BoxService<Req, Res, Err>, Err>>,
|
||||
> + Sync
|
||||
+ Send,
|
||||
Future = AFBoxFuture<'static, Result<BoxService<Req, Res, Err>, Err>>,
|
||||
> + Send
|
||||
+ Sync,
|
||||
>;
|
||||
|
||||
pub struct BoxServiceFactory<Cfg, Req, Res, Err>(Inner<Cfg, Req, Res, Err>);
|
||||
@ -39,15 +51,21 @@ where
|
||||
type Error = Err;
|
||||
type Service = BoxService<Req, Res, Err>;
|
||||
type Context = Cfg;
|
||||
type Future = BoxFuture<'static, Result<Self::Service, Self::Error>>;
|
||||
type Future = AFBoxFuture<'static, Result<Self::Service, Self::Error>>;
|
||||
|
||||
fn new_service(&self, cfg: Cfg) -> Self::Future {
|
||||
self.0.new_service(cfg)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "single_thread")]
|
||||
pub type BoxService<Req, Res, Err> = Box<
|
||||
dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<'static, Result<Res, Err>>>
|
||||
dyn Service<Req, Response = Res, Error = Err, Future = AFBoxFuture<'static, Result<Res, Err>>>,
|
||||
>;
|
||||
|
||||
#[cfg(not(feature = "single_thread"))]
|
||||
pub type BoxService<Req, Res, Err> = Box<
|
||||
dyn Service<Req, Response = Res, Error = Err, Future = AFBoxFuture<'static, Result<Res, Err>>>
|
||||
+ Sync
|
||||
+ Send,
|
||||
>;
|
||||
@ -88,11 +106,11 @@ impl<S> ServiceWrapper<S> {
|
||||
impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
|
||||
where
|
||||
S: Service<Req, Response = Res, Error = Err>,
|
||||
S::Future: 'static + Send + Sync,
|
||||
S::Future: 'static + AFConcurrent,
|
||||
{
|
||||
type Response = Res;
|
||||
type Error = Err;
|
||||
type Future = BoxFuture<'static, Result<Res, Err>>;
|
||||
type Future = AFBoxFuture<'static, Result<Res, Err>>;
|
||||
|
||||
fn call(&self, req: Req) -> Self::Future {
|
||||
Box::pin(self.inner.call(req))
|
||||
@ -108,15 +126,15 @@ where
|
||||
Err: 'static,
|
||||
SF: AFPluginServiceFactory<Req, Context = Cfg, Response = Res, Error = Err>,
|
||||
SF::Future: 'static,
|
||||
SF::Service: 'static + Send + Sync,
|
||||
<<SF as AFPluginServiceFactory<Req>>::Service as Service<Req>>::Future: Send + Sync + 'static,
|
||||
<SF as AFPluginServiceFactory<Req>>::Future: Send + Sync,
|
||||
SF::Service: 'static + AFConcurrent,
|
||||
<<SF as AFPluginServiceFactory<Req>>::Service as Service<Req>>::Future: AFConcurrent + 'static,
|
||||
<SF as AFPluginServiceFactory<Req>>::Future: AFConcurrent,
|
||||
{
|
||||
type Response = Res;
|
||||
type Error = Err;
|
||||
type Service = BoxService<Req, Res, Err>;
|
||||
type Context = Cfg;
|
||||
type Future = BoxFuture<'static, Result<Self::Service, Self::Error>>;
|
||||
type Future = AFBoxFuture<'static, Result<Self::Service, Self::Error>>;
|
||||
|
||||
fn new_service(&self, cfg: Cfg) -> Self::Future {
|
||||
let f = self.0.new_service(cfg);
|
||||
|
@ -8,18 +8,19 @@ use std::{
|
||||
use futures_core::ready;
|
||||
use pin_project::pin_project;
|
||||
|
||||
use crate::dispatcher::AFConcurrent;
|
||||
use crate::{
|
||||
errors::DispatchError,
|
||||
request::{payload::Payload, AFPluginEventRequest, FromAFPluginRequest},
|
||||
request::{AFPluginEventRequest, FromAFPluginRequest},
|
||||
response::{AFPluginEventResponse, AFPluginResponder},
|
||||
service::{AFPluginServiceFactory, Service, ServiceRequest, ServiceResponse},
|
||||
util::ready::*,
|
||||
};
|
||||
|
||||
/// A closure that is run every time for the specified plugin event
|
||||
pub trait AFPluginHandler<T, R>: Clone + 'static + Sync + Send
|
||||
pub trait AFPluginHandler<T, R>: Clone + AFConcurrent + 'static
|
||||
where
|
||||
R: Future + Send + Sync,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
fn call(&self, param: T) -> R;
|
||||
@ -29,7 +30,7 @@ pub struct AFPluginHandlerService<H, T, R>
|
||||
where
|
||||
H: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest,
|
||||
R: Future + Sync + Send,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
handler: H,
|
||||
@ -40,7 +41,7 @@ impl<H, T, R> AFPluginHandlerService<H, T, R>
|
||||
where
|
||||
H: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest,
|
||||
R: Future + Sync + Send,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
pub fn new(handler: H) -> Self {
|
||||
@ -55,7 +56,7 @@ impl<H, T, R> Clone for AFPluginHandlerService<H, T, R>
|
||||
where
|
||||
H: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest,
|
||||
R: Future + Sync + Send,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
@ -70,7 +71,7 @@ impl<F, T, R> AFPluginServiceFactory<ServiceRequest> for AFPluginHandlerService<
|
||||
where
|
||||
F: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest,
|
||||
R: Future + Send + Sync,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
type Response = ServiceResponse;
|
||||
@ -88,7 +89,7 @@ impl<H, T, R> Service<ServiceRequest> for AFPluginHandlerService<H, T, R>
|
||||
where
|
||||
H: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest,
|
||||
R: Future + Sync + Send,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
type Response = ServiceResponse;
|
||||
@ -107,7 +108,7 @@ pub enum HandlerServiceFuture<H, T, R>
|
||||
where
|
||||
H: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest,
|
||||
R: Future + Sync + Send,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
Extract(#[pin] T::Future, Option<AFPluginEventRequest>, H),
|
||||
@ -118,7 +119,7 @@ impl<F, T, R> Future for HandlerServiceFuture<F, T, R>
|
||||
where
|
||||
F: AFPluginHandler<T, R>,
|
||||
T: FromAFPluginRequest,
|
||||
R: Future + Sync + Send,
|
||||
R: Future + AFConcurrent,
|
||||
R::Output: AFPluginResponder,
|
||||
{
|
||||
type Output = Result<ServiceResponse, DispatchError>;
|
||||
@ -154,8 +155,8 @@ where
|
||||
|
||||
macro_rules! factory_tuple ({ $($param:ident)* } => {
|
||||
impl<Func, $($param,)* Res> AFPluginHandler<($($param,)*), Res> for Func
|
||||
where Func: Fn($($param),*) -> Res + Clone + 'static + Sync + Send,
|
||||
Res: Future + Sync + Send,
|
||||
where Func: Fn($($param),*) -> Res + Clone + 'static + AFConcurrent,
|
||||
Res: Future + AFConcurrent,
|
||||
Res::Output: AFPluginResponder,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
@ -181,7 +182,7 @@ macro_rules! tuple_from_req ({$tuple_type:ident, $(($n:tt, $T:ident)),+} => {
|
||||
type Error = DispatchError;
|
||||
type Future = $tuple_type<$($T),+>;
|
||||
|
||||
fn from_request(req: &AFPluginEventRequest, payload: &mut Payload) -> Self::Future {
|
||||
fn from_request(req: &AFPluginEventRequest, payload: &mut crate::prelude::Payload) -> Self::Future {
|
||||
$tuple_type {
|
||||
items: <($(Option<$T>,)+)>::default(),
|
||||
futs: FromRequestFutures($($T::from_request(req, payload),)+),
|
||||
|
@ -1,7 +1,8 @@
|
||||
use lib_dispatch::prelude::*;
|
||||
use lib_dispatch::runtime::tokio_default_runtime;
|
||||
use std::sync::Arc;
|
||||
|
||||
use lib_dispatch::prelude::*;
|
||||
use lib_dispatch::runtime::AFPluginRuntime;
|
||||
|
||||
pub async fn hello() -> String {
|
||||
"say hello".to_string()
|
||||
}
|
||||
@ -9,7 +10,7 @@ pub async fn hello() -> String {
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let event = "1";
|
||||
let runtime = tokio_default_runtime().unwrap();
|
||||
let runtime = Arc::new(AFPluginRuntime::new().unwrap());
|
||||
let dispatch = Arc::new(AFPluginDispatcher::construct(runtime, || {
|
||||
vec![AFPlugin::new().event(event, hello)]
|
||||
}));
|
||||
|
Reference in New Issue
Block a user