Events
Sails offers a mechanism to emit events from a service while processing commands. These events notify off-chain subscribers about state changes.
Events are declared per service via the events argument to #[service].
The event payload is a Rust enum whose variants describe each event
shape. Annotate the enum with #[event] (registers it as an event type)
and #[sails_type] (wires the SCALE codec and scale-info traits with the
correct re-export paths). When a service declares events = SomeEnum,
#[service] generates an emit_event method on the service exposure
that the command body calls to publish events.
use sails_rs::{cell::RefCell, prelude::*};
pub struct CounterData {
counter: u32,
}
impl CounterData {
pub const fn new(counter: u32) -> Self {
Self { counter }
}
}
// `#[event]` registers the enum as an event payload type.
// `#[sails_type]` wires up SCALE codec + type-info traits with the
// correct re-export paths (no manual `#[codec(crate=...)]` needed).
#[event]
#[sails_type]
#[derive(Clone, Debug, PartialEq)]
pub enum MyCounterEvent {
Incremented(u32),
}
pub struct MyCounter {
data: RefCell<CounterData>,
}
#[service(events = MyCounterEvent)]
impl MyCounter {
pub fn new(initial: u32) -> Self {
Self { data: RefCell::new(CounterData::new(initial)) }
}
#[export]
pub fn increment(&mut self) -> u32 {
let value = {
let mut data = self.data.get_mut();
data.counter += 1;
data.counter
};
// `emit_event` is generated by `#[service(events = ...)]`.
// The event is only published when the command completes
// successfully (it rides on the same message-transmission
// mechanism as any other Gear reply).
self.emit_event(MyCounterEvent::Incremented(value)).unwrap();
value
}
}Internally, events ride on the same Gear message-transmission machinery as any other reply. As a result, an event is only published when the command that emitted it completes successfully — a panic, trap, or error return cancels every event queued during the call.