[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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
extern crate core;
|
||||
|
||||
mod app_state;
|
||||
mod countdown;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user