Skip to main content

shipper_core/state/store/
fs.rs

1//! Filesystem-backed implementation of [`StateStore`].
2
3use std::path::{Path, PathBuf};
4
5use anyhow::{Context, Result};
6
7use crate::state::events::EventLog;
8use crate::state::execution_state as state;
9use crate::types::{ExecutionState, Receipt};
10
11use super::StateStore;
12
13/// Filesystem-based state store implementation.
14///
15/// This is the default implementation that stores state in a local directory.
16pub struct FileStore {
17    state_dir: PathBuf,
18}
19
20impl FileStore {
21    /// Create a new FileStore with the specified state directory
22    pub fn new(state_dir: PathBuf) -> Self {
23        Self { state_dir }
24    }
25
26    /// Get the state directory path
27    pub fn state_dir(&self) -> &Path {
28        &self.state_dir
29    }
30}
31
32impl StateStore for FileStore {
33    fn save_state(&self, state: &ExecutionState) -> Result<()> {
34        state::save_state(&self.state_dir, state)
35    }
36
37    fn load_state(&self) -> Result<Option<ExecutionState>> {
38        state::load_state(&self.state_dir)
39    }
40
41    fn save_receipt(&self, receipt: &Receipt) -> Result<()> {
42        state::write_receipt(&self.state_dir, receipt)
43    }
44
45    fn load_receipt(&self) -> Result<Option<Receipt>> {
46        state::load_receipt(&self.state_dir)
47    }
48
49    fn save_events(&self, events: &EventLog) -> Result<()> {
50        let path = crate::state::events::events_path(&self.state_dir);
51        events.write_to_file(&path)
52    }
53
54    fn load_events(&self) -> Result<Option<EventLog>> {
55        let path = crate::state::events::events_path(&self.state_dir);
56        if !path.exists() {
57            return Ok(None);
58        }
59        Ok(Some(EventLog::read_from_file(&path)?))
60    }
61
62    fn clear(&self) -> Result<()> {
63        let state_path = state::state_path(&self.state_dir);
64        let receipt_path = state::receipt_path(&self.state_dir);
65        let reconciliation_path = state::reconciliation_path(&self.state_dir);
66        let events_path = crate::state::events::events_path(&self.state_dir);
67
68        // Remove files if they exist
69        if state_path.exists() {
70            std::fs::remove_file(&state_path)
71                .with_context(|| format!("failed to remove state file {}", state_path.display()))?;
72        }
73        if receipt_path.exists() {
74            std::fs::remove_file(&receipt_path).with_context(|| {
75                format!("failed to remove receipt file {}", receipt_path.display())
76            })?;
77        }
78        if reconciliation_path.exists() {
79            std::fs::remove_file(&reconciliation_path).with_context(|| {
80                format!(
81                    "failed to remove reconciliation file {}",
82                    reconciliation_path.display()
83                )
84            })?;
85        }
86        if events_path.exists() {
87            std::fs::remove_file(&events_path).with_context(|| {
88                format!("failed to remove events file {}", events_path.display())
89            })?;
90        }
91
92        Ok(())
93    }
94}