gestura_core/checkpoints/
manager.rs1use chrono::Utc;
4
5use super::{
6 store::FileCheckpointStore,
7 types::{
8 Checkpoint, CheckpointError, CheckpointId, CheckpointMetadata, CheckpointRetentionPolicy,
9 CheckpointSnapshot,
10 },
11};
12
13#[derive(Debug, Clone)]
15pub struct CheckpointManager {
16 store: FileCheckpointStore,
17 policy: CheckpointRetentionPolicy,
18}
19
20impl CheckpointManager {
21 pub fn new(store: FileCheckpointStore, policy: CheckpointRetentionPolicy) -> Self {
23 Self { store, policy }
24 }
25
26 pub fn new_default() -> Self {
28 Self::new(
29 FileCheckpointStore::new_default(),
30 CheckpointRetentionPolicy::default(),
31 )
32 }
33
34 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 pub fn restore_checkpoint(
58 &self,
59 id: &CheckpointId,
60 ) -> Result<CheckpointSnapshot, CheckpointError> {
61 Ok(self.store.load(id)?.snapshot)
62 }
63
64 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 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}