use qsu::{
log,
rt::{InitCtx, RocketServiceHandler, RunEnv, SrvAppRt, SvcEvt, TermCtx},
tracing
};
use tokio::sync::mpsc;
use rocket::{fairing::AdHoc, fs::FileServer, Build, Ignite, Rocket};
use crate::err::Error;
pub fn create() -> SrvAppRt<Error> {
let (tx_svcevt, rx_svcevt) = mpsc::unbounded_channel();
let handler = MyService { rx_svcevt };
SrvAppRt::Rocket {
svcevt_handler: Box::new(move |msg| {
if let Err(e) = tx_svcevt.send(msg) {
log::error!("Unable to forward svcevt; {e}");
}
}),
rt_handler: Box::new(handler)
}
}
pub struct MyService {
rx_svcevt: mpsc::UnboundedReceiver<SvcEvt>
}
#[qsu::async_trait]
impl RocketServiceHandler for MyService {
type AppErr = Error;
async fn init(
&mut self,
ictx: InitCtx
) -> Result<Vec<Rocket<Build>>, Self::AppErr> {
tracing::trace!("Running init()");
let mut rockets = vec![];
ictx.report(Some("Building rocket".into()));
let rocket =
rocket::build().attach(AdHoc::try_on_ignite("Config", |rocket| async {
let htdocsdir = match rocket
.figment()
.extract_inner::<String>("htdocs")
{
Ok(htdocsdir) => htdocsdir,
Err(e) => {
log::error!("Unable to extract htdocs from configuration; {}", e);
return Err(rocket);
}
};
let htdocsdir = match shellexpand::full(&htdocsdir) {
Ok(dir) => dir.into_owned(),
Err(e) => {
log::error!("Unable to expand htdocs from configuration; {}", e);
return Err(rocket);
}
};
let rocket = rocket.mount("/", FileServer::from(htdocsdir));
Ok(rocket)
}));
rockets.push(rocket);
Ok(rockets)
}
async fn run(
&mut self,
rockets: Vec<Rocket<Ignite>>,
_re: &RunEnv
) -> Result<(), Self::AppErr> {
for rocket in rockets {
tokio::task::spawn(async {
rocket.launch().await.unwrap();
});
}
loop {
tokio::select! {
evt = self.rx_svcevt.recv() => {
let Some(evt) = evt else {
break;
};
#[allow(clippy::single_match)]
match evt {
SvcEvt::Shutdown(_) => {
break;
}
_ => { }
}
}
}
}
Ok(())
}
async fn shutdown(&mut self, tctx: TermCtx) -> Result<(), Self::AppErr> {
tracing::trace!("Running shutdown()");
tctx.report(Some("Shutting down".into()));
Ok(())
}
}