AppFlowy/rust-lib/flowy-sys/src/rt/system.rs

154 lines
4.2 KiB
Rust
Raw Normal View History

2021-06-26 15:52:03 +00:00
use crate::{
2021-06-26 17:24:00 +00:00
module::{Command, CommandServiceFactory, Module},
2021-06-26 15:52:03 +00:00
request::FlowyRequest,
response::FlowyResponse,
rt::Runtime,
2021-06-26 17:24:00 +00:00
service::BoxServiceFactory,
2021-06-26 15:52:03 +00:00
};
use futures_core::{future::LocalBoxFuture, ready, task::Context};
use futures_util::{future, pin_mut};
2021-06-26 17:24:00 +00:00
use std::{cell::RefCell, collections::HashMap, future::Future, io, sync::Arc};
2021-06-26 15:52:03 +00:00
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>,
2021-06-26 17:24:00 +00:00
sender_map: HashMap<Command, UnboundedSender<FlowyRequest>>,
2021-06-26 15:52:03 +00:00
}
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(),
2021-06-26 17:24:00 +00:00
sender_map: HashMap::default(),
2021-06-26 15:52:03 +00:00
};
let factory = module_factory(resp_tx.clone());
factory.into_iter().for_each(|m| {
2021-06-26 17:24:00 +00:00
system.sender_map.extend(m.service_sender_map());
2021-06-26 15:52:03 +00:00
runtime.spawn(m);
});
FlowySystem::set_current(system);
let runner = SystemRunner { rt: runtime, stop_rx };
runner
}
pub fn handle_command(&self, cmd: Command, request: FlowyRequest) {
2021-06-26 17:24:00 +00:00
if let Some(sender) = self.sender_map.get(&cmd) {
sender.send(request);
}
2021-06-26 15:52:03 +00:00
}
#[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) => {
2021-06-26 17:24:00 +00:00
// FF
2021-06-26 15:52:03 +00:00
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();
}
}