use async_trait::async_trait;
use backstage::*;
use std::borrow::Cow;
builder!(
#[derive(Clone)]
HelloWorldBuilder<T> {}
);
impl<H: LauncherSender<Self>> ThroughType for HelloWorldBuilder<H> {
type Through = HelloWorldEvent;
}
impl<H: LauncherSender<Self>> Builder for HelloWorldBuilder<H> {
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<Self>> AppBuilder<H> for HelloWorldBuilder<H> {}
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<H> {
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<H>>> 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<H>>> 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<H>>> 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,
}
launcher!(builder: AppsBuilder {[] -> HelloWorld: HelloWorldBuilder<Sender>}, state: Apps {});
impl Builder for AppsBuilder {
type State = Apps;
fn build(self) -> Self::State {
let hello_world_builder = HelloWorldBuilder::new();
self.HelloWorld(hello_world_builder).to_apps()
}
}
#[tokio::main]
async fn main() {
env_logger::init();
let apps = AppsBuilder::new().build();
apps.HelloWorld().await.start(None).await;
}