[bugfix] fix countdown snapshot time calculations and unify tokio instants

- switch ClockAnchor to tokio::time::Instant for consistent async timing
- remove incorrect epoch-ms math in Countdown model and expose instant getters
- update CountdownService snapshot to use remaining_at(now) plus start/target instants
- add missing core extern declaration in lib.rs
This commit is contained in:
2026-02-26 16:24:35 +01:00
parent 503a3ef94c
commit d0857d7028
4 changed files with 40 additions and 38 deletions

View File

@@ -1,14 +1,14 @@
use crate::countdown::service::CountdownService;
#[derive(Clone, Debug)]
pub struct ClockAnchor {
pub boot_instant: std::time::Instant,
pub boot_instant: tokio::time::Instant,
pub boot_epoch_ms: u128,
}
impl ClockAnchor {
pub fn new() -> Self {
Self {
boot_instant: std::time::Instant::now(),
boot_instant: tokio::time::Instant::now(),
boot_epoch_ms: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
@@ -16,7 +16,7 @@ impl ClockAnchor {
}
}
pub fn instant_to_epoch_ms(&self, instant: std::time::Instant) -> u128 {
pub fn instant_to_epoch_ms(&self, instant: tokio::time::Instant) -> u128 {
instant.duration_since(self.boot_instant).as_millis() + self.boot_epoch_ms
}
}

View File

@@ -1,5 +1,4 @@
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::time::{Duration, Instant};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
@@ -43,6 +42,14 @@ impl Countdown {
}
}
pub fn id(&self) -> u64 {
self.id
}
pub fn label(&self) -> &str {
&self.label
}
pub fn state(&self) -> CountdownState {
self.state
}
@@ -51,6 +58,14 @@ impl Countdown {
self.initial_duration
}
pub fn start_timestamp(&self) -> Option<Instant> {
self.start_timestamp
}
pub fn target_timestamp(&self) -> Option<Instant> {
self.target_timestamp
}
pub fn remaining_at(&self, now: Instant) -> Duration {
match self.state {
CountdownState::Idle => self.initial_duration,
@@ -165,29 +180,6 @@ impl Countdown {
self.start_timestamp = None;
self.target_timestamp = None;
}
pub fn start_epoch_ms(&self) -> u128 {
let anchor_instant = Instant::now();
let anchor_epoch_ms = SystemTime::now();
let anchor_epoch_ms = anchor_epoch_ms.duration_since(UNIX_EPOCH).unwrap();
anchor_instant
.checked_duration_since(self.start_timestamp.unwrap())
.unwrap()
.as_millis()
- anchor_epoch_ms.as_millis()
}
pub fn target_epoch_ms(&self) -> u128 {
let anchor_instant = Instant::now();
let anchor_epoch_ms = SystemTime::now();
let anchor_epoch_ms = anchor_epoch_ms.duration_since(UNIX_EPOCH).unwrap();
self.target_timestamp
.unwrap()
.checked_duration_since(anchor_instant)
.unwrap()
.as_millis()
+ anchor_epoch_ms.as_millis()
}
}
#[cfg(test)]

View File

@@ -1,14 +1,22 @@
use crate::countdown::model::{Countdown, CountdownError, CountdownState};
use tokio::sync::Mutex;
use tokio::time::{Duration, Instant};
use crate::countdown::dto::CountdownSnapshotDto;
use crate::countdown::model::{Countdown, CountdownError};
#[derive(Debug)]
pub struct CountdownService {
countdown: Mutex<Countdown>,
}
#[derive(Debug)]
pub struct CountdownSnapshot {
pub id: u64,
pub label: String,
pub state: CountdownState,
pub duration: Duration,
pub start_instant: Option<Instant>,
pub target_instant: Option<Instant>,
}
impl CountdownService {
pub fn default() -> Self {
Self::new(0, "Countdown0", Duration::new(600, 0))
@@ -20,15 +28,15 @@ impl CountdownService {
}
}
pub async fn snapshot(&self, now: Instant) -> CountdownSnapshotDto {
let countdown = self.countdown.lock().await;
CountdownSnapshotDto {
id: countdown.id,
label: countdown.label.to_string(),
pub async fn snapshot(&self, now: Instant) -> CountdownSnapshot {
let countdown = self.countdown.lock().await.clone();
CountdownSnapshot {
id: countdown.id(),
label: countdown.label().parse().unwrap(),
state: countdown.state(),
duration: countdown.remaining(),
start_epoch_ms: Some(countdown.start_epoch_ms()),
target_epoch_ms: Some(countdown.target_epoch_ms()),
duration: countdown.remaining_at(now),
start_instant: countdown.start_timestamp(),
target_instant: countdown.target_timestamp(),
}
}

View File

@@ -1,3 +1,5 @@
extern crate core;
mod app_state;
mod countdown;