Skip to content

pimalaya/io-timer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

I/O Timer Documentation Matrix

Set of I/O-free Rust coroutines to manage timers, based on io-stream.

This library allows you to manage timers using an I/O-agnostic approach, based on 3 concepts:

Coroutine

A coroutine is an I/O-free, resumable and composable state machine that emits I/O requests. A coroutine is considered terminated when it does not emit I/O requests anymore.

See available coroutines at ./src.

Runtime

A runtime contains all the I/O logic, and is responsible for processing I/O requests emitted by coroutines.

See available runtimes at pimalaya/io-stream.

Loop

The loop is the glue between coroutines and runtimes. It makes the coroutine progress while allowing runtime to process I/O.

Examples

Standard blocking client using TCP

use std::net::TcpStream;

use io_stream::runtimes::std::handle;
use io_timer::client::coroutines::{GetTimer, StartTimer};

let mut stream = TcpStream::connect("localhost:1234").unwrap();

// start the timer

let mut arg = None;
let mut start = StartTimer::new();

while let Err(io) = start.resume(arg.take()) {
    arg = Some(handle(&mut stream, io).unwrap());
}

// wait few seconds, then get the timer

let mut arg = None;
let mut get = GetTimer::new();

let timer = loop {
    match get.resume(arg.take()) {
        Ok(timer) => break timer,
        Err(io) => arg = Some(handle(&mut stream, io).unwrap()),
    }
};

See complete example at ./examples/std-tcp.rs.

Tokio async server using Unix sockets

use std::{sync::Arc, time::Duration};

use io_stream::runtimes::tokio::handle;
use io_timer::{
    server::coroutines::HandleRequest,
    timer::{TimerConfig, TimerCycles, TimerLoop},
    Timer,
};

let config = TimerConfig {
    cycles: TimerCycles::from([("Work", 2).into(), ("Rest", 3).into()]),
    cycles_count: TimerLoop::Infinite,
};

let timer = Arc::new(tokio::sync::Mutex::new(Timer::new(config)));

// use an unbounded channel for receiving timer events
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();

// start the timer event notifier
tokio::spawn(async move {
    loop {
        let _event = rx.recv().await.unwrap();
        // do whatever with the event
    }
});

// define and spawn the timer tick
// this is needed to update the internal state of the timer
tokio::spawn({
    let timer = timer.clone();
    let tx = tx.clone();

    async move {
        loop {
            let mut timer = timer.lock().await;
            let events = timer.update();
            drop(timer);

            for event in events {
                tx.send(event).unwrap();
            }

            // the timer can be refreshed every seconds
            tokio::time::sleep(Duration::from_secs(1)).await;
        }
    }
});

// listen to the unix socket for client <-> server communication
let listener = tokio::net::UnixListener::bind("/tmp/timer.sock").unwrap();
let (mut stream, _) = listener.accept().await.unwrap();

loop {
    let mut arg = None;
    let mut handler = HandleRequest::new();

    let events = loop {
        let mut timer = timer.lock().await;
        let output = handler.resume(&mut timer, arg.take());
        drop(timer);

        match output {
            Ok(events) => break events,
            Err(io) => arg = Some(handle(&mut stream, io).await.unwrap()),
        }
    };

    for event in events {
        tx.send(event).unwrap();
    }
}

See complete example at ./examples/tokio-unix.rs.

More examples

See projects built at the top of this library:

Sponsoring

nlnet

Special thanks to the NLnet foundation and the European Commission that helped the project to receive financial support from various programs:

If you appreciate the project, feel free to donate using one of the following providers:

GitHub Ko-fi Buy Me a Coffee Liberapay thanks.dev PayPal