use tokio::sync::{mpsc::UnboundedReceiver, Mutex}; use twitch_irc::{login::StaticLoginCredentials, message::ServerMessage, SecureTCPTransport, TwitchIRCClient}; use dotenv::dotenv; use std::{env, sync::Arc}; use super::bot_objects::listener::Listener; /// Twitch chat bot pub struct Bot { /// Prefix for commands _prefix: char, /// inbound chat msg stream incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>, /// outbound chat client msg stream pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>, /// joined channels botchannels: Vec<String>, /// listeners listeners: Vec<Listener>, } impl Bot { /// Creates a new `Bot` using env variables /// /// Be sure the following is defined in an `.env` file /// - login_name /// - access_token /// - bot_channels /// - prefix /// - bot_admins pub fn new() -> Bot { dotenv().ok(); let bot_login_name = env::var("login_name").unwrap().to_owned(); let oauth_token = env::var("access_token").unwrap().to_owned(); let prefix = env::var("prefix") .unwrap() .to_owned() .chars() .next() .expect("ERROR : when defining prefix"); let mut botchannels = Vec::new(); for chnl in env::var("bot_channels").unwrap().split(',') { botchannels.push(chnl.to_owned()); } Bot::new_from(bot_login_name, oauth_token, prefix, botchannels) } /// Creates a new `Bot` using bot information /// /// Bot joined channels will include channels from `.env` and `botchannels` argument pub fn new_from(bot_login_name:String,oauth_token:String,prefix:char,botchannels:Vec<String>) -> Bot { dotenv().ok(); let bot_login_name = bot_login_name; let config = twitch_irc::ClientConfig::new_simple(StaticLoginCredentials::new( bot_login_name.to_owned(), Some(oauth_token.to_owned()), )); let (incoming_messages, client) = TwitchIRCClient::<SecureTCPTransport, StaticLoginCredentials>::new(config); let mut botchannels_all = Vec::new(); botchannels_all.extend(botchannels); for chnl in env::var("bot_channels").unwrap().split(',') { botchannels_all.push(chnl.to_owned()); } Bot { _prefix : prefix, incoming_msgs : Mutex::new(incoming_messages), client, botchannels : botchannels_all, listeners : vec![], } } /// Runs the bot pub async fn run(self) { for chnl in &self.botchannels { self.client.join(chnl.to_owned()).unwrap(); } let bot = Arc::new(self); let join_handle = tokio::spawn(async move { let mut in_msgs_lock = bot.incoming_msgs.lock().await; while let Some(message) = in_msgs_lock.recv().await { // dbg!("Received message: {:?}", message.clone()); for listener in &(*bot).listeners { let a = listener.clone(); if a.cond_triggered(bot.clone(),message.clone()) { let _ = listener.execute_fn(bot.clone(),message.clone()).await; } } } drop(in_msgs_lock); }); join_handle.await.unwrap(); } /// Loads a `Listener` into the bot pub fn load_listener(&mut self,l : Listener) { self.listeners.push(l); } }