1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
# I/O Timer
Set of **I/O-free** Rust coroutines to manage timers, based on [io-stream](https://github.com/pimalaya/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](https://github.com/pimalaya/io-timer/tree/master/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](https://github.com/pimalaya/io-stream/tree/master/src/runtimes).*
### 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
```rust,ignore
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](https://github.com/pimalaya/io-timer/blob/master/examples/std-tcp.rs).*
### Tokio async server using Unix sockets
```rust,ignore
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](https://github.com/pimalaya/io-timer/blob/master/examples/tokio-unix.rs).*
### More examples
See projects built at the top of this library:
- [comodoro](https://github.com/pimalaya/comodoro): CLI to manage timers
## Sponsoring
Special thanks to the [NLnet foundation](https://nlnet.nl/) and the [European Commission](https://www.ngi.eu/) that helped the project to receive financial support from various programs:
- [NGI Assure](https://nlnet.nl/project/Himalaya/) in 2022
- [NGI Zero Entrust](https://nlnet.nl/project/Pimalaya/) in 2023
- [NGI Zero Core](https://nlnet.nl/project/Pimalaya-PIM/) in 2024 *(still ongoing)*
If you appreciate the project, feel free to donate using one of the following providers:
- [GitHub](https://github.com/sponsors/soywod)
- [Ko-fi](https://ko-fi.com/soywod)
- [Buy Me a Coffee](https://www.buymeacoffee.com/soywod)
- [Liberapay](https://liberapay.com/soywod)
- [thanks.dev](https://thanks.dev/soywod)
- [PayPal](https://www.paypal.com/paypalme/soywod)
|