canic_backup/persistence/
layout.rs1use crate::{
8 execution::BackupExecutionJournal,
9 journal::DownloadJournal,
10 manifest::DeploymentBackupManifest,
11 persistence::{
12 BackupExecutionIntegrityReport, BackupIntegrityReport, PersistenceError,
13 integrity::{verify_execution_integrity, verify_layout_integrity},
14 json::{read_json, write_json_atomic},
15 },
16 plan::BackupPlan,
17};
18
19use std::path::{Path, PathBuf};
20
21const MANIFEST_FILE_NAME: &str = "deployment-backup-manifest.json";
22const BACKUP_PLAN_FILE_NAME: &str = "backup-plan.json";
23const JOURNAL_FILE_NAME: &str = "download-journal.json";
24const EXECUTION_JOURNAL_FILE_NAME: &str = "backup-execution-journal.json";
25
26#[derive(Clone, Debug)]
34pub struct BackupLayout {
35 root: PathBuf,
36}
37
38impl BackupLayout {
39 #[must_use]
41 pub const fn new(root: PathBuf) -> Self {
42 Self { root }
43 }
44
45 #[must_use]
47 pub fn root(&self) -> &Path {
48 &self.root
49 }
50
51 #[must_use]
53 pub fn manifest_path(&self) -> PathBuf {
54 self.root.join(MANIFEST_FILE_NAME)
55 }
56
57 #[must_use]
59 pub fn backup_plan_path(&self) -> PathBuf {
60 self.root.join(BACKUP_PLAN_FILE_NAME)
61 }
62
63 #[must_use]
65 pub fn journal_path(&self) -> PathBuf {
66 self.root.join(JOURNAL_FILE_NAME)
67 }
68
69 #[must_use]
71 pub fn execution_journal_path(&self) -> PathBuf {
72 self.root.join(EXECUTION_JOURNAL_FILE_NAME)
73 }
74
75 pub fn write_manifest(
77 &self,
78 manifest: &DeploymentBackupManifest,
79 ) -> Result<(), PersistenceError> {
80 manifest.validate()?;
81 write_json_atomic(&self.manifest_path(), manifest)
82 }
83
84 pub fn read_manifest(&self) -> Result<DeploymentBackupManifest, PersistenceError> {
86 let manifest = read_json(&self.manifest_path())?;
87 DeploymentBackupManifest::validate(&manifest)?;
88 Ok(manifest)
89 }
90
91 pub fn write_backup_plan(&self, plan: &BackupPlan) -> Result<(), PersistenceError> {
93 plan.validate()?;
94 write_json_atomic(&self.backup_plan_path(), plan)
95 }
96
97 pub fn read_backup_plan(&self) -> Result<BackupPlan, PersistenceError> {
99 let plan = read_json(&self.backup_plan_path())?;
100 BackupPlan::validate(&plan)?;
101 Ok(plan)
102 }
103
104 pub fn write_journal(&self, journal: &DownloadJournal) -> Result<(), PersistenceError> {
106 journal.validate()?;
107 write_json_atomic(&self.journal_path(), journal)
108 }
109
110 pub fn read_journal(&self) -> Result<DownloadJournal, PersistenceError> {
112 let journal = read_json(&self.journal_path())?;
113 DownloadJournal::validate(&journal)?;
114 Ok(journal)
115 }
116
117 pub fn write_execution_journal(
119 &self,
120 journal: &BackupExecutionJournal,
121 ) -> Result<(), PersistenceError> {
122 journal.validate()?;
123 write_json_atomic(&self.execution_journal_path(), journal)
124 }
125
126 pub fn read_execution_journal(&self) -> Result<BackupExecutionJournal, PersistenceError> {
128 let journal = read_json(&self.execution_journal_path())?;
129 BackupExecutionJournal::validate(&journal)?;
130 Ok(journal)
131 }
132
133 pub fn verify_integrity(&self) -> Result<BackupIntegrityReport, PersistenceError> {
135 let manifest = self.read_manifest()?;
136 let journal = self.read_journal()?;
137 verify_layout_integrity(self, &manifest, &journal)
138 }
139
140 pub fn verify_execution_integrity(
142 &self,
143 ) -> Result<BackupExecutionIntegrityReport, PersistenceError> {
144 let plan = self.read_backup_plan()?;
145 let journal = self.read_execution_journal()?;
146 verify_execution_integrity(&plan, &journal)
147 }
148}