//! Simple service that does nothing other than log/trace every N seconds. mod argp; mod err; mod procres; use std::time::{Duration, Instant}; use tokio::sync::mpsc; use qsu::{ argp::ArgParser, rt::{InitCtx, RunEnv, SrvAppRt, SvcEvt, TermCtx, TokioServiceHandler} }; use err::Error; use procres::ProcRes; struct MyService { rx: mpsc::UnboundedReceiver } #[qsu::async_trait] impl TokioServiceHandler for MyService { type AppErr = Error; async fn init(&mut self, ictx: InitCtx) -> Result<(), Self::AppErr> { ictx.report(Some("Entered init".into())); tracing::trace!("Running init()"); Ok(()) } #[allow(clippy::redundant_pub_crate)] async fn run(&mut self, _re: &RunEnv) -> Result<(), Self::AppErr> { const SECS: u64 = 30; // unwrap() is okay due to time scales involed let mut last_dump = Instant::now() .checked_sub(Duration::from_secs(SECS)) .unwrap(); loop { if last_dump.elapsed() > Duration::from_secs(SECS) { log::error!("error"); log::warn!("warn"); log::info!("info"); log::debug!("debug"); log::trace!("trace"); tracing::error!("error"); tracing::warn!("warn"); tracing::info!("info"); tracing::debug!("debug"); tracing::trace!("trace"); last_dump = Instant::now(); } tokio::select! { () = tokio::time::sleep(std::time::Duration::from_secs(1)) => { continue; } evt = self.rx.recv() => { match evt { Some(SvcEvt::Shutdown(_)) => { tracing::info!("The service subsystem requested that the application shut down"); break; } Some(SvcEvt::ReloadConf) => { tracing::info!("The service subsystem requested that application reload configuration"); } _ => { } } } } } Ok(()) } async fn shutdown(&mut self, tctx: TermCtx) -> Result<(), Self::AppErr> { tctx.report(Some(("Entered shutdown".to_string()).into())); tracing::trace!("Running shutdown()"); Ok(()) } } fn main() -> ProcRes { // In the future we'll be able to use Try to implement support for implicit // conversion to ProcRes from a Result using `?`, but for now use this hack. ProcRes::into(main2().into()) } fn main2() -> Result<(), Error> { // Derive default service name from executable name. let svcname = qsu::default_service_name() .expect("Unable to determine default service name"); let bldr = Box::new(|| { let (tx, rx) = mpsc::unbounded_channel(); let svcevt_handler = Box::new(move |msg| { // Just foward messages to runtime handler tx.send(msg).unwrap(); }); let rt_handler = Box::new(MyService { rx }); SrvAppRt::Tokio { rtbldr: None, svcevt_handler, rt_handler } }); // Parse, and process, command line arguments. let mut argsproc = argp::AppArgsProc { bldr }; let ap = ArgParser::new(&svcname, &mut argsproc); ap.proc()?; Ok(()) } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :