canic_backup/journal/
types.rs1use crate::journal::JournalValidationError;
8
9use serde::{Deserialize, Serialize};
10
11#[derive(Clone, Debug, Deserialize, Serialize)]
19pub struct DownloadJournal {
20 pub journal_version: u16,
21 pub backup_id: String,
22 #[serde(default)]
23 pub discovery_topology_hash: Option<String>,
24 #[serde(default)]
25 pub pre_snapshot_topology_hash: Option<String>,
26 #[serde(default)]
27 pub operation_metrics: DownloadOperationMetrics,
28 pub artifacts: Vec<ArtifactJournalEntry>,
29}
30
31#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
39pub struct DownloadOperationMetrics {
40 pub target_count: usize,
41 pub snapshot_create_started: usize,
42 pub snapshot_create_completed: usize,
43 pub snapshot_download_started: usize,
44 pub snapshot_download_completed: usize,
45 pub checksum_verify_started: usize,
46 pub checksum_verify_completed: usize,
47 pub artifact_finalize_started: usize,
48 pub artifact_finalize_completed: usize,
49}
50
51#[derive(Clone, Debug, Deserialize, Serialize)]
59pub struct ArtifactJournalEntry {
60 pub canister_id: String,
61 pub snapshot_id: String,
62 pub state: ArtifactState,
63 pub temp_path: Option<String>,
64 pub artifact_path: String,
65 pub checksum_algorithm: String,
66 pub checksum: Option<String>,
67 pub updated_at: String,
68}
69
70impl ArtifactJournalEntry {
71 #[must_use]
73 pub const fn resume_action(&self) -> ResumeAction {
74 match self.state {
75 ArtifactState::Created => ResumeAction::Download,
76 ArtifactState::Downloaded => ResumeAction::VerifyChecksum,
77 ArtifactState::ChecksumVerified => ResumeAction::Finalize,
78 ArtifactState::Durable => ResumeAction::Skip,
79 }
80 }
81
82 pub fn advance_to(
84 &mut self,
85 next_state: ArtifactState,
86 updated_at: String,
87 ) -> Result<(), JournalValidationError> {
88 if !self.state.can_advance_to(next_state) {
89 return Err(JournalValidationError::InvalidStateTransition {
90 from: self.state,
91 to: next_state,
92 });
93 }
94
95 self.state = next_state;
96 self.updated_at = updated_at;
97 Ok(())
98 }
99}
100
101#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
109#[serde(rename_all = "PascalCase")]
110pub enum ArtifactState {
111 Created,
112 Downloaded,
113 ChecksumVerified,
114 Durable,
115}
116
117impl ArtifactState {
118 #[must_use]
120 pub const fn can_advance_to(self, next: Self) -> bool {
121 self.as_order() <= next.as_order()
122 }
123
124 const fn as_order(self) -> u8 {
126 match self {
127 Self::Created => 0,
128 Self::Downloaded => 1,
129 Self::ChecksumVerified => 2,
130 Self::Durable => 3,
131 }
132 }
133}
134
135#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
143#[serde(rename_all = "PascalCase")]
144pub enum ResumeAction {
145 Download,
146 VerifyChecksum,
147 Finalize,
148 Skip,
149}