Asynchronous Rust library to manage synchronized timers.
- Create custom timers using cycles and handlers.
- Use pre-defined timers like Pomodoro or 52/17.
- Servers control the timer and can bind to multiple protocols simultaneously
- Clients can connect simultaneously to the same server
- Supports tokio and async-std async runtimes
See the full API documentation on docs.rs.
The core concept is the timer, which contains information about the time cycle and the state.
The server runs the timer and accepts connections from clients using binders. It can bind using multiple binders, using different protocols (the default one is TCP, but you can create your own).
The client controls the server's timer using requests and responses. Multiple clients can connect to the same server.
┌────────────────────────┐
│Server │
│ ┌────────┐ │ Request ┌────────┐
│ │ │◄├─────────┤ │
│ ┌────────┤Binder A│ │ │Client A│
│ │ │ ├─┼────────►│ │
│ │ └────────┘ │Response └────────┘
│ │ │
│ ▼ ┌────────┐ │ ┌────────┐
│ ┌─────┐ │ │◄├─────────┤ │
│ │Timer│◄────┤Binder B│ │ │Client B│
│ └─────┘ │ ├─┼────────►│ │
│ ▲ └────────┘ │ └────────┘
│ │ │
│ │ ┌────────┐ │ ┌────────┐
│ │ │ │◄├─────────┤ │
│ └────────┤Binder C│ │ │Client C│
│ │ ├─┼────────►│ │
│ └────────┘ │ └────────┘
│ │
└────────────────────────┘
use std::time::Duration;
use time::{
client::tcp::TcpClient,
server::{tcp::TcpBind, ServerBuilder, ServerEvent},
timer::TimerEvent,
};
static HOST: &str = "127.0.0.1";
static PORT: u16 = 3000;
#[tokio::main]
async fn main() {
let server = ServerBuilder::new()
.with_server_handler(|event: ServerEvent| async move {
println!("server event: {event:?}");
Ok(())
})
.with_timer_handler(|event: TimerEvent| async move {
println!("timer event: {event:?}");
Ok(())
})
.with_binder(TcpBind::new(HOST, PORT))
.with_pomodoro_config()
.build()
.unwrap();
server
.bind_with(|| async {
// wait for the binder to be ready
tokio::time::sleep(Duration::from_secs(1)).await;
let client = TcpClient::new_boxed(HOST, PORT);
client.start().await.unwrap();
tokio::time::sleep(Duration::from_secs(1)).await;
client.pause().await.unwrap();
tokio::time::sleep(Duration::from_secs(1)).await;
let timer = client.get().await.unwrap();
println!("current timer: {timer:?}");
Ok(())
})
.await
.unwrap();
}
Other examples can be found at ./examples
:
cargo run --example
Special thanks to the NLnet foundation and the European Commission that helped the project to receive financial support from various programs:
- NGI Assure in 2022
- NGI Zero Entrust in 2023
- NGI Zero Core in 2024 (still ongoing)
If you appreciate the project, feel free to donate using one of the following providers: