[bugfix] align countdown snapshot timing with tokio instants

- switch ClockAnchor to tokio::time::Instant
- remove flawed epoch conversion helpers from Countdown
- expose countdown getters for id/label/start/target instants
- update service snapshot to compute remaining_at(now) and return instants directly
- add core extern declaration in lib.rs
This commit is contained in:
2026-02-26 17:27:55 +01:00
parent d0857d7028
commit 8f8db9233b
6 changed files with 93 additions and 12 deletions

View File

@@ -0,0 +1,66 @@
use crate::countdown::dto::CountdownSnapshotDto;
use crate::countdown::errors::CountdownError;
use crate::AppState;
use tauri::{command, State};
use tokio::time::Instant;
type CmdResult<T> = Result<T, String>;
#[command]
pub async fn countdown_start(state: State<'_, AppState>) -> Result<(), String> {
state
.countdown_service
.start(Instant::now())
.await
.map_err(|e: CountdownError| format!("{e:?}"))?;
Ok(())
}
#[command]
pub async fn countdown_reset(state: State<'_, AppState>) -> Result<(), String> {
state.countdown_service.reset().await;
Ok(())
}
#[command]
pub async fn countdown_pause(state: State<'_, AppState>) -> Result<(), String> {
state
.countdown_service
.pause(Instant::now())
.await
.map_err(|e: CountdownError| format!("{e:?}"))?;
Ok(())
}
#[command]
pub async fn countdown_resume(state: State<'_, AppState>) -> Result<(), String> {
state
.countdown_service
.resume(Instant::now())
.await
.map_err(|e: CountdownError| format!("{e:?}"))?;
Ok(())
}
#[command]
pub async fn countdown_snapshot(
state: State<'_, AppState>,
) -> Result<CountdownSnapshotDto, String> {
let countdown_snapshot = state.countdown_service.snapshot(Instant::now()).await;
let start = match countdown_snapshot.start_instant {
Some(instant) => Some(state.clock_anchor.instant_to_epoch_ms(instant)),
None => None,
};
let target = match countdown_snapshot.target_instant {
Some(instant) => Some(state.clock_anchor.instant_to_epoch_ms(instant)),
None => None,
};
Ok(CountdownSnapshotDto {
id: countdown_snapshot.id,
label: countdown_snapshot.label,
duration: countdown_snapshot.duration,
state: countdown_snapshot.state,
start_epoch_ms: start,
target_epoch_ms: target,
})
}

View File

@@ -0,0 +1,10 @@
use crate::countdown::model::CountdownState;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CountdownError {
InvalidTransition {
from: CountdownState,
action: &'static str,
},
TimeOverflow,
}

View File

@@ -1,3 +1,5 @@
pub mod commands;
pub mod dto;
pub mod errors;
pub mod model;
pub mod service;

View File

@@ -1,3 +1,4 @@
use crate::countdown::errors::CountdownError;
use serde::{Deserialize, Serialize};
use tokio::time::{Duration, Instant};
@@ -9,15 +10,6 @@ pub enum CountdownState {
Finished,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CountdownError {
InvalidTransition {
from: CountdownState,
action: &'static str,
},
TimeOverflow,
}
#[derive(Debug, Clone)]
pub struct Countdown {
pub id: u64,

View File

@@ -1,4 +1,5 @@
use crate::countdown::model::{Countdown, CountdownError, CountdownState};
use crate::countdown::errors::CountdownError;
use crate::countdown::model::{Countdown, CountdownState};
use tokio::sync::Mutex;
use tokio::time::{Duration, Instant};
@@ -32,7 +33,7 @@ impl CountdownService {
let countdown = self.countdown.lock().await.clone();
CountdownSnapshot {
id: countdown.id(),
label: countdown.label().parse().unwrap(),
label: countdown.label().to_string(),
state: countdown.state(),
duration: countdown.remaining_at(now),
start_instant: countdown.start_timestamp(),

View File

@@ -3,6 +3,9 @@ extern crate core;
mod app_state;
mod countdown;
use crate::countdown::commands::{
countdown_pause, countdown_reset, countdown_resume, countdown_snapshot, countdown_start,
};
pub use app_state::AppState;
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
@@ -17,7 +20,14 @@ pub fn run() {
tauri::Builder::default()
.manage(app_state)
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.invoke_handler(tauri::generate_handler![
greet,
countdown_start,
countdown_reset,
countdown_pause,
countdown_resume,
countdown_snapshot,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}