Files
ziemniak/src-tauri/src/main.rs

175 lines
4.4 KiB
Rust
Raw Normal View History

2022-07-26 05:03:28 +02:00
#![cfg_attr(
2022-07-26 23:36:24 +02:00
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
2022-07-26 05:03:28 +02:00
)]
2022-07-28 01:47:53 +02:00
use std::{
collections::HashMap,
sync::{Arc, Mutex},
time::{Duration, Instant}, fmt, error::Error,
};
2022-07-26 23:36:24 +02:00
use chrono::{DateTime, FixedOffset, Local};
2022-07-28 01:47:53 +02:00
use tauri::{State, Window, async_runtime::spawn};
2022-07-26 23:36:24 +02:00
use tokio::time::interval;
use uuid::Uuid;
2022-07-28 01:47:53 +02:00
#[derive(serde::Serialize, Debug)]
enum TimerError {
NotFound,
NotStarted,
}
impl fmt::Display for TimerError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TimerError::NotFound => write!(f, "timer not found"),
TimerError::NotStarted => write!(f, "timer not started"),
}
}
}
impl Error for TimerError {}
2022-07-26 23:36:24 +02:00
#[derive(Clone, Default, serde::Serialize)]
struct Timer {
id: Uuid,
started: Option<DateTime<FixedOffset>>,
duration: Duration,
elapsed: Option<Duration>,
message: String,
2022-07-28 01:47:53 +02:00
#[serde(skip)]
checked: Option<Instant>,
2022-07-26 23:36:24 +02:00
}
impl Timer {
fn new(message: &str, duration: Duration) -> Self {
2022-07-27 12:58:22 +02:00
Self {
2022-07-26 23:36:24 +02:00
id: Uuid::new_v4(),
2022-07-27 12:58:22 +02:00
duration,
2022-07-26 23:36:24 +02:00
message: message.to_string(),
..Default::default()
2022-07-27 12:58:22 +02:00
}
2022-07-26 23:36:24 +02:00
}
2022-07-27 12:58:22 +02:00
fn complete(&self) -> bool {
self.elapsed.map_or(false, |e| e >= self.duration)
2022-07-26 23:36:24 +02:00
}
2022-07-28 01:47:53 +02:00
fn start(self) -> Self {
Timer {
started: Some(Local::now().into()),
elapsed: Some(Duration::from_secs(0)),
checked: Some(Instant::now()),
..self
}
}
2022-07-26 23:36:24 +02:00
2022-07-28 01:47:53 +02:00
fn tick(self) -> Result<Self, TimerError> {
let now = Instant::now();
let elapsed = now - match self.checked {
None => return Err(TimerError::NotStarted),
Some(checked) => checked,
};
2022-07-26 23:36:24 +02:00
2022-07-28 01:47:53 +02:00
Ok(Timer {
elapsed: self.elapsed.map(|e| e + elapsed),
checked: Some(now),
..self
})
}
}
2022-07-26 23:36:24 +02:00
2022-07-28 01:47:53 +02:00
#[derive(Default)]
struct Timers(Arc<Mutex<HashMap<Uuid, Timer>>>);
2022-07-26 23:36:24 +02:00
2022-07-28 01:47:53 +02:00
impl Timers {
fn make_timer(&self, duration: Duration, message: &str) -> Timer {
let timer = Timer::new(message, duration);
self.0.lock().unwrap().insert(timer.id, timer.clone());
timer
}
fn delete_timer(&self, timer_id: Uuid) -> Option<Timer> {
self.0.lock().unwrap().get(&timer_id).cloned()
}
fn start_timer(&self, timer_id: Uuid) -> Result<Timer, TimerError> {
let mut timers = self.0.lock().unwrap();
match timers.get(&timer_id).cloned() {
None => Err(TimerError::NotFound),
Some(t) => {
let started = t.start();
timers.insert(started.id, started.clone());
Ok(started)
2022-07-26 23:36:24 +02:00
}
}
2022-07-28 01:47:53 +02:00
}
2022-07-26 23:36:24 +02:00
2022-07-28 01:47:53 +02:00
fn tick_timer(&self, timer_id: Uuid) -> Result<Timer, TimerError> {
let mut timers = self.0.lock().unwrap();
match timers.get(&timer_id).cloned() {
None => Err(TimerError::NotFound),
Some(t) => {
let started = t.tick()?;
timers.insert(started.id, started.clone());
Ok(started)
}
}
2022-07-26 23:36:24 +02:00
}
2022-07-28 01:47:53 +02:00
2022-07-26 23:36:24 +02:00
}
2022-07-26 05:03:28 +02:00
#[tauri::command]
2022-07-28 01:47:53 +02:00
fn make_timer(timers: State<'_, Timers>, duration: Duration, message: &str) -> Timer {
timers.make_timer(duration, message)
}
#[tauri::command]
fn delete_timer(timers: State<'_, Timers>, timer_id: Uuid) -> Option<Timer> {
timers.delete_timer(timer_id)
}
#[tauri::command]
fn start_timer(window: Window, timers: State<'_, Timers>, timer_id: Uuid) -> Result<Timer, TimerError> {
let timers = Timers(timers.0.to_owned());
let timer = timers.start_timer(timer_id)?;
let res = timer.clone();
2022-07-26 23:36:24 +02:00
spawn(async move {
2022-07-28 01:47:53 +02:00
let mut interval = interval(Duration::from_secs(1) / 60);
loop {
interval.tick().await;
match timers.tick_timer(timer_id) {
Err(_) => break,
Ok(timer) => {
if timer.complete() || window.emit("timer-tick", timer).is_err() {
break;
}
}
}
}
window.emit("timer-done", timer).ok();
2022-07-26 23:36:24 +02:00
});
2022-07-28 01:47:53 +02:00
Ok(res)
2022-07-26 05:03:28 +02:00
}
fn main() {
2022-07-26 23:36:24 +02:00
tauri::Builder::default()
2022-07-28 01:47:53 +02:00
.manage(Timers(Default::default()))
.invoke_handler(tauri::generate_handler![
delete_timer,
make_timer,
start_timer
])
2022-07-26 23:36:24 +02:00
.run(tauri::generate_context!())
.expect("error while running tauri application");
2022-07-26 05:03:28 +02:00
}