Skip to main content

Crate ircbot

Crate ircbot 

Source
Expand description

§ircbot

ircbot on crates.io ircbot-macros on crates.io docs.rs

An async IRC bot framework for Rust powered by Tokio and procedural macros.

ⓘ
use ircbot::{bot, Context, User, Result};

#[bot]
impl MyBot {
    #[command("ping")]
    async fn ping(&self, ctx: Context) -> Result {
        ctx.reply("Pong!")
    }

    // Typed args: the words after `!add` are parsed into `a` and `b`.
    #[command("add")]
    async fn add(&self, ctx: Context, a: i64, b: i64) -> Result {
        ctx.reply(a + b)
    }

    #[on(message = "you are *")]
    async fn praise_me(&self, ctx: Context) -> Result {
        ctx.say("Correct.")
    }

    #[on(event = "JOIN")]
    async fn welcome(&self, ctx: Context, user: User) -> Result {
        ctx.say(format!("Welcome, {}!", user.nick))
    }

    #[on(cron = "0 0 9 * * MON-FRI", target = "#general")]
    async fn morning(&self, ctx: Context) -> Result {
        ctx.say("Good morning!")
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    MyBot::new("mybot", "localhost:6667", ["general"])
        .await?
        .main_loop()
        .await
}

§Highlights

  • Proc-macro API — annotate methods with #[command] or #[on]; #[bot] wires everything up.
  • Typed state — #[bot(state = MyState)] adds a pub state field your handlers can read; mutate it through interior mutability (Mutex/atomics). See examples/stateful_bot.rs.
  • Flexible triggers — commands (!ping), glob patterns ("you are *"), raw IRC events, mention detection, /me actions and CTCP commands, cron schedules — all with optional target-channel and regex filters. CTCP messages reach only the action and ctcp triggers, never the text triggers.
  • Typed command arguments — declare async fn add(&self, ctx: Context, a: i64, b: i64) and the words after !add are parsed into the parameters (FromStr types, a trailing String/Vec, Option<T>); on bad input the bot replies with a generated usage string.
  • Reply helpers — ctx.reply(), ctx.say(), ctx.action(), ctx.notice(), ctx.whisper().
  • Channel control — ctx.join() and ctx.part() to make the bot enter or leave channels from a handler.
  • Raw escape hatch — ctx.raw() sends any IRC line the helpers don’t wrap (MODE, INVITE, …), still sanitized.
  • Moderation — ctx.set_topic() and ctx.kick() act on the channel the message arrived in.
  • Access control — define hostmask-based roles with .with_role("admin", ["*!*@trusted.host"]) and gate commands with #[command("op", role = "admin")]; unauthorized senders are silently ignored.
  • Ignore list — .with_ignore(["*!*@spam.example", "otherbot!*@*"]) drops a message from a matching sender before any trigger, and answers no CTCP for it.
  • Channel or query — scope = "channel" or scope = "private" limits a handler to one kind of target, so an administrative command can stay out of the channel.
  • No self-replies — the messages of the bot itself do not reach handlers; a handler that needs them uses #[on(event = "JOIN", include_self)].
  • Message accessors — ctx.nick(), ctx.is_from_self(), ctx.mentions_me() to inspect who sent a message and what it says.
  • Formatting codes — triggers match the text without the IRC bold, colour, and italic codes, and the captures carry it without them; #[on(..., raw)] keeps them. ctx.plain_text() and ircbot::format::strip() strip any text.
  • Keepalive & auto-reconnect — periodic PING/PONG monitoring; reconnects and re-joins on drop. The bot retries until it is connected again, and each failed attempt doubles the delay, from 5 seconds up to 5 minutes (.with_reconnect(delay, max_delay)). A server that accepts the connection and then closes it, as a reconnect throttle does, counts as a failed attempt too. If the configured nick is already in use, the bot automatically retries with a suffixed alternative (bot, bot_, …).
  • Authentication — SASL PLAIN and EXTERNAL (CertFP) during registration, a PASS server password, and IRCv3 capability negotiation. A rejected login fails the connection instead of continuing unauthenticated.
  • TLS (optional) — Server::tls("irc.libera.chat:6697") behind the tls feature, with certificate verification against the platform root store, private-CA and self-signed support, and client certificates for CertFP.
  • Flood protection — token-bucket rate limiter (default: burst 4, 1 msg / 500 ms).
  • Auto message splitting — long messages are word-wrapped and split within the 512-byte IRC limit.
  • Output sanitization — \r, \n, \0 stripped from every outgoing message.
  • Unit-testable — ircbot::testing::TestContext lets you test handlers without a live server, and ircbot::testing::TestBot sends a raw IRC line through the real trigger matching and argument parsing.
  • Structured logging — diagnostics are emitted through tracing; you pick the subscriber, level, and format. Raw IRC traffic is available opt-in on the ircbot::protocol target.

Full API reference: docs.rs/ircbot

§Getting started

[dependencies]
ircbot = "0.4"
tokio  = { version = "1", features = ["full"] }

See the basic_bot example and the docs for the complete API, testing helpers, and lower-level State / internal APIs.

§Authentication

Most networks want a bot to identify itself. The credentials live on Server, because the handshake needs them before the bot exists:

ⓘ
use ircbot::Server;

MyBot::new(
    "mybot",
    Server::tls("irc.libera.chat:6697").with_sasl_plain("mybot", &password),
    ["rust"],
)

The bot authenticates during registration, before it joins a channel. It is therefore already identified when it arrives, which is what +r channels require and what earns the account its cloak.

Three methods are available:

