Skip to main content

rightkit_control/
events.rs

1//! Content-free lifecycle events for the caller's journal.
2//!
3//! Mirrors `rightkit_service::ServiceEvent` / `EventFn`: one `Arc<dyn Fn>` sink
4//! the host installs. Events never carry request payloads (typed text, JS,
5//! coordinates); only ids, kinds, method names, outcomes and lease numbers.
6use std::sync::Arc;
7
8use crate::admission::{EffectAdmissionStage, EffectKind, SettleOutcome};
9
10/// Lifecycle event emitted by [`crate::admission::EffectGate`] and
11/// [`crate::lease::InputLease`].
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum ControlEvent {
14    /// The request passed admission and its executor is about to run.
15    EffectStarted {
16        id: u64,
17        kind: EffectKind,
18        method: String,
19    },
20    /// The executor returned (ok/failed/cancelled), or a cancelled request was
21    /// settled before execution (`executed == false`).
22    EffectStopped {
23        id: u64,
24        kind: EffectKind,
25        method: String,
26        outcome: SettleOutcome,
27        executed: bool,
28    },
29    /// The executor panicked. Settled as `Failed`; the panic is contained.
30    EffectCrashed {
31        id: u64,
32        kind: EffectKind,
33        method: String,
34    },
35    /// Validation or approval refused the request; nothing executed.
36    EffectDenied {
37        id: u64,
38        kind: EffectKind,
39        method: String,
40        stage: EffectAdmissionStage,
41        reason: String,
42    },
43    /// A controller acquired the input lease at `epoch`.
44    LeaseAcquired { lease: String, epoch: u64 },
45    /// An attached holder at `old_epoch` was fenced by a new acquisition.
46    LeaseFenced {
47        lease: String,
48        old_epoch: u64,
49        new_epoch: u64,
50    },
51    /// The current holder released the lease.
52    LeaseReleased { lease: String, epoch: u64 },
53    /// Input was refused by lease fencing / sequencing (never executed).
54    InputRejected {
55        lease: String,
56        epoch: u64,
57        sequence: u64,
58        reason: &'static str,
59    },
60}
61
62/// Callback for [`ControlEvent`]s. A panicking sink is contained and ignored.
63pub type EventSink = Arc<dyn Fn(&ControlEvent) + Send + Sync>;
64
65pub(crate) fn emit(sink: &Option<EventSink>, event: ControlEvent) {
66    if let Some(sink) = sink {
67        let sink = sink.clone();
68        let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || sink(&event)));
69    }
70}