use crate::journal::JournalValidationError;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DownloadJournal {
pub journal_version: u16,
pub backup_id: String,
#[serde(default)]
pub discovery_topology_hash: Option<String>,
#[serde(default)]
pub pre_snapshot_topology_hash: Option<String>,
#[serde(default)]
pub operation_metrics: DownloadOperationMetrics,
pub artifacts: Vec<ArtifactJournalEntry>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct DownloadOperationMetrics {
pub target_count: usize,
pub snapshot_create_started: usize,
pub snapshot_create_completed: usize,
pub snapshot_download_started: usize,
pub snapshot_download_completed: usize,
pub checksum_verify_started: usize,
pub checksum_verify_completed: usize,
pub artifact_finalize_started: usize,
pub artifact_finalize_completed: usize,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ArtifactJournalEntry {
pub canister_id: String,
pub snapshot_id: String,
pub state: ArtifactState,
pub temp_path: Option<String>,
pub artifact_path: String,
pub checksum_algorithm: String,
pub checksum: Option<String>,
pub updated_at: String,
}
impl ArtifactJournalEntry {
#[must_use]
pub const fn resume_action(&self) -> ResumeAction {
match self.state {
ArtifactState::Created => ResumeAction::Download,
ArtifactState::Downloaded => ResumeAction::VerifyChecksum,
ArtifactState::ChecksumVerified => ResumeAction::Finalize,
ArtifactState::Durable => ResumeAction::Skip,
}
}
pub fn advance_to(
&mut self,
next_state: ArtifactState,
updated_at: String,
) -> Result<(), JournalValidationError> {
if !self.state.can_advance_to(next_state) {
return Err(JournalValidationError::InvalidStateTransition {
from: self.state,
to: next_state,
});
}
self.state = next_state;
self.updated_at = updated_at;
Ok(())
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "PascalCase")]
pub enum ArtifactState {
Created,
Downloaded,
ChecksumVerified,
Durable,
}
impl ArtifactState {
#[must_use]
pub const fn can_advance_to(self, next: Self) -> bool {
self.as_order() <= next.as_order()
}
const fn as_order(self) -> u8 {
match self {
Self::Created => 0,
Self::Downloaded => 1,
Self::ChecksumVerified => 2,
Self::Durable => 3,
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub enum ResumeAction {
Download,
VerifyChecksum,
Finalize,
Skip,
}