To create an event listener, begin by defining a struct or enum which will listen to events:
use gadget_sdk::event_listener::EventListener;
use async_trait::async_trait;
/// Define a simple event listener that ticks every MS milliseconds.
pub struct Ticker<const MSEC: usize> {
additional_delay: u64,
}
Then, define a context for the event listener:
#[derive(Copy, Clone)]
pub struct MyContext {
pub additional_delay: u64,
}
Next, implement EventListener
for Ticker
:
/// Implement the [`EventListener`] trait for the Ticker struct. [`EventListener`] has two type parameters:
///
/// - T: is the type of the event that the listener listens for. This can be anything that is Send + Sync + 'static.
/// In this case, we are using [`Instant`], which is a timestamp.
///
/// - Ctx: is the context type that the listener receives when constructed. This can be anything that is Send + Sync + 'static,
/// with the special requirement that it is the *first* listed additional parameter in the [`job`] macro (i.e., a parameter not
/// in params(...)). In this case, we are using [`MyContext`].
#[async_trait]
impl<const MSEC: usize> EventListener<Instant, MyContext> for Ticker<MSEC> {
/// Use a reference to the context, [`MyContext`], to construct the listener
async fn new(context: &MyContext) -> Result<Self, Error>
where
Self: Sized,
{
Ok(Self { additional_delay: context.additional_delay })
}
/// Implement the logic that looks for events. In this case, we have a simple stream
/// that returns after MS milliseconds.
async fn next_event(&mut self) -> Option<Instant> {
tokio::time::sleep(tokio::time::Duration::from_millis(MSEC as u64 + self.additional_delay)).await;
Some(Instant::now())
}
/// After next_event is called, the event gets passed here. This is where you would implement
/// listener-specific logic.
async fn handle_event(&mut self, _event: Instant) -> Result<(), Error> {
Ok(())
}
}
Finally, register the event listener inside the job
macro using event_listener
:
#[job(
id = 0,
params(x),
result(_),
event_listener(listener = Ticker::<6000>), // <-- Register the event listener here
)]
pub fn hello_event_listener(
x: u64,
context: MyContext, // <-- The context type must be the first additional parameter
) -> Result<u64, Infallible> {
Ok(x.saturating_pow(2u32))
}