rubot/src/bot/mod.rs
2026-07-29 17:32:33 +00:00

106 lines
3.1 KiB
Rust

use std::collections::{HashMap, HashSet};
use std::io;
use crate::config::Config;
use crate::irc::{Connection, Message};
mod caps;
mod commands;
pub mod module;
pub mod modules;
pub use module::{Action, Command, CommandSpec, Module};
pub struct Bot {
config: Config,
conn: Connection,
current_nick: String,
registered: bool,
available_caps: HashSet<String>,
enabled_caps: HashSet<String>,
batches: HashMap<String, String>,
sasl_started: bool,
modules: Vec<Box<dyn Module>>,
routes: HashMap<&'static str, usize>,
}
impl Bot {
pub fn new(config: Config, conn: Connection) -> Bot {
let current_nick = config.nick.clone();
let mods = modules::all(&config.name);
let mut routes: HashMap<&'static str, usize> = HashMap::new();
for (i, m) in mods.iter().enumerate() {
for spec in m.commands() {
if routes.insert(spec.name, i).is_some() {
crate::log(&format!(
"module '{}' overrides command '{}'",
m.name(),
spec.name
));
}
}
}
Bot {
config,
conn,
current_nick,
registered: false,
available_caps: HashSet::new(),
enabled_caps: HashSet::new(),
batches: HashMap::new(),
sasl_started: false,
modules: mods,
routes,
}
}
pub fn run(&mut self) -> io::Result<()> {
self.register()?;
while let Some(msg) = self.conn.read_message()? {
self.handle(&msg)?;
}
Ok(())
}
fn register(&mut self) -> io::Result<()> {
if let Some(password) = self.config.password.clone() {
self.conn.pass(&password)?;
}
self.conn.cap_ls()?;
let nick = self.current_nick.clone();
self.conn.nick(&nick)?;
let (user, realname) = (self.config.user.clone(), self.config.realname.clone());
self.conn.user(&user, &realname)?;
Ok(())
}
fn handle(&mut self, msg: &Message) -> io::Result<()> {
match msg.command.as_str() {
"PING" => {
let token = msg.trailing().unwrap_or("").to_string();
self.conn.pong(&token)?;
}
"CAP" => self.handle_cap(msg)?,
"AUTHENTICATE" => self.handle_authenticate(msg)?,
"903" => self.conn.cap_end()?,
"902" | "904" | "905" | "906" | "907" => self.conn.cap_end()?,
"BATCH" => self.handle_batch(msg),
"001" => {
self.registered = true;
for channel in self.config.channels.clone() {
self.conn.join(&channel)?;
}
}
"433" => {
self.current_nick.push('_');
let nick = self.current_nick.clone();
self.conn.nick(&nick)?;
}
"PRIVMSG" => self.handle_privmsg(msg)?,
_ => {}
}
Ok(())
}
}