made_core/entities/ceremony_instance/
step_execution.rs1use crate::entities::ceremony_commands::{ApplyStepResult, StartStep};
2use crate::entities::CeremonyCommand;
3use crate::value_objects::{MaxParallel, StepClaimFence};
4
5use super::{
6 CeremonyDefinition, CeremonyEvent, CeremonyInstance, DomainError, OffsetDateTime, RoleId,
7 StepAttempt, StepId, StepLease, StepResult,
8};
9
10impl CeremonyInstance {
14 pub fn start_step_as(
15 &mut self,
16 definition: &CeremonyDefinition,
17 role_id: &RoleId,
18 step_id: &StepId,
19 lease: StepLease,
20 now: OffsetDateTime,
21 ) -> Result<StepAttempt, DomainError> {
22 self.start_step_with(
23 definition,
24 Some(role_id.clone()),
25 step_id,
26 lease,
27 now,
28 MaxParallel::SERVER_MAX,
29 )
30 }
31
32 pub fn start_step(
33 &mut self,
34 definition: &CeremonyDefinition,
35 step_id: &StepId,
36 lease: StepLease,
37 now: OffsetDateTime,
38 ) -> Result<StepAttempt, DomainError> {
39 self.start_step_with(
40 definition,
41 None,
42 step_id,
43 lease,
44 now,
45 MaxParallel::SERVER_MAX,
46 )
47 }
48
49 fn start_step_with(
50 &mut self,
51 definition: &CeremonyDefinition,
52 role_id: Option<RoleId>,
53 step_id: &StepId,
54 lease: StepLease,
55 now: OffsetDateTime,
56 max_parallel_ceiling: MaxParallel,
57 ) -> Result<StepAttempt, DomainError> {
58 let command = CeremonyCommand::StartStep(StartStep {
59 role_id,
60 step_id: step_id.clone(),
61 lease,
62 now,
63 max_parallel_ceiling,
64 });
65 let events = self.decide(&command, definition)?;
66 let attempt = events
67 .iter()
68 .find_map(|event| match event {
69 CeremonyEvent::StepStarted(started) => Some(started.attempt),
70 _ => None,
71 })
72 .ok_or(DomainError::InvariantViolated {
73 reason: "starting a step decides a step start",
74 })?;
75 self.apply_all(&events);
76 Ok(attempt)
77 }
78
79 pub fn step_claim_fence(&self, step_id: &StepId) -> Result<StepClaimFence, DomainError> {
81 let record = self.step_record(step_id).ok_or(DomainError::NotFound {
82 what: "ceremony_instance.step_record",
83 })?;
84 StepClaimFence::for_record(self.id(), step_id, record)
85 }
86
87 pub(super) fn require_step_claim_fence(
88 &self,
89 step_id: &StepId,
90 fence: &StepClaimFence,
91 ) -> Result<(), DomainError> {
92 if &self.step_claim_fence(step_id)? != fence {
93 return Err(DomainError::InvariantViolated {
94 reason: "step completion claim fence does not match the current claim",
95 });
96 }
97 Ok(())
98 }
99
100 pub fn apply_step_result(
101 &mut self,
102 definition: &CeremonyDefinition,
103 step_id: &StepId,
104 claim_fence: StepClaimFence,
105 result: StepResult,
106 now: OffsetDateTime,
107 ) -> Result<(), DomainError> {
108 let command = CeremonyCommand::ApplyStepResult(ApplyStepResult {
109 step_id: step_id.clone(),
110 claim_fence,
111 result,
112 now,
113 });
114 let events = self.decide(&command, definition)?;
115 self.apply_all(&events);
116 Ok(())
117 }
118}