Skip to main content

on

Attribute Macro on 

Source
#[on]
Expand description

Registers the annotated method as an event handler inside a #[bot] impl block.

The general-purpose trigger attribute. Exactly one of command, message, event, mention, or cron must be present. target, regex, and tz are optional modifiers.

§Keys

KeyDescription
command = "name"Fires on !name; equivalent to #[command("name")] but also accepts target
message = "pattern"Glob pattern on PRIVMSG text; each * captures the matched portion as a String parameter
event = "IRC_CMD"Any raw IRC command (e.g. "JOIN", "PRIVMSG", "PART", "NICK")
mentionFires when a PRIVMSG addresses the bot by name ("botname: …" or "botname, …"); matched text is passed as first String parameter
cron = "expr"Fires on a cron schedule independent of any IRC message; uses the 6-field Quartz format (sec min hour dom month dow) with an optional 7th year field, validated at compile time
target = "#channel"(optional) Restrict the trigger to a specific channel
regex = "pattern"(optional, with event) Further filter by a regex on the message text; capture groups become String parameters
tz = "Timezone"(optional, with cron) IANA timezone for evaluating the schedule (default: "UTC"), validated at compile time

When multiple trigger keys are present, the first one in this precedence order wins: messagecommandeventmentioncron.

§Examples

message — glob pattern on PRIVMSG text. Each * captures the corresponding portion of the text as a String parameter:

// Fires on any PRIVMSG that looks like "you are <something>".
#[on(message = "you are *")]
async fn praise_me(&self, ctx: Context, praise: String) -> Result {
    ctx.say(format!("Indeed, I am {}!", praise))
}

event — any raw IRC command. Use this for protocol-level events:

// Fires whenever any user joins any channel.
#[on(event = "JOIN")]
async fn on_join(&self, ctx: Context, user: User) -> Result {
    ctx.say(format!("Welcome, {}!", user.nick))
}

event + target — restrict to a specific channel:

// Fires only when someone joins #rust.
#[on(event = "JOIN", target = "#rust")]
async fn welcome_rust(&self, ctx: Context, user: User) -> Result {
    ctx.say(format!("Welcome to #rust, {}!", user.nick))
}

event + regex — filter by a regex applied to the message text. Capture groups become String parameters in the order they appear:

// Fires on PRIVMSG lines that match `!op <nick> <reason>`.
#[on(event = "PRIVMSG", regex = r"^!op (\S+) (.+)$")]
async fn op_request(&self, ctx: Context, target_nick: String, reason: String) -> Result {
    ctx.say(format!("Granting op to {} (reason: {})", target_nick, reason))
}

command — command-style shorthand inside #[on], useful when you also need target:

#[on(command = "dance", target = "#general")]
async fn dance(&self, ctx: Context) -> Result {
    ctx.action("dances!")
}

mention — fires when a PRIVMSG directly addresses the bot by name ("botname: …" or "botname, …"). The text that follows the prefix is passed as the first String parameter:

// Fires when a user writes "mybot: hello there" in a channel.
#[on(mention)]
async fn on_mention(&self, ctx: Context, text: String) -> Result {
    ctx.reply(format!("You said: {}", text))
}

// Restrict to a specific channel.
#[on(mention, target = "#rust")]
async fn on_mention_rust(&self, ctx: Context) -> Result {
    ctx.notice("I heard you!").await
}

cron — fires the handler according to a cron schedule, independent of any IRC message. The expression uses the 6-field Quartz format backed by the cron crate:

sec  min  hour  day-of-month  month  day-of-week  [year]

Times are evaluated in UTC by default. Use tz to specify any IANA timezone (backed by chrono-tz). Both the cron expression and the timezone are validated at compile time — a typo is a compile error, not a runtime panic.

// Top of every hour, 8 a.m.–4 p.m. Eastern time, Monday–Friday.
#[on(cron = "0 0 8-16 * * MON-FRI", tz = "America/New_York", target = "#work")]
async fn work_hours_reminder(&self, ctx: Context) -> Result {
    ctx.say("Heads up: stand-up in 5 minutes!")
}

// Every 15 minutes, UTC (default when `tz` is omitted).
#[on(cron = "0 */15 * * * *", target = "#general")]
async fn quarter_hour(&self, ctx: Context) -> Result {
    ctx.say("15-minute check-in!")
}

// Every Monday at 9 a.m. Tokyo time.
#[on(cron = "0 0 9 * * MON", tz = "Asia/Tokyo")]
async fn weekly_report(&self, ctx: Context) -> Result {
    // ctx.target is empty when no target is specified;
    // use ctx.tx directly or store the channel name in bot state.
    Ok(())
}

Quick reference — common expressions:

ExpressionMeaning
"0 0 * * * *"Every hour (on the minute)
"0 0 8-16 * * MON-FRI"Top of each hour, 8 a.m.–4 p.m., weekdays
"0 */15 * * * *"Every 15 minutes
"0 30 9 * * *"Every day at 09:30
"0 0 9 * * MON"Every Monday at 9 a.m.
"* * * * * *"Every second (useful in tests)

The handler fires for the first time after the next scheduled time is reached (never at bot startup). On reconnect, the schedule is evaluated fresh from the current time.

Cron handlers receive a synthetic Context whose sender is None and captures is empty. Use ctx.say() to post to the configured target.

§Note

