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, enabled_caps: HashSet, batches: HashMap, sasl_started: bool, modules: Vec>, 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(()) } }