kimun_notes/update/
state.rs1use chrono::{DateTime, Duration, Utc};
7use serde::{Deserialize, Serialize};
8use std::io;
9use std::path::Path;
10
11const STATE_FILE: &str = "update_state.toml";
12
13const STATE_HEADER: &str = "\
14# Kimün update state — auto-generated, do not edit.
15# Tracks the last update check, the latest known release, and any version you
16# chose to skip. Your settings live in config.toml, not here.
17";
18
19#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
20pub struct UpdateState {
21 #[serde(default)]
23 pub last_check: Option<DateTime<Utc>>,
24 #[serde(default)]
26 pub latest_version: Option<String>,
27 #[serde(default)]
30 pub dismissed_version: Option<String>,
31}
32
33impl UpdateState {
34 pub fn load(config_dir: &Path) -> Self {
37 std::fs::read_to_string(config_dir.join(STATE_FILE))
38 .ok()
39 .and_then(|raw| toml::from_str(&raw).ok())
40 .unwrap_or_default()
41 }
42
43 pub fn save(&self, config_dir: &Path) -> io::Result<()> {
45 let body = toml::to_string(self).map_err(io::Error::other)?;
46 std::fs::write(config_dir.join(STATE_FILE), format!("{STATE_HEADER}{body}"))
47 }
48
49 pub fn is_stale(&self, now: DateTime<Utc>, max_age: Duration) -> bool {
51 match self.last_check {
52 Some(checked) => now.signed_duration_since(checked) >= max_age,
53 None => true,
54 }
55 }
56}