use crate::model::{
attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
ic_observation::{IcObservationRequestError, ObservationReservation},
ic_request::{IcManagementMethodRecord, IcManagementRequestRecord},
ic_snapshot_upload::{
IcSnapshotUploadAttemptError, IcSnapshotUploadKind, IcSnapshotUploadRequest,
original_authority,
},
operation_plan::OperationPlanRecord,
};
use thiserror::Error;
#[derive(Debug)]
pub struct IcSnapshotUploadObservationRequest<'request, 'source> {
plan: &'request OperationPlanRecord,
mutation: &'request IcSnapshotUploadRequest<'source>,
payload: &'request IcManagementRequestRecord,
authority: AttemptAuthorityRecord,
mutation_attempt: u32,
observation_attempt: u32,
}
impl<'request, 'source> IcSnapshotUploadObservationRequest<'request, 'source> {
pub fn new(
plan: &'request OperationPlanRecord,
operation_sequence: u64,
journal: &AttemptJournalRecord,
mutation: &'request IcSnapshotUploadRequest<'source>,
payload: &'request IcManagementRequestRecord,
) -> Result<Self, IcSnapshotUploadObservationError> {
if !matches!(mutation.kind(), IcSnapshotUploadKind::Metadata) {
return Err(IcSnapshotUploadObservationError::UnsupportedUpload);
}
if payload.method() != IcManagementMethodRecord::ListCanisterSnapshots {
return Err(IcSnapshotUploadObservationError::UnsupportedObservation);
}
let authority = original_authority(plan, operation_sequence, journal, mutation)?;
payload
.validate_observation_binding(authority.binding(), &payload.digest())
.map_err(IcObservationRequestError::from)?;
let current = journal.view();
let request = Self {
plan,
mutation,
payload,
authority,
mutation_attempt: current
.pending_mutation
.ok_or(IcObservationRequestError::NoPendingMutation)?,
observation_attempt: current
.pending_observation
.ok_or(IcObservationRequestError::NoPendingObservation)?,
};
request.validate_journal(journal)?;
Ok(request)
}
#[must_use]
pub const fn plan(&self) -> &OperationPlanRecord {
self.plan
}
#[must_use]
pub const fn mutation(&self) -> &'request IcSnapshotUploadRequest<'source> {
self.mutation
}
#[must_use]
pub const fn payload(&self) -> &'request IcManagementRequestRecord {
self.payload
}
#[must_use]
pub const fn authority(&self) -> &AttemptAuthorityRecord {
&self.authority
}
#[must_use]
pub const fn mutation_attempt(&self) -> u32 {
self.mutation_attempt
}
#[must_use]
pub const fn observation_attempt(&self) -> u32 {
self.observation_attempt
}
pub fn validate_journal(
&self,
journal: &AttemptJournalRecord,
) -> Result<(), IcObservationRequestError> {
ObservationReservation {
authority: &self.authority,
mutation_attempt: self.mutation_attempt,
observation_attempt: self.observation_attempt,
payload: self.payload,
}
.validate(journal)
}
}
#[derive(Debug, Error)]
pub enum IcSnapshotUploadObservationError {
#[error("snapshot upload observation requires metadata intent")]
UnsupportedUpload,
#[error("snapshot upload observation requires snapshot list")]
UnsupportedObservation,
#[error(transparent)]
Upload(#[from] IcSnapshotUploadAttemptError),
#[error(transparent)]
Observation(#[from] IcObservationRequestError),
}
#[cfg(test)]
mod tests;