gestura_core/checkpoints/
manager.rs

1//! High-level checkpoint APIs.
2
3use chrono::Utc;
4
5use super::{
6    store::FileCheckpointStore,
7    types::{
8        Checkpoint, CheckpointError, CheckpointId, CheckpointMetadata, CheckpointRetentionPolicy,
9        CheckpointSnapshot,
10    },
11};
12
13/// Checkpoint manager responsible for creating, listing, and restoring checkpoints.
14#[derive(Debug, Clone)]
15pub struct CheckpointManager {
16    store: FileCheckpointStore,
17    policy: CheckpointRetentionPolicy,
18}
19
20impl CheckpointManager {
21    /// Create a checkpoint manager.
22    pub fn new(store: FileCheckpointStore, policy: CheckpointRetentionPolicy) -> Self {
23        Self { store, policy }
24    }
25
26    /// Create a manager using default store directory and default policy.
27    pub fn new_default() -> Self {
28        Self::new(
29            FileCheckpointStore::new_default(),
30            CheckpointRetentionPolicy::default(),
31        )
32    }
33
34    /// Create and persist a checkpoint.
35    pub fn create_checkpoint(
36        &self,
37        snapshot: CheckpointSnapshot,
38        label: Option<String>,
39    ) -> Result<CheckpointMetadata, CheckpointError> {
40        let id = CheckpointId::new();
41        let metadata = CheckpointMetadata {
42            id,
43            session_id: snapshot.session_id.clone(),
44            created_at: Utc::now(),
45            label,
46        };
47        let checkpoint = Checkpoint {
48            metadata: metadata.clone(),
49            snapshot,
50        };
51        self.store.save(&checkpoint)?;
52        self.enforce_retention()?;
53        Ok(metadata)
54    }
55
56    /// Restore a checkpoint snapshot.
57    pub fn restore_checkpoint(
58        &self,
59        id: &CheckpointId,
60    ) -> Result<CheckpointSnapshot, CheckpointError> {
61        Ok(self.store.load(id)?.snapshot)
62    }
63
64    /// List all checkpoints (metadata only), sorted by creation time ascending.
65    pub fn list_checkpoints(&self) -> Result<Vec<CheckpointMetadata>, CheckpointError> {
66        let mut items = self.store.list_metadata()?;
67        items.sort_by_key(|m| m.created_at);
68        Ok(items)
69    }
70
71    /// Enforce the configured retention policy by deleting the oldest checkpoints first.
72    fn enforce_retention(&self) -> Result<(), CheckpointError> {
73        if self.policy.max_checkpoints == 0 {
74            return Ok(());
75        }
76
77        let mut items = self.list_checkpoints()?;
78        while items.len() > self.policy.max_checkpoints {
79            if let Some(oldest) = items.first() {
80                self.store.delete(&oldest.id)?;
81            }
82            items.remove(0);
83        }
84        Ok(())
85    }
86}