#[on] is meaningful only when placed on a method inside an #[bot] impl block. Outside that context it is a no-op marker that leaves the item unchanged. Registers the annotated method as an event handler inside a #[bot] impl block.

The general-purpose trigger attribute. Exactly one of command, message, event, mention, or cron must be present. target, regex, and tz are optional modifiers.

§Keys

KeyDescription
command = "name"Fires on !name; equivalent to #[command("name")] but also accepts target
message = "pattern"Glob pattern on PRIVMSG text; each * captures the matched portion as a String parameter
event = "IRC_CMD"Any raw IRC command (e.g. "JOIN", "PRIVMSG", "PART", "NICK")
mentionFires when a PRIVMSG addresses the bot by name ("botname: …" or "botname, …"); matched text is passed as first String parameter
cron = "expr"Fires on a cron schedule independent of any IRC message; uses the 6-field Quartz format (sec min hour dom month dow) with an optional 7th year field, validated at compile time
target = "#channel"(optional) Restrict the trigger to a specific channel
regex = "pattern"(optional, with event) Further filter by a regex on the message text; capture groups become String parameters
tz = "Timezone"(optional, with cron) IANA timezone for evaluating the schedule (default: "UTC"), validated at compile time

When multiple trigger keys are present, the first one in this precedence order wins: messagecommandeventmentioncron.

§Examples

message — glob pattern on PRIVMSG text. Each * captures the corresponding portion of the text as a String parameter:

// Fires on any PRIVMSG that looks like "you are <something>".
#[on(message = "you are *")]
async fn praise_me(&self, ctx: Context, praise: String) -> Result {
    ctx.say(format!("Indeed, I am {}!", praise))
}

event — any raw IRC command. Use this for protocol-level events:

// Fires whenever any user joins any channel.
#[on(event = "JOIN")]
async fn on_join(&self, ctx: Context, user: User) -> Result {
    ctx.say(format!("Welcome, {}!", user.nick))
}

event + target — restrict to a specific channel:

// Fires only when someone joins #rust.
#[on(event = "JOIN", target = "#rust")]
async fn welcome_rust(&self, ctx: Context, user: User) -> Result {
    ctx.say(format!("Welcome to #rust, {}!", user.nick))
}

event + regex — filter by a regex applied to the message text. Capture groups become String parameters in the order they appear:

// Fires on PRIVMSG lines that match `!op <nick> <reason>`.
#[on(event = "PRIVMSG", regex = r"^!op (\S+) (.+)$")]
async fn op_request(&self, ctx: Context, target_nick: String, reason: String) -> Result {
    ctx.say(format!("Granting op to {} (reason: {})", target_nick, reason))
}

command — command-style shorthand inside #[on], useful when you also need target:

#[on(command = "dance", target = "#general")]
async fn dance(&self, ctx: Context) -> Result {
    ctx.action("dances!")
}

mention — fires when a PRIVMSG directly addresses the bot by name ("botname: …" or "botname, …"). The text that follows the prefix is passed as the first String parameter:

// Fires when a user writes "mybot: hello there" in a channel.
#[on(mention)]
async fn on_mention(&self, ctx: Context, text: String) -> Result {
    ctx.reply(format!("You said: {}", text))
}

// Restrict to a specific channel.
#[on(mention, target = "#rust")]
async fn on_mention_rust(&self, ctx: Context) -> Result {
    ctx.notice("I heard you!").await
}

cron — fires the handler according to a cron schedule, independent of any IRC message. The expression uses the 6-field Quartz format backed by the cron crate:

sec  min  hour  day-of-month  month  day-of-week  [year]

Times are evaluated in UTC by default. Use tz to specify any IANA timezone (backed by chrono-tz). Both the cron expression and the timezone are validated at compile time — a typo is a compile error, not a runtime panic.

// Top of every hour, 8 a.m.–4 p.m. Eastern time, Monday–Friday.
#[on(cron = "0 0 8-16 * * MON-FRI", tz = "America/New_York", target = "#work")]
async fn work_hours_reminder(&self, ctx: Context) -> Result {
    ctx.say("Heads up: stand-up in 5 minutes!")
}

// Every 15 minutes, UTC (default when `tz` is omitted).
#[on(cron = "0 */15 * * * *", target = "#general")]
async fn quarter_hour(&self, ctx: Context) -> Result {
    ctx.say("15-minute check-in!")
}

// Every Monday at 9 a.m. Tokyo time.
#[on(cron = "0 0 9 * * MON", tz = "Asia/Tokyo")]
async fn weekly_report(&self, ctx: Context) -> Result {
    // ctx.target is empty when no target is specified;
    // use ctx.tx directly or store the channel name in bot state.
    Ok(())
}

Quick reference — common expressions:

ExpressionMeaning
"0 0 * * * *"Every hour (on the minute)
"0 0 8-16 * * MON-FRI"Top of each hour, 8 a.m.–4 p.m., weekdays
"0 */15 * * * *"Every 15 minutes
"0 30 9 * * *"Every day at 09:30
"0 0 9 * * MON"Every Monday at 9 a.m.
"* * * * * *"Every second (useful in tests)

The handler fires for the first time after the next scheduled time is reached (never at bot startup). On reconnect, the schedule is evaluated fresh from the current time.

Cron handlers receive a synthetic Context whose sender is None and captures is empty. Use ctx.say() to post to the configured target.

§Note

#[on] is meaningful only when placed on a method inside an #[bot] impl block. Outside that context it is a no-op marker that leaves the item unchanged.