Skip to main content

ircbot/
handler.rs

1//! What fires a handler, and the shape of the handler itself.
2//!
3//! A [`Trigger`] describes a condition on an incoming message, or a schedule.
4//! A [`HandlerEntry`] pairs one trigger with the function to call. The bot holds
5//! a list of these entries and tests each incoming message against all of them.
6//!
7//! The `#[command]` and `#[on]` macros build these values for you. Construct
8//! them by hand only when you assemble a handler list without the macros.
9
10use std::future::Future;
11use std::pin::Pin;
12use std::sync::Arc;
13
14use crate::context::Context;
15
16/// A boxed, heap-allocated future that is `Send + 'static`.
17pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
18
19/// The type-erased handler function stored in [`HandlerEntry`].
20pub type HandlerFn<T> = Box<dyn Fn(Arc<T>, Context) -> BoxFuture<crate::Result> + Send + Sync>;
21
22/// What causes a handler to fire.
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum Trigger {
25    /// Fires when the user sends `!<name>` (optionally in a specific channel).
26    ///
27    /// When `role` is `Some`, the command only fires for senders whose
28    /// `nick!user@host` matches one of the hostmask patterns configured for that
29    /// role (see [`State::with_role`](crate::State::with_role)); unauthorized
30    /// senders are silently ignored.
31    Command {
32        /// The command word that follows the `!` prefix.
33        name: String,
34        /// When set, the command fires only in this channel or query.
35        target: Option<String>,
36        /// When set, the command fires only for senders that hold this role.
37        role: Option<String>,
38    },
39    /// Fires when an incoming PRIVMSG matches a glob pattern (`*` as wildcard).
40    Message {
41        /// The glob pattern matched against the message text.
42        pattern: String,
43        /// When set, the pattern applies only to messages sent to this target.
44        target: Option<String>,
45    },
46    /// Fires on a specific IRC event (e.g. "JOIN"), with optional target/regex filter.
47    Event {
48        /// The IRC command or numeric that fires the handler, compared
49        /// without case sensitivity.
50        event: String,
51        /// When set, the handler fires only for events on this target.
52        target: Option<String>,
53        /// When set, the trailing parameter of the message must also match this
54        /// regular expression. Its capture groups become the handler's captures.
55        regex: Option<String>,
56    },
57    /// Fires when a PRIVMSG addresses the bot by name at the start of the
58    /// message (e.g. `"botname: hello"` or `"botname, ping"`).
59    /// The text following the address prefix is provided as a capture.
60    Mention {
61        /// When set, the handler fires only for messages sent to this target.
62        target: Option<String>,
63    },
64    /// Fires on a schedule described by a cron expression.  The expression uses
65    /// the 6-field Quartz format: `sec min hour day-of-month month day-of-week`
66    /// with an optional 7th `year` field.  Times are evaluated in `tz`, which
67    /// must be a valid IANA timezone name (e.g. `"America/New_York"`); defaults
68    /// to `"UTC"` when not specified.
69    ///
70    /// When `target` is `None` the handler's [`Context::target`] is a
71    /// [`Target::User`](crate::Target::User) with an empty name (so its
72    /// `as_str()` is empty) and [`Context::is_channel`] returns `false`.
73    /// Handlers that need to send a message should either specify a `target` or
74    /// store the destination in their bot state.
75    ///
76    /// Example — top of every hour on weekday afternoons (Eastern time):
77    /// `"0 0 8-16 * * MON-FRI"` with `tz = "America/New_York"`
78    Cron {
79        /// The cron expression, in 6-field Quartz format with an optional
80        /// 7th `year` field.
81        schedule: String,
82        /// The IANA timezone name that the schedule is evaluated in.
83        tz: String,
84        /// When set, the handler's [`Context::target`] is this channel or user.
85        target: Option<String>,
86    },
87}
88
89/// Associates a [`Trigger`] with a handler function for a bot of type `T`.
90pub struct HandlerEntry<T> {
91    /// What causes the handler to fire.
92    pub trigger: Trigger,
93    /// The function called when the trigger matches.
94    pub handler: HandlerFn<T>,
95}