  • with_sasl_plain(account, password) — an account name and a password. The password travels in a reversible encoding, so use it only over TLS.
  • with_sasl_external() — the server reads the account from the TLS client certificate (CertFP), and no password is sent. Set the certificate with Server::tls(..).with_client_cert_pem(..), and register its fingerprint with the network first.
  • with_password(password) — a server password (PASS). This authenticates to the server itself, not to its services.

A failed SASL exchange fails the connection. If the network offers no SASL, or rejects the credentials, connect returns an error. The bot does not continue unauthenticated: a bot that loses its identity without saying so is the fault SASL exists to prevent.

with_capabilities asks for further IRCv3 capabilities, for example server-time or multi-prefix. The framework requests the ones the server advertises and skips the rest. It does not interpret them itself — what they change reaches handlers on the raw message.

A bot with no credentials sends the same bare NICK/USER handshake as before, and no CAP line at all.

§TLS

TLS is behind the optional tls feature, which pulls in rustls:

[dependencies]
ircbot = { version = "0.4", features = ["tls"] }

The second argument to new is the server, and it decides the transport. A bare "host:port" string connects in plaintext; Server::tls connects over TLS, verifying the certificate against the platform’s root store:

ⓘ
use ircbot::Server;

MyBot::new("mybot", Server::tls("irc.libera.chat:6697"), ["rust"])
    .await?
    .main_loop()
    .await

The transport is never inferred from the port number, so a misconfigured port cannot silently downgrade the connection to plaintext.

For a network with a private CA or a self-signed certificate, trust that certificate specifically rather than turning verification off:

ⓘ
Server::tls("irc.internal.example:6697")
    .with_extra_root_pem(std::fs::read("ca.pem")?)

with_client_cert_pem presents a client certificate for CertFP, which with_sasl_external then authenticates with. with_sni overrides the verified hostname when connecting by IP. danger_accept_invalid_certs disables verification entirely — it is meant for a development server on localhost, leaves the connection unauthenticated, and logs a warning on every connect.

§Logging

The framework emits structured tracing events and installs no subscriber of its own, so verbosity, format, and destination are yours to configure. Raw IRC traffic is available opt-in on the ircbot::protocol target.

See the logging module docs for subscriber setup and the raw-protocol opt-in.

§License

MIT

§AI Disclaimer

This project was written primarily by AI, orchestrated, supervised and reviewed by a human (me). Feel free to use any AI tool for contributions to this project.

Re-exports§

pub use bot::HandlerSet;
pub use connection::State;
pub use connection::DEFAULT_FLOOD_BURST;
pub use connection::DEFAULT_FLOOD_RATE;
pub use connection::DEFAULT_KEEPALIVE_INTERVAL;
pub use connection::DEFAULT_KEEPALIVE_TIMEOUT;
pub use connection::DEFAULT_KEEPNICK_INTERVAL;
pub use connection::DEFAULT_MAX_RECONNECT_DELAY;
pub use connection::DEFAULT_RECONNECT_DELAY;
pub use connection::REGISTRATION_TIMEOUT;
pub use context::make_messages;
pub use context::Context;
pub use context::User;
pub use handler::Bot;
pub use handler::BoxFuture;
pub use handler::HandlerEntry;
pub use handler::HandlerFn;
pub use handler::Scope;
pub use handler::Trigger;
pub use irc::CtcpMessage;
pub use logging::PROTOCOL_LOG_TARGET;
pub use server::Server;
pub use server::TlsServer;
pub use types::Channel;
pub use types::Nick;
pub use types::Target;

Modules§

bot
The dispatch loop and the trigger matching behind it.
connection
The live connection to an IRC server, and the settings that shape it.
context
What a handler receives, and how it replies.
format
Removal of the IRC formatting codes from text.
handler
What fires a handler, and the shape of the handler itself.
internal
Internal helpers used by the generated main_loop code.
irc
IRC protocol types — backed by the irc-proto crate.
logging
Logging and diagnostics.
server
How to reach an IRC server: an address plus the transport to use.
testing
Helpers for unit-testing bot handler methods.
types
Strongly-typed wrappers for IRC identifiers.

Structs§

ReloadHandle
A handle for replacing the bot’s handler list at runtime without disconnecting from IRC.

Enums§

Error
Errors specific to the bot framework.

Type Aliases§

BoxError
The standard error type used throughout the crate.
Result
The standard result type returned by handlers.

Attribute Macros§

bot
Derive-like attribute that turns an impl block into a runnable IRC bot.
command
Registers the annotated method as a command handler inside a #[bot] impl block.
on
Registers the annotated method as an event handler inside a #[bot] impl block.