IRC bot writted in rust
Find a file
2026-07-28 14:29:34 +00:00
src rust bot 2026-07-28 14:29:34 +00:00
.gitignore rust bot 2026-07-28 14:29:34 +00:00
Cargo.toml rust bot 2026-07-28 14:29:34 +00:00
README.md rust bot 2026-07-28 14:29:34 +00:00

rustbot

A small, modular IRC bot in Rust — zero dependencies, with its own IRC protocol layer built to the modern IRC client spec.

Structure

File Layer Responsibility
src/irc.rs protocol + I/O Parse/serialize IRC messages (incl. IRCv3 tags), TCP transport
src/bot.rs behavior Registration, event loop, command handling
src/main.rs wiring Config from env vars, connect/reconnect supervisor

The layers are deliberately separable: irc.rs knows nothing about the bot, and bot.rs knows nothing about how the process is launched.

Build & run

cargo build            # or: cargo build --release
cargo test             # unit tests for the message parser
cargo run

Configuration

Settings are layered, each overriding the previous:

  1. Built-in defaults (Config::default() in src/bot.rs)
  2. A config filekey = value, see rustbot.conf
  3. Environment variables — handy for one-off overrides

The config file is found via: the first CLI argument, else RUSTBOT_CONFIG, else ./rustbot.conf if present.

cargo run                       # uses ./rustbot.conf
cargo run -- /etc/rustbot.conf  # explicit path
RUSTBOT_CONFIG=/etc/rustbot.conf cargo run

Config file keys: server, port, nick, user, realname, channels (comma/space-separated), prefix, password. Whole-line #/; comments only — inline comments would clash with channel #s.

Environment overrides: IRC_SERVER, IRC_PORT, IRC_NICK, IRC_REALNAME, IRC_CHANNELS, IRC_PREFIX, IRC_PASSWORD.

IRC_NICK=mybot IRC_CHANNELS='#test' cargo run   # override the file for one run

If you put a real password in rustbot.conf, add it to .gitignore so the secret isn't committed.

Built-in commands

With the default ! prefix:

  • !pingpong
  • !echo <text> → echoes text back
  • !hello → greets the sender
  • !help → lists commands

Add your own in Bot::handle_command in src/bot.rs.

Deployment (systemd)

Runs as a system service (User=debian), auto-restarts on crash, and starts on boot. The unit is kept in the repo as rustbot.service.

cargo build --release
sudo cp rustbot.service /etc/systemd/system/rustbot.service
sudo systemctl daemon-reload
sudo systemctl enable --now rustbot        # start now + on boot

systemctl status rustbot                   # health
journalctl -u rustbot -f                    # live logs (<< in, >> out)
sudo systemctl restart rustbot             # after a rebuild

One-off overrides without touching rustbot.conf: put IRC_* lines in /etc/default/rustbot (env wins over the config file), then restart.

IRCv3

The bot negotiates capabilities (CAP LS 302CAP REQCAP END) and enables everything useful the server offers: message-tags, server-time, batch, echo-message, account-tag, extended-join, multi-prefix, away-notify, chghost, setname, userhost-in-names, cap-notify, labeled-response.

Two of these do real work:

  • server-time + batch let the bot recognise replayed history. On join, InspIRCd replays recent channel lines (wrapped in a chathistory batch). Without this the bot re-answered old commands on every reconnect; now such messages are ignored (see Bot::is_historical).
  • sasl (PLAIN) authenticates to services during negotiation. Set sasl_user/sasl_pass in the config (or IRC_SASL_USER/IRC_SASL_PASS). base64 is hand-rolled, so this stays dependency-free.

Roadmap / natural next steps

  • TLS (port 6697, or the tls STARTTLS cap) — the one remaining item that needs a dependency (rustls/native-tls).
  • Read timeout + client-sent PING to detect dead connections faster.
  • Split commands into a registry/trait once there are many of them.