qsu 0.10.1

Service subsystem utilities and runtime wrapper.
Documentation
#[cfg(feature = "rt")]
mod gate {
  use std::{sync::mpsc, time::Duration};

  #[derive(Debug)]
  enum MyError {}

  use qsu::{
    rt::{
      Demise, InitCtx, RunCtx, RunEnv, ServiceHandler, SrvAppRt, SvcEvt,
      TermCtx, UserSig
    },
    tracing
  };

  struct InitData {
    name: String,
    value: u32
  }

  struct TermData {
    name: String,
    value: u32
  }

  struct AnotherTermData {
    name: String,
    value: u32
  }

  struct MyService {
    rx_term: mpsc::Receiver<()>
  }

  impl ServiceHandler for MyService {
    type AppErr = MyError;

    fn init(&mut self, ictx: &mut InitCtx) -> Result<(), Self::AppErr> {
      tracing::info!("Running ServiceHandler::init()");

      let id = ictx.take::<InitData>().unwrap();
      assert_eq!(id.name, "hello");
      assert_eq!(id.value, 42);

      log::info!("init passthrough name={}, value={}", id.name, id.value);

      let atd = AnotherTermData {
        name: "extra bye".to_string(),
        value: 23
      };
      ictx.term_passthrough(atd);

      Ok(())
    }

    fn run(&mut self, _re: &RunEnv) -> Result<(), Self::AppErr> {
      tracing::info!("Running ServiceHandler::run()");

      tracing::info!("Wait for termination event for up to 4 seconds ..");
      let _ = self.rx_term.recv_timeout(Duration::from_secs(4));

      Ok(())
    }

    fn shutdown(&mut self, tctx: &mut TermCtx) -> Result<(), Self::AppErr> {
      tracing::info!("Running ServiceHandler::shutdown()");

      let td = tctx.take::<TermData>().unwrap();
      assert_eq!(td.name, "bye");
      assert_eq!(td.value, 17);

      log::info!("term passthrough name={}, value={}", td.name, td.value);

      let atd = tctx.take::<AnotherTermData>().unwrap();
      assert_eq!(atd.name, "extra bye");
      assert_eq!(atd.value, 23);

      log::info!(
        "another term passthrough name={}, value={}",
        atd.name,
        atd.value
      );

      Ok(())
    }
  }


  pub fn main() {
    let svcname = qsu::default_service_name().unwrap();

    // Channel used to signal termination from service event handler to main
    // application
    let (tx, rx) = mpsc::channel::<()>();

    // Service event handler
    let svcevt_handler = move |msg| match msg {
      SvcEvt::Shutdown(demise) => {
        tracing::debug!("Shutdown event received");
        match demise {
          Demise::Interrupted => {
            tracing::info!("Service application was interrupted");
          }
          Demise::Terminated => {
            tracing::info!("Service application was terminated");
          }
          Demise::ReachedEnd => {
            tracing::info!("Service application reached its end");
          }
        }

        // Once a Shutdown event has been received, signal to the main service
        // callback to terminate.
        tx.send(()).unwrap();
      }
      SvcEvt::User(us) => match us {
        UserSig::Sig1 => {
          log::info!("User signal 1");
        }
        UserSig::Sig2 => {
          log::info!("User signal 2");
        }
      },
      _ => {}
    };

    // Set up main service runtime handler
    let svcrt = MyService { rx_term: rx };

    // Define service application runtime components
    let apprt = SrvAppRt::Sync {
      svcevt_handler: Box::new(svcevt_handler),
      rt_handler: Box::new(svcrt)
    };

    let id = InitData {
      name: String::from("hello"),
      value: 42
    };
    let td = TermData {
      name: String::from("bye"),
      value: 17
    };

    // Launch service
    let rctx = RunCtx::new(&svcname)
      .init_passthrough(id)
      .term_passthrough(td);
    rctx.run(apprt).unwrap();
  }
}


fn main() {
  #[cfg(feature = "rt")]
  gate::main();

  #[cfg(not(feature = "rt"))]
  println!("simplesync example requires the rt feature");
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :