use roboplc::{prelude::*, time::interval};
use signal_hook::{
consts::{SIGINT, SIGTERM},
iterator::Signals,
};
use tracing::info;
const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(2);
#[derive(DataPolicy, Clone)]
enum Message {
Data(u8),
Terminate,
}
#[derive(WorkerOpts)]
#[worker_opts(name = "veryblocking", blocking = true)]
struct VeryBlocking {}
impl Worker<Message, ()> for VeryBlocking {
fn run(&mut self, _context: &Context<Message, ()>) -> WResult {
for _ in interval(Duration::from_secs(120)) {
info!(worker = self.worker_name(), "I am still running");
}
Ok(())
}
}
#[derive(WorkerOpts)]
#[worker_opts(name = "parser")]
struct DataParser {}
impl Worker<Message, ()> for DataParser {
fn run(&mut self, context: &Context<Message, ()>) -> WResult {
let hc = context.hub().register(
self.worker_name(),
event_matches!(Message::Data(_) | Message::Terminate),
)?;
for msg in hc {
match msg {
Message::Data(data) => {
info!(worker = self.worker_name(), data = data);
}
Message::Terminate => {
break;
}
}
}
Ok(())
}
}
#[derive(WorkerOpts)]
#[worker_opts(name = "generator")]
struct DataGenerator {}
impl Worker<Message, ()> for DataGenerator {
fn run(&mut self, context: &Context<Message, ()>) -> WResult {
for _ in interval(Duration::from_secs(1)).take_while(|_| context.is_online()) {
context.hub().send(Message::Data(42));
}
Ok(())
}
}
#[derive(WorkerOpts)]
#[worker_opts(name = "sighandle")]
struct SignalHandler {}
impl Worker<Message, ()> for SignalHandler {
fn run(&mut self, context: &Context<Message, ()>) -> WResult {
let mut signals = Signals::new([SIGTERM, SIGINT])?;
if let Some(sig) = signals.forever().next() {
match sig {
SIGTERM | SIGINT => {
info!("terminating");
suicide(SHUTDOWN_TIMEOUT, true);
context.terminate();
context.hub().send(Message::Terminate);
}
_ => unreachable!(),
}
}
Ok(())
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
roboplc::setup_panic();
roboplc::configure_logger(roboplc::LevelFilter::Info);
let mut controller = Controller::<Message, ()>::new();
controller.spawn_worker(DataGenerator {})?;
controller.spawn_worker(DataParser {})?;
controller.spawn_worker(SignalHandler {})?;
controller.spawn_worker(VeryBlocking {})?;
info!("controller started");
controller.block();
info!("controller terminated");
Ok(())
}