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}