use crate::model::{
attempt_journal::AttemptJournalRecord,
ic_lifecycle_reply::{IcLifecycleReply, IcLifecycleReplyError},
ic_observation::{IcObservationRequest, IcObservationRequestError, IcObservationResponse},
ic_request::IcManagementMethodRecord,
ic_snapshot_reply::{IcSnapshotReply, IcSnapshotReplyError},
};
use thiserror::Error;
#[derive(Debug)]
pub enum IcObservationReplyView<'a> {
Inventory(IcSnapshotReply<'a>),
Status(IcLifecycleReply<'a>),
}
#[derive(Debug)]
pub struct IcObservationResponseView<'a> {
response: &'a IcObservationResponse,
reply: IcObservationReplyView<'a>,
}
impl<'a> IcObservationResponseView<'a> {
#[must_use]
pub const fn response(&self) -> &'a IcObservationResponse {
self.response
}
#[must_use]
pub const fn reply(&self) -> &IcObservationReplyView<'a> {
&self.reply
}
}
pub fn validate_response<'a>(
request: &IcObservationRequest<'a>,
journal: &AttemptJournalRecord,
response: &'a IcObservationResponse,
) -> Result<IcObservationResponseView<'a>, IcObservationAssociationError> {
request.validate_journal(journal)?;
let input = response.input();
if input.authority != request.authority().digest() {
return Err(IcObservationAssociationError::AuthorityMismatch);
}
if input.mutation_attempt != request.mutation_attempt()
|| input.observation_attempt != request.observation_attempt()
{
return Err(IcObservationAssociationError::AttemptMismatch);
}
if input.request != request.payload().digest() {
return Err(IcObservationAssociationError::RequestMismatch);
}
if &input.context != request.plan().context() {
return Err(IcObservationAssociationError::ContextMismatch);
}
if input.target != request.payload().target() {
return Err(IcObservationAssociationError::TargetMismatch);
}
let reply = match request.payload().method() {
IcManagementMethodRecord::ListCanisterSnapshots => IcObservationReplyView::Inventory(
IcSnapshotReply::decode(request.payload(), &input.reply)?,
),
_ => IcObservationReplyView::Status(IcLifecycleReply::decode(
request.payload(),
&input.reply,
)?),
};
Ok(IcObservationResponseView { response, reply })
}
#[derive(Debug, Error)]
pub enum IcObservationAssociationError {
#[error(transparent)]
Reservation(#[from] IcObservationRequestError),
#[error("IC observation response authority mismatch")]
AuthorityMismatch,
#[error("IC observation response attempt mismatch")]
AttemptMismatch,
#[error("IC observation response request mismatch")]
RequestMismatch,
#[error("IC observation response context mismatch")]
ContextMismatch,
#[error("IC observation response target mismatch")]
TargetMismatch,
#[error(transparent)]
Inventory(#[from] IcSnapshotReplyError),
#[error(transparent)]
Status(#[from] IcLifecycleReplyError),
}
#[cfg(test)]
mod tests;