|
@@ -7,43 +7,52 @@ use crate::{
|
|
|
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 pin_project::pin_project;
|
|
|
use std::{
|
|
|
+ cell::RefCell,
|
|
|
collections::HashMap,
|
|
|
+ fmt::Debug,
|
|
|
future::Future,
|
|
|
hash::Hash,
|
|
|
marker::PhantomData,
|
|
|
pin::Pin,
|
|
|
rc::Rc,
|
|
|
+ sync::Arc,
|
|
|
task::{Context, Poll},
|
|
|
};
|
|
|
-use tokio::sync::{mpsc, mpsc::UnboundedReceiver};
|
|
|
-
|
|
|
-use crate::{
|
|
|
- request::{payload::Payload, FlowyRequest},
|
|
|
- service::{factory, BoxServiceFactory, HandlerService},
|
|
|
+use tokio::sync::{
|
|
|
+ mpsc,
|
|
|
+ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
|
|
};
|
|
|
-use pin_project::pin_project;
|
|
|
-use std::fmt::Debug;
|
|
|
|
|
|
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 {
|
|
|
name: String,
|
|
|
data: DataContainer,
|
|
|
- fact_map: HashMap<Command, ModuleServiceFactory>,
|
|
|
- cmd_rx: UnboundedReceiver<FlowyRequest>,
|
|
|
+ factory_map: HashMap<Command, CommandServiceFactory>,
|
|
|
+ req_tx: UnboundedSender<FlowyRequest>,
|
|
|
+ req_rx: UnboundedReceiver<FlowyRequest>,
|
|
|
+ resp_tx: UnboundedSender<FlowyResponse>,
|
|
|
}
|
|
|
|
|
|
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 {
|
|
|
name: "".to_owned(),
|
|
|
data: DataContainer::new(),
|
|
|
- fact_map: HashMap::new(),
|
|
|
- cmd_rx,
|
|
|
+ factory_map: HashMap::new(),
|
|
|
+ req_tx,
|
|
|
+ req_rx,
|
|
|
+ resp_tx,
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -65,51 +74,111 @@ impl Module {
|
|
|
R: Future + 'static,
|
|
|
R::Output: Responder + 'static,
|
|
|
{
|
|
|
- self.fact_map.insert(command, factory(HandlerService::new(handler)));
|
|
|
+ self.factory_map.insert(command, factory(HandlerService::new(handler)));
|
|
|
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 {
|
|
|
type Output = ();
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
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(()),
|
|
|
- Some(request) => match self.fact_map.get(request.get_id()) {
|
|
|
+ Some(request) => match self.factory_map.get(request.get_cmd()) {
|
|
|
Some(factory) => {
|
|
|
- let service_future = factory.new_service(());
|
|
|
- tokio::task::spawn_local(ModuleServiceFuture {
|
|
|
+ let fut = ModuleServiceFuture {
|
|
|
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)]
|
|
|
-pub struct ModuleServiceFuture<Service, Error> {
|
|
|
+type BoxModuleService = BoxService<ServiceRequest, ServiceResponse, SystemError>;
|
|
|
+#[pin_project]
|
|
|
+pub struct ModuleServiceFuture {
|
|
|
request: FlowyRequest,
|
|
|
#[pin]
|
|
|
- service_future: LocalBoxFuture<'static, Result<Service, Error>>,
|
|
|
+ fut: LocalBoxFuture<'static, Result<BoxModuleService, SystemError>>,
|
|
|
}
|
|
|
|
|
|
-impl<Service, Error> Future for ModuleServiceFuture<Service, Error> {
|
|
|
- type Output = ();
|
|
|
+impl Future for ModuleServiceFuture {
|
|
|
+ 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 {
|
|
|
- type Response = ServiceResponse;
|
|
|
- type Error = SystemError;
|
|
|
- type Service = BoxService<ServiceRequest, ServiceResponse, SystemError>;
|
|
|
- type Config = ();
|
|
|
- type Future = LocalBoxFuture<'static, Result<Self::Service, Self::Error>>;
|
|
|
+#[cfg(test)]
|
|
|
+mod tests {
|
|
|
+ use super::*;
|
|
|
+ use crate::rt::Runtime;
|
|
|
+ use futures_util::{future, pin_mut};
|
|
|
+ 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;
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|