use nasaga_backend::TimerScope;
use nasaga_core::{AttemptNo, Direction, SagaId, StepName, StepPhase};
use uuid::Uuid;
use crate::envelope::canonical_bytes;
pub const KIND_STEP_TIMEOUT: &str = "step-timeout";
pub const KIND_INSTANCE_DEADLINE: &str = "instance-deadline";
pub const KIND_RESOLUTION_BUDGET: &str = "resolution-budget";
pub const KIND_FORWARD_RESOLUTION_BUDGET: &str = "forward-resolution-budget";
pub const KIND_COMPENSATION_RESOLUTION_BUDGET: &str = "compensation-resolution-budget";
pub const KIND_CANCEL_TIMEOUT: &str = "cancel-timeout";
pub const KIND_COMPENSATE_TIMEOUT: &str = "compensate-timeout";
pub const KIND_RESOLVE_TIMEOUT: &str = "resolve-timeout";
const TIMER_ID_NAMESPACE: Uuid = Uuid::from_bytes(*b"nasasaga-v1-tmid");
pub fn derive_timer_id(
saga_id: &SagaId,
scope: &TimerScope<'_>,
kind: &str,
attempt: AttemptNo,
) -> String {
Uuid::new_v5(
&TIMER_ID_NAMESPACE,
&canonical_bytes(&[
saga_id.as_str().as_bytes(),
scope.kind_str().as_bytes(),
scope.key_str().as_bytes(),
kind.as_bytes(),
&attempt.get().to_be_bytes(),
]),
)
.to_string()
}
pub fn phase_timeout_kind(phase: StepPhase) -> &'static str {
match phase {
StepPhase::Execute => KIND_STEP_TIMEOUT,
StepPhase::Cancel => KIND_CANCEL_TIMEOUT,
StepPhase::Compensate => KIND_COMPENSATE_TIMEOUT,
StepPhase::Resolve => KIND_RESOLVE_TIMEOUT,
}
}
pub(crate) fn resolution_budget_kind(direction: Direction) -> &'static str {
match direction {
Direction::Forward => KIND_FORWARD_RESOLUTION_BUDGET,
Direction::Compensating => KIND_COMPENSATION_RESOLUTION_BUDGET,
}
}
pub fn parse_step_scope(scope_kind: &str, scope_key: &str) -> anyhow::Result<Option<StepName>> {
match scope_kind {
"INSTANCE" => Ok(None),
"STEP" => {
Ok(Some(StepName::new(scope_key).map_err(|v| {
anyhow::anyhow!("bad step scope: {}", v.code())
})?))
}
_ => anyhow::bail!("unknown timer scope kind"),
}
}