Skip to main content

ic_backup/model/application_ingress/request/
mod.rs

1//! Passive original application reservations; reconstructing one is never a resend permit.
2
3use super::{ApplicationIngressError, ApplicationIngressPayload};
4use crate::model::attempt_journal::MutationReservation;
5use crate::model::attempt_journal::MutationReservationError as Reservation;
6use crate::model::attempt_journal::ObservationReservation;
7use crate::model::{
8    attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
9    operation_plan::OperationPlanRecord,
10};
11
12/// Exact original application mutation after durable reservation.
13///
14/// The caller holds its original guard and independently admits fresh authority,
15/// dependencies, application safety and exclusive never-dispatched custody.
16#[derive(Debug)]
17pub struct ApplicationMutationRequest<'a> {
18    plan: &'a OperationPlanRecord,
19    payload: &'a ApplicationIngressPayload,
20    reservation: MutationReservation,
21}
22impl<'a> ApplicationMutationRequest<'a> {
23    /// Bind original exact opaque bytes to the current pending mutation.
24    /// # Errors
25    /// Rejects changed authority/payload, absent mutation or pending recovery.
26    pub fn new(
27        plan: &'a OperationPlanRecord,
28        sequence: u64,
29        journal: &AttemptJournalRecord,
30        payload: &'a ApplicationIngressPayload,
31    ) -> Result<Self, ApplicationIngressError> {
32        let authority = plan.attempt_authority_for_journal(
33            sequence,
34            journal,
35            ApplicationIngressError::AuthorityMismatch,
36        )?;
37        payload.validate_mutation_binding(authority.binding())?;
38        let reservation = MutationReservation::new(authority, journal)?;
39        Ok(Self {
40            plan,
41            payload,
42            reservation,
43        })
44    }
45    /// Read the complete original plan/context and inventory.
46    #[must_use]
47    pub const fn plan(&self) -> &OperationPlanRecord {
48        self.plan
49    }
50    /// Read exact opaque update fields.
51    #[must_use]
52    pub const fn payload(&self) -> &ApplicationIngressPayload {
53        self.payload
54    }
55    /// Read full original authority and finite allowances.
56    #[must_use]
57    pub const fn authority(&self) -> &AttemptAuthorityRecord {
58        &self.reservation.authority
59    }
60    /// Read the already consumed mutation attempt.
61    #[must_use]
62    pub const fn mutation_attempt(&self) -> u32 {
63        self.reservation.mutation_attempt
64    }
65    /// Recheck current exact original reservation without authorizing dispatch.
66    /// # Errors
67    /// Rejects changed authority, mutation or pending observation.
68    pub fn validate_journal(
69        &self,
70        journal: &AttemptJournalRecord,
71    ) -> Result<(), ApplicationIngressError> {
72        self.reservation.validate(journal).map_err(Into::into)
73    }
74}
75
76/// Exact separately reserved application recovery update for an unresolved mutation.
77///
78/// This consumes the observation lane, even when its opaque method reads status.
79/// It never reuses mutation allowance or supplies application settlement semantics.
80#[derive(Debug)]
81pub struct ApplicationObservationRequest<'a> {
82    plan: &'a OperationPlanRecord,
83    payload: &'a ApplicationIngressPayload,
84    reservation: ObservationReservation,
85}
86impl<'a> ApplicationObservationRequest<'a> {
87    /// Bind exact recovery bytes to the independently reserved observation digest.
88    /// # Errors
89    /// Rejects changed authority/target, absent attempts or different reserved bytes.
90    pub fn new(
91        plan: &'a OperationPlanRecord,
92        sequence: u64,
93        journal: &AttemptJournalRecord,
94        payload: &'a ApplicationIngressPayload,
95    ) -> Result<Self, ApplicationIngressError> {
96        let authority = plan.attempt_authority_for_journal(
97            sequence,
98            journal,
99            ApplicationIngressError::AuthorityMismatch,
100        )?;
101        payload.validate_observation_binding(authority.binding())?;
102        let reservation = ObservationReservation::new(authority, journal, payload.digest())
103            .map_err(crate::model::ic_observation::IcObservationRequestError::from)?;
104        Ok(Self {
105            plan,
106            payload,
107            reservation,
108        })
109    }
110    /// Read the complete original mutation plan/context and inventory.
111    #[must_use]
112    pub const fn plan(&self) -> &OperationPlanRecord {
113        self.plan
114    }
115    /// Read exact original recovery update fields.
116    #[must_use]
117    pub const fn payload(&self) -> &ApplicationIngressPayload {
118        self.payload
119    }
120    /// Read original authority; its request still names the unresolved mutation.
121    #[must_use]
122    pub const fn authority(&self) -> &AttemptAuthorityRecord {
123        &self.reservation.authority
124    }
125    /// Read the original unresolved mutation attempt.
126    #[must_use]
127    pub const fn mutation_attempt(&self) -> u32 {
128        self.reservation.mutation_attempt
129    }
130    /// Read the independently consumed observation attempt.
131    #[must_use]
132    pub const fn observation_attempt(&self) -> u32 {
133        self.reservation.observation_attempt
134    }
135    /// Recheck exact current observation identity without a dispatch permit.
136    /// # Errors
137    /// Rejects settled/replaced attempts, changed authority or different reserved bytes.
138    pub fn validate_journal(
139        &self,
140        journal: &AttemptJournalRecord,
141    ) -> Result<(), ApplicationIngressError> {
142        self.reservation
143            .validate(journal)
144            .map_err(crate::model::ic_observation::IcObservationRequestError::from)?;
145        Ok(())
146    }
147}
148
149impl From<crate::model::attempt_journal::MutationReservationError> for ApplicationIngressError {
150    fn from(error: crate::model::attempt_journal::MutationReservationError) -> Self {
151        match error {
152            Reservation::NoPendingMutation => Self::NoPendingMutation,
153            Reservation::AuthorityMismatch => Self::AuthorityMismatch,
154            Reservation::MutationMismatch => Self::MutationMismatch,
155            Reservation::ObservationPending => Self::ObservationPending,
156        }
157    }
158}