use std::borrow::Cow;
use async_trait::async_trait;
use backstage::*;
builder!(
#[derive(Clone)]
HelloWorldBuilder {}
);
impl ThroughType for HelloWorldBuilder {
type Through = HelloWorldEvent;
}
impl Builder for HelloWorldBuilder {
type State = HelloWorld;
fn build(self) -> Self::State {
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<HelloWorldEvent>();
HelloWorld {
tx,
rx,
service: Service::new(),
}
.set_name()
}
}
impl<H: LauncherSender<HelloWorldBuilder>> AppBuilder<H> for HelloWorldBuilder {}
impl Name for HelloWorld {
fn get_name(&self) -> String {
self.service.get_name()
}
fn set_name(mut self) -> Self {
self.service.update_name("HelloWorld".to_string());
self
}
}
impl Passthrough<HelloWorldEvent> for HelloWorldSender {
fn passthrough(&mut self, _event: HelloWorldEvent, _from_app_name: String) {}
fn service(&mut self, _service: &Service) {}
fn launcher_status_change(&mut self, _service: &Service) {}
fn app_status_change(&mut self, _service: &Service) {}
}
impl Shutdown for HelloWorldSender {
fn shutdown(self) -> Option<Self> {
let _ = self.tx.send(HelloWorldEvent::Shutdown);
None
}
}
#[async_trait]
impl<H: LauncherSender<Self>> Starter<H> for HelloWorldBuilder {
type Ok = HelloWorldSender;
type Error = Cow<'static, str>;
type Input = HelloWorld;
async fn starter(mut self, handle: H, mut _input: Option<Self::Input>) -> Result<Self::Ok, Self::Error> {
let hello_world = self.build();
let app_handle = HelloWorldSender {
tx: hello_world.tx.clone(),
};
tokio::spawn(hello_world.start(Some(handle)));
Ok(app_handle)
}
}
#[async_trait]
impl<H: LauncherSender<HelloWorldBuilder>> Init<H> for HelloWorld {
async fn init(&mut self, status: Result<(), Need>, _supervisor: &mut Option<H>) -> Result<(), Need> {
self.service.update_status(ServiceStatus::Initializing);
_supervisor.as_mut().unwrap().status_change(self.service.clone());
status
}
}
#[async_trait]
impl<H: LauncherSender<HelloWorldBuilder>> EventLoop<H> for HelloWorld {
async fn event_loop(&mut self, _status: Result<(), Need>, _supervisor: &mut Option<H>) -> Result<(), Need> {
self.service.update_status(ServiceStatus::Running);
_supervisor.as_mut().unwrap().status_change(self.service.clone());
{
let apps_through: Result<H::AppsEvents, _> = serde_json::from_str("{\"HelloWorld\": \"Shutdown\"}");
if let Ok(apps_events) = apps_through {
match apps_events.try_get_my_event() {
Ok(HelloWorldEvent::Shutdown) => {
_supervisor.as_mut().unwrap().shutdown_app(&self.get_name());
}
Err(other_app_event) => {
_supervisor.as_mut().unwrap().passthrough(other_app_event, self.get_name());
}
}
} else {
return Err(Need::Abort);
};
}
while let Some(HelloWorldEvent::Shutdown) = self.rx.recv().await {
self.rx.close();
}
_status
}
}
#[async_trait]
impl<H: LauncherSender<HelloWorldBuilder>> Terminating<H> for HelloWorld {
async fn terminating(&mut self, _status: Result<(), Need>, _supervisor: &mut Option<H>) -> Result<(), Need> {
self.service.update_status(ServiceStatus::Stopping);
_supervisor.as_mut().unwrap().status_change(self.service.clone());
_status
}
}
pub struct HelloWorld {
tx: tokio::sync::mpsc::UnboundedSender<HelloWorldEvent>,
rx: tokio::sync::mpsc::UnboundedReceiver<HelloWorldEvent>,
service: Service,
}
#[allow(dead_code)]
pub struct HelloWorldSender {
tx: tokio::sync::mpsc::UnboundedSender<HelloWorldEvent>,
}
#[derive(Serialize, Deserialize)]
pub enum HelloWorldEvent {
Shutdown,
}
builder!(
#[derive(Clone)]
HowdyBuilder {}
);
impl ThroughType for HowdyBuilder {
type Through = HowdyEvent;
}
impl Builder for HowdyBuilder {
type State = Howdy;
fn build(self) -> Self::State {
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<HowdyEvent>();
Howdy {
tx,
rx,
service: Service::new(),
}
.set_name()
}
}
impl<H: LauncherSender<HowdyBuilder>> AppBuilder<H> for HowdyBuilder {}
impl Name for Howdy {
fn get_name(&self) -> String {
self.service.get_name()
}
fn set_name(mut self) -> Self {
self.service.update_name("Howdy".to_string());
self
}
}
impl Passthrough<HowdyEvent> for HowdySender {
fn passthrough(&mut self, _event: HowdyEvent, _from_app_name: String) {}
fn service(&mut self, _service: &Service) {}
fn launcher_status_change(&mut self, _service: &Service) {}
fn app_status_change(&mut self, _service: &Service) {}
}
impl Shutdown for HowdySender {
fn shutdown(self) -> Option<Self> {
let _ = self.tx.send(HowdyEvent::Shutdown);
None
}
}
#[async_trait]
impl<H: LauncherSender<HowdyBuilder>> Starter<H> for HowdyBuilder {
type Ok = HowdySender;
type Error = Cow<'static, str>;
type Input = Howdy;
async fn starter(mut self, handle: H, mut _input: Option<Self::Input>) -> Result<Self::Ok, Self::Error> {
let howdy = self.build();
let app_handle = HowdySender { tx: howdy.tx.clone() };
tokio::spawn(howdy.start(Some(handle)));
Ok(app_handle)
}
}
#[async_trait]
impl<H: LauncherSender<HowdyBuilder>> Init<H> for Howdy {
async fn init(&mut self, status: Result<(), Need>, _supervisor: &mut Option<H>) -> Result<(), Need> {
self.service.update_status(ServiceStatus::Initializing);
_supervisor.as_mut().unwrap().status_change(self.service.clone());
status
}
}
#[async_trait]
impl<H: LauncherSender<HowdyBuilder>> EventLoop<H> for Howdy {
async fn event_loop(&mut self, _status: Result<(), Need>, _supervisor: &mut Option<H>) -> Result<(), Need> {
self.service.update_status(ServiceStatus::Running);
_supervisor.as_mut().unwrap().status_change(self.service.clone());
{
let apps_through: Result<H::AppsEvents, _> = serde_json::from_str("{\"Howdy\": \"Shutdown\"}");
if let Ok(apps_events) = apps_through {
match apps_events.try_get_my_event() {
Ok(HowdyEvent::Shutdown) => {
_supervisor.as_mut().unwrap().shutdown_app(&self.get_name());
}
Err(other_app_event) => {
_supervisor.as_mut().unwrap().passthrough(other_app_event, self.get_name());
}
}
} else {
return Err(Need::Abort);
};
}
while let Some(HowdyEvent::Shutdown) = self.rx.recv().await {
self.rx.close();
}
_status
}
}
#[async_trait]
impl<H: LauncherSender<HowdyBuilder>> Terminating<H> for Howdy {
async fn terminating(&mut self, _status: Result<(), Need>, _supervisor: &mut Option<H>) -> Result<(), Need> {
self.service.update_status(ServiceStatus::Stopping);
_supervisor.as_mut().unwrap().status_change(self.service.clone());
_status
}
}
pub struct Howdy {
tx: tokio::sync::mpsc::UnboundedSender<HowdyEvent>,
rx: tokio::sync::mpsc::UnboundedReceiver<HowdyEvent>,
service: Service,
}
#[allow(dead_code)]
pub struct HowdySender {
tx: tokio::sync::mpsc::UnboundedSender<HowdyEvent>,
}
#[derive(Serialize, Deserialize)]
pub enum HowdyEvent {
Shutdown,
}
launcher!(builder: AppsBuilder {[] -> HelloWorld: HelloWorldBuilder, [] -> Howdy: HowdyBuilder}, state: Apps {});
impl Builder for AppsBuilder {
type State = Apps;
fn build(self) -> Self::State {
let hello_world_builder = HelloWorldBuilder::new();
let howdy_builder = HowdyBuilder::new();
self.HelloWorld(hello_world_builder).Howdy(howdy_builder).to_apps()
}
}
#[tokio::main]
async fn main() {
env_logger::init();
let apps = AppsBuilder::new().build();
apps.HelloWorld().await.Howdy().await.start(None).await;
}