//! Simple service that does nothing other than log/trace every N seconds. mod argp; mod err; mod procres; use std::{ thread, time::{Duration, Instant} }; use tokio::sync::mpsc; use qsu::{ argp::ArgParser, rt::{InitCtx, RunEnv, ServiceHandler, SrvAppRt, SvcEvt, TermCtx} }; use err::Error; use procres::ProcRes; struct MyService { rx: mpsc::UnboundedReceiver } impl ServiceHandler for MyService { type AppErr = Error; fn init(&mut self, ictx: InitCtx) -> Result<(), Self::AppErr> { ictx.report(Some("Entered init".into())); tracing::trace!("Running init()"); Ok(()) } fn run(&mut self, _re: &RunEnv) -> Result<(), Self::AppErr> { const SECS: u64 = 30; // unwrap() is okay due to time scale 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(); } match self.rx.try_recv() { Ok(SvcEvt::Shutdown(_)) => { tracing::info!("Service application shutdown"); break; } Ok(SvcEvt::ReloadConf) => { tracing::info!( "The service subsystem requested that the application reload its \ configuration" ); } _ => {} } thread::sleep(std::time::Duration::from_secs(1)); } Ok(()) } 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"); // Create a closure that will generate a sync service runtime with a // service event handler that will forward any messages it receives to a // channel receiver end-point held by the main service handler. let bldr = Box::new(|| { let (tx, rx) = mpsc::unbounded_channel(); SrvAppRt::Sync { svcevt_handler: Box::new(move |msg| { // Just foward messages to runtime handler tx.send(msg).unwrap(); }), rt_handler: Box::new(MyService { rx }) } }); // Parse, and process, command line arguments. // Add a service registration callback that will set service's description. let mut argsproc = argp::AppArgsProc { bldr }; let ap = ArgParser::new(&svcname, &mut argsproc).regsvc_proc(|mut regsvc| { // Set description, but only if it hasn't been set already (presumably // via the command line). if regsvc.description.is_none() { regsvc .description_ref("A sync server that says hello every 30 seconds"); } regsvc }); ap.proc()?; Ok(()) } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :