AppFlowy/frontend/rust-lib/lib-dispatch/src/dispatcher.rs

186 lines
5.8 KiB
Rust
Raw Normal View History

use crate::runtime::AFPluginRuntime;
use crate::{
errors::{DispatchError, Error, InternalError},
module::{as_plugin_map, AFPlugin, AFPluginMap, AFPluginRequest},
response::EventResponse,
service::{AFPluginServiceFactory, Service},
};
use derivative::*;
use futures_core::future::BoxFuture;
2021-07-03 06:14:10 +00:00
use futures_util::task::Context;
use pin_project::pin_project;
2021-09-04 07:12:53 +00:00
use std::{future::Future, sync::Arc};
2021-07-03 14:24:02 +00:00
use tokio::macros::support::{Pin, Poll};
2022-06-27 15:15:43 +00:00
pub struct AFPluginDispatcher {
plugins: AFPluginMap,
runtime: AFPluginRuntime,
}
impl AFPluginDispatcher {
pub fn construct<F>(runtime: AFPluginRuntime, module_factory: F) -> AFPluginDispatcher
where
F: FnOnce() -> Vec<AFPlugin>,
{
let plugins = module_factory();
tracing::trace!("{}", plugin_info(&plugins));
AFPluginDispatcher {
plugins: as_plugin_map(plugins),
runtime,
}
}
pub fn async_send<Req>(dispatch: Arc<AFPluginDispatcher>, request: Req) -> DispatchFuture<EventResponse>
2021-07-16 15:18:12 +00:00
where
Req: std::convert::Into<AFPluginRequest>,
2021-07-16 15:18:12 +00:00
{
AFPluginDispatcher::async_send_with_callback(dispatch, request, |_| Box::pin(async {}))
2021-07-16 15:18:12 +00:00
}
2021-09-04 07:12:53 +00:00
pub fn async_send_with_callback<Req, Callback>(
dispatch: Arc<AFPluginDispatcher>,
2021-09-04 07:12:53 +00:00
request: Req,
callback: Callback,
) -> DispatchFuture<EventResponse>
where
Req: std::convert::Into<AFPluginRequest>,
Callback: FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync,
{
let request: AFPluginRequest = request.into();
let plugins = dispatch.plugins.clone();
let service = Box::new(DispatchService { plugins });
2021-11-03 07:37:38 +00:00
tracing::trace!("Async event: {:?}", &request.event);
2021-09-04 07:12:53 +00:00
let service_ctx = DispatchContext {
request,
callback: Some(Box::new(callback)),
};
let join_handle = dispatch.runtime.spawn(async move {
2022-08-15 14:40:54 +00:00
service.call(service_ctx).await.unwrap_or_else(|e| {
tracing::error!("Dispatch runtime error: {:?}", e);
InternalError::Other(format!("{:?}", e)).as_response()
})
2021-09-04 07:12:53 +00:00
});
2021-09-04 07:12:53 +00:00
DispatchFuture {
fut: Box::pin(async move {
join_handle.await.unwrap_or_else(|e| {
2022-08-15 14:40:54 +00:00
let msg = format!("EVENT_DISPATCH join error: {:?}", e);
tracing::error!("{}", msg);
let error = InternalError::JoinError(msg);
2021-09-04 07:12:53 +00:00
error.as_response()
})
}),
}
}
pub fn sync_send(dispatch: Arc<AFPluginDispatcher>, request: AFPluginRequest) -> EventResponse {
futures::executor::block_on(async {
AFPluginDispatcher::async_send_with_callback(dispatch, request, |_| Box::pin(async {})).await
})
}
2021-09-16 15:07:15 +00:00
pub fn spawn<F>(&self, f: F)
where
F: Future<Output = ()> + Send + 'static,
{
self.runtime.spawn(f);
}
}
2021-07-03 06:14:10 +00:00
#[pin_project]
pub struct DispatchFuture<T: Send + Sync> {
2021-07-03 06:14:10 +00:00
#[pin]
pub fut: Pin<Box<dyn Future<Output = T> + Sync + Send>>,
2021-07-03 06:14:10 +00:00
}
impl<T> Future for DispatchFuture<T>
where
T: Send + Sync,
{
type Output = T;
2021-07-03 06:14:10 +00:00
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.as_mut().project();
2021-11-27 11:19:41 +00:00
Poll::Ready(futures_core::ready!(this.fut.poll(cx)))
2021-07-03 06:14:10 +00:00
}
}
pub type BoxFutureCallback = Box<dyn FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync>;
#[derive(Derivative)]
#[derivative(Debug)]
pub struct DispatchContext {
pub request: AFPluginRequest,
#[derivative(Debug = "ignore")]
2021-07-03 06:14:10 +00:00
pub callback: Option<BoxFutureCallback>,
}
impl DispatchContext {
pub(crate) fn into_parts(self) -> (AFPluginRequest, Option<BoxFutureCallback>) {
let DispatchContext { request, callback } = self;
(request, callback)
2021-07-03 06:14:10 +00:00
}
}
pub(crate) struct DispatchService {
pub(crate) plugins: AFPluginMap,
}
impl Service<DispatchContext> for DispatchService {
type Response = EventResponse;
type Error = DispatchError;
type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
2021-07-03 13:40:13 +00:00
#[cfg_attr(
feature = "use_tracing",
tracing::instrument(name = "DispatchService", level = "debug", skip(self, ctx))
2021-07-03 13:40:13 +00:00
)]
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 = {
2021-07-21 14:41:44 +00:00
// print_module_map_info(&module_map);
2021-07-09 09:47:15 +00:00
match module_map.get(&request.event) {
Some(module) => {
2022-04-26 23:58:40 +00:00
tracing::trace!("Handle event: {:?} by {:?}", &request.event, module.name);
let fut = module.new_service(());
let service_fut = fut.await?.call(request);
service_fut.await
2022-01-23 04:14:00 +00:00
}
None => {
2021-07-08 13:23:44 +00:00
let msg = format!("Can not find the event handler. {:?}", request);
2022-04-26 23:58:40 +00:00
tracing::error!("{}", msg);
Err(InternalError::HandleNotFound(msg).into())
2022-01-23 04:14:00 +00:00
}
}
};
let response = result.unwrap_or_else(|e| e.into());
2021-11-03 07:37:38 +00:00
tracing::trace!("Dispatch result: {:?}", response);
if let Some(callback) = callback {
2021-07-03 06:14:10 +00:00
callback(response.clone()).await;
}
Ok(response)
})
}
}
2021-07-03 06:14:10 +00:00
2021-07-21 14:41:44 +00:00
#[allow(dead_code)]
fn plugin_info(plugins: &[AFPlugin]) -> String {
let mut info = format!("{} plugins loaded\n", plugins.len());
for module in plugins {
2021-07-03 06:14:10 +00:00
info.push_str(&format!("-> {} loaded \n", module.name));
}
info
}
2021-07-21 14:41:44 +00:00
#[allow(dead_code)]
fn print_plugins(plugins: &AFPluginMap) {
plugins.iter().for_each(|(k, v)| {
tracing::info!("Event: {:?} plugin : {:?}", k, v.name);
2021-07-21 14:41:44 +00:00
})
}