2021-07-08 13:23:44 +00:00
|
|
|
use crate::module::{as_module_map, Module, ModuleMap};
|
2021-06-27 07:11:41 +00:00
|
|
|
use futures_core::{ready, task::Context};
|
2021-07-02 12:45:51 +00:00
|
|
|
use std::{cell::RefCell, fmt::Debug, 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);
|
|
|
|
);
|
|
|
|
|
2021-06-27 14:07:33 +00:00
|
|
|
#[derive(Debug)]
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-06-27 14:07:33 +00:00
|
|
|
pub enum SystemCommand {
|
2021-06-27 07:11:41 +00:00
|
|
|
Exit(i8),
|
|
|
|
}
|
|
|
|
|
2021-06-26 15:52:03 +00:00
|
|
|
pub struct FlowySystem {
|
2021-06-28 06:27:16 +00:00
|
|
|
sys_cmd_tx: UnboundedSender<SystemCommand>,
|
2021-06-26 15:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FlowySystem {
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-06-30 07:33:49 +00:00
|
|
|
pub fn construct<F, S>(module_factory: F, sender_factory: S) -> SystemRunner
|
2021-06-26 15:52:03 +00:00
|
|
|
where
|
2021-06-28 06:27:16 +00:00
|
|
|
F: FnOnce() -> Vec<Module>,
|
2021-06-30 07:33:49 +00:00
|
|
|
S: FnOnce(ModuleMap, &Runtime),
|
2021-06-26 15:52:03 +00:00
|
|
|
{
|
2021-07-02 12:45:51 +00:00
|
|
|
let runtime = Arc::new(Runtime::new().unwrap());
|
2021-06-28 06:27:16 +00:00
|
|
|
let (sys_cmd_tx, sys_cmd_rx) = unbounded_channel::<SystemCommand>();
|
2021-06-26 15:52:03 +00:00
|
|
|
let (stop_tx, stop_rx) = oneshot::channel();
|
2021-06-27 07:11:41 +00:00
|
|
|
|
|
|
|
runtime.spawn(SystemController {
|
|
|
|
stop_tx: Some(stop_tx),
|
2021-06-28 06:27:16 +00:00
|
|
|
sys_cmd_rx,
|
2021-06-27 07:11:41 +00:00
|
|
|
});
|
2021-06-26 15:52:03 +00:00
|
|
|
|
2021-07-02 12:45:51 +00:00
|
|
|
let module_map = as_module_map(module_factory());
|
2021-11-27 11:19:41 +00:00
|
|
|
sender_factory(module_map, &runtime);
|
2021-06-28 08:27:46 +00:00
|
|
|
|
2021-06-28 14:56:15 +00:00
|
|
|
let system = Self { sys_cmd_tx };
|
2021-06-26 15:52:03 +00:00
|
|
|
FlowySystem::set_current(system);
|
2021-11-27 11:19:41 +00:00
|
|
|
SystemRunner { rt: runtime, stop_rx }
|
2021-06-26 15:52:03 +00:00
|
|
|
}
|
|
|
|
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-06-27 07:11:41 +00:00
|
|
|
pub fn stop(&self) {
|
2021-06-28 06:27:16 +00:00
|
|
|
match self.sys_cmd_tx.send(SystemCommand::Exit(0)) {
|
2021-06-27 07:11:41 +00:00
|
|
|
Ok(_) => {},
|
|
|
|
Err(e) => {
|
|
|
|
log::error!("Stop system error: {}", e);
|
|
|
|
},
|
2021-06-26 17:24:00 +00:00
|
|
|
}
|
2021-06-26 15:52:03 +00:00
|
|
|
}
|
|
|
|
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-06-26 15:52:03 +00:00
|
|
|
pub fn set_current(sys: FlowySystem) {
|
|
|
|
CURRENT.with(|cell| {
|
|
|
|
*cell.borrow_mut() = Some(Arc::new(sys));
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-06-26 15:52:03 +00:00
|
|
|
pub fn current() -> Arc<FlowySystem> {
|
|
|
|
CURRENT.with(|cell| match *cell.borrow() {
|
|
|
|
Some(ref sys) => sys.clone(),
|
|
|
|
None => panic!("System is not running"),
|
|
|
|
})
|
|
|
|
}
|
2021-06-27 07:11:41 +00:00
|
|
|
}
|
|
|
|
|
2021-06-26 15:52:03 +00:00
|
|
|
struct SystemController {
|
2021-06-27 07:11:41 +00:00
|
|
|
stop_tx: Option<oneshot::Sender<i8>>,
|
2021-06-28 06:27:16 +00:00
|
|
|
sys_cmd_rx: UnboundedReceiver<SystemCommand>,
|
2021-06-26 15:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Future for SystemController {
|
|
|
|
type Output = ();
|
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
loop {
|
2021-06-28 06:27:16 +00:00
|
|
|
match ready!(Pin::new(&mut self.sys_cmd_rx).poll_recv(cx)) {
|
2021-06-26 15:52:03 +00:00
|
|
|
None => return Poll::Ready(()),
|
2021-06-27 07:11:41 +00:00
|
|
|
Some(cmd) => match cmd {
|
|
|
|
SystemCommand::Exit(code) => {
|
|
|
|
if let Some(tx) = self.stop_tx.take() {
|
|
|
|
let _ = tx.send(code);
|
|
|
|
}
|
|
|
|
},
|
2021-06-26 15:52:03 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SystemRunner {
|
2021-07-02 12:45:51 +00:00
|
|
|
rt: Arc<Runtime>,
|
2021-06-27 07:11:41 +00:00
|
|
|
stop_rx: oneshot::Receiver<i8>,
|
2021-06-26 15:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SystemRunner {
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-06-26 15:52:03 +00:00
|
|
|
pub fn run(self) -> io::Result<()> {
|
|
|
|
let SystemRunner { rt, stop_rx } = self;
|
|
|
|
match rt.block_on(stop_rx) {
|
|
|
|
Ok(code) => {
|
|
|
|
if code != 0 {
|
2021-10-01 11:39:08 +00:00
|
|
|
Err(io::Error::new(
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
format!("Non-zero exit code: {}", code),
|
|
|
|
))
|
2021-06-26 15:52:03 +00:00
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-06-28 06:27:16 +00:00
|
|
|
pub fn spawn<F: Future<Output = ()> + 'static>(self, future: F) -> Self {
|
2021-06-26 15:52:03 +00:00
|
|
|
self.rt.spawn(future);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
2021-07-08 13:23:44 +00:00
|
|
|
|
|
|
|
use crate::util::tokio_default_runtime;
|
|
|
|
use tokio::{runtime, task::LocalSet};
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Runtime {
|
|
|
|
local: LocalSet,
|
|
|
|
rt: runtime::Runtime,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Runtime {
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-07-08 13:23:44 +00:00
|
|
|
pub fn new() -> io::Result<Runtime> {
|
|
|
|
let rt = tokio_default_runtime()?;
|
|
|
|
Ok(Runtime {
|
|
|
|
rt,
|
|
|
|
local: LocalSet::new(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-07-08 13:23:44 +00:00
|
|
|
pub fn spawn<F>(&self, future: F) -> &Self
|
|
|
|
where
|
|
|
|
F: Future<Output = ()> + 'static,
|
|
|
|
{
|
|
|
|
self.local.spawn_local(future);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-07-09 06:02:42 +00:00
|
|
|
#[allow(dead_code)]
|
2021-07-08 13:23:44 +00:00
|
|
|
pub fn block_on<F>(&self, f: F) -> F::Output
|
|
|
|
where
|
|
|
|
F: Future + 'static,
|
|
|
|
{
|
|
|
|
self.local.block_on(&self.rt, f)
|
|
|
|
}
|
|
|
|
}
|