use crate::{
model::{
ic_snapshot_transfer_read::{
IcSnapshotTransferReadError, IcSnapshotTransferReadPayload,
IcSnapshotTransferReadRequest, IcSnapshotTransferReadResponse,
},
operation_plan::OperationPlanError,
},
ops::persistence::{
AttemptJournalError, AttemptJournalGuard, ExecutionProgressPersistenceError,
ExecutionStageGuard, ExecutionWorkflowPersistenceError,
},
policy::ic_snapshot_transfer_read::{
IcSnapshotTransferReadAssociationError, IcSnapshotTransferReadView, validate_response,
},
ports::{
ic_observation::IcObservationProviderError,
ic_snapshot_transfer_read::IcSnapshotTransferReadProvider,
},
};
use thiserror::Error;
pub(super) async fn read_snapshot_with<E: std::error::Error + 'static, T>(
stage: &ExecutionStageGuard<'_>,
operation_sequence: u64,
payload: IcSnapshotTransferReadPayload<'_, '_>,
provider: &mut impl IcSnapshotTransferReadProvider,
admit: impl AsyncFnOnce(&IcSnapshotTransferReadRequest<'_, '_>) -> Result<(), E>,
complete: impl AsyncFnOnce(
&mut AttemptJournalGuard<'_>,
&IcSnapshotTransferReadRequest<'_, '_>,
&IcSnapshotTransferReadView<'_, '_>,
) -> T,
) -> Result<(IcSnapshotTransferReadResponse, T), IcSnapshotTransferReadExecutionError<E>> {
let plan = stage.plan();
let authority = plan.attempt_authority(operation_sequence)?;
payload.validate_binding(&authority)?;
let (response, result) = super::ic_mutation::execute_reserved(
stage,
&authority,
|_| Ok::<_, IcSnapshotTransferReadExecutionError<E>>(()),
|journal| {
Ok(IcSnapshotTransferReadRequest::new(
plan,
operation_sequence,
journal,
payload,
)?)
},
async |request| {
admit(request)
.await
.map_err(IcSnapshotTransferReadExecutionError::Admission)?;
stage.layout()?;
Ok(())
},
async |request, journal| Ok(provider.read_snapshot(request, journal).await?),
async |journal, request, response| {
let admitted = validate_response(request, journal.record()?, response)?;
stage.layout()?;
Ok::<_, IcSnapshotTransferReadReplyError>(complete(journal, request, &admitted).await)
},
)
.await?;
super::qualified_receipt::retain_reply(response, result, |source, response| {
IcSnapshotTransferReadExecutionError::AfterReply { source, response }
})
}
#[derive(Debug, Error)]
pub enum IcSnapshotTransferReadExecutionError<E: std::error::Error + 'static> {
#[error(transparent)]
Plan(#[from] OperationPlanError),
#[error(transparent)]
Stage(#[from] ExecutionWorkflowPersistenceError),
#[error(transparent)]
Journal(#[from] AttemptJournalError),
#[error(transparent)]
Progress(#[from] ExecutionProgressPersistenceError),
#[error(transparent)]
Request(#[from] IcSnapshotTransferReadError),
#[error("fresh snapshot read admission failed: {0}")]
Admission(#[source] E),
#[error(transparent)]
Provider(#[from] IcObservationProviderError),
#[error("snapshot transfer read reply rejected: {source}")]
AfterReply {
source: IcSnapshotTransferReadReplyError,
response: Box<IcSnapshotTransferReadResponse>,
},
}
#[derive(Debug, Error)]
pub enum IcSnapshotTransferReadReplyError {
#[error(transparent)]
Journal(#[from] AttemptJournalError),
#[error(transparent)]
Association(#[from] IcSnapshotTransferReadAssociationError),
#[error(transparent)]
Stage(#[from] ExecutionWorkflowPersistenceError),
}
#[cfg(all(test, unix))]
mod tests;