diff --git a/forcebot_core/src/bin/fun_bot.rs b/forcebot_core/src/bin/fun_bot.rs index abbc426..b506faf 100644 --- a/forcebot_core/src/bin/fun_bot.rs +++ b/forcebot_core/src/bin/fun_bot.rs @@ -1,30 +1,30 @@ //! WIP Fun forcebot with catered customizations #todo -//! +//! //! Custom modules that can be managed in chat through `disable` and `enable` commands //! - `besty` - uses a custom prefix tp trigger //! - `guests` //! - `pyramid` //! - `quiet` -//! -//! -//! Be sure the followig is defined in `.env` +//! +//! +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> -use forcebot_core::{custom_mods::{debug, guest_badge, pyramid}, Bot}; - - +use forcebot_core::{ + custom_mods::{debug, guest_badge, pyramid}, + Bot, +}; #[tokio::main] pub async fn main() { - /* Create the bot using env */ let bot = Bot::new().await; @@ -33,14 +33,11 @@ pub async fn main() { bot.load_module(guest_badge::create_module()).await; bot.load_module(pyramid::create_module()).await; bot.load_module(debug::create_module()).await; - - + /* 3. Run the bot */ bot.run().await; - } - pub mod funbot_objs { use std::sync::Arc; @@ -50,8 +47,9 @@ pub mod funbot_objs { /// Create a Module with a loaded Command object pub fn create_module() -> Module { let mut custom_mod = Module::new( - vec!["besty".to_string()], - "Now Aware of besty xdd666 ".to_string()); + vec!["besty".to_string()], + "Now Aware of besty xdd666 ".to_string(), + ); custom_mod.load_command(create_cmd_test()); // custom_mod.set_status_by_default(Status::Disabled); @@ -61,16 +59,22 @@ pub mod funbot_objs { /// Create a Command Object fn create_cmd_test() -> Command { - - let mut cmd = Command::new(vec!["remind besty".to_string()],"annytfYandere ".to_string()); + let mut cmd = Command::new( + vec!["remind besty".to_string()], + "annytfYandere ".to_string(), + ); - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - let _= bot.chat.lock().await.say_in_reply_to( - &msg, "annytfYandere he's mine".to_string()).await; - return Result::Ok("Success".to_string()); + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, "annytfYandere he's mine".to_string()) + .await; + return Result::Ok("Success".to_string()); } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } cmd.set_exec_fn(execution_async(execbody)); @@ -79,6 +83,5 @@ pub mod funbot_objs { cmd.set_min_badge(Badge::Vip); cmd - } -} \ No newline at end of file +} diff --git a/forcebot_core/src/bin/new_bot.rs b/forcebot_core/src/bin/new_bot.rs index a81462e..856f6b1 100644 --- a/forcebot_core/src/bin/new_bot.rs +++ b/forcebot_core/src/bin/new_bot.rs @@ -1,12 +1,12 @@ //! Example simple Binary crate that creates & runs bot based on `.env` -//! Be sure the followig is defined in `.env` +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> @@ -14,11 +14,9 @@ use forcebot_core::Bot; #[tokio::main] pub async fn main() { - /* 1. Create the bot using env */ let bot = Bot::new().await; /* 2. Run the bot */ bot.run().await; - } diff --git a/forcebot_core/src/bin/simple_module.rs b/forcebot_core/src/bin/simple_module.rs index 3e36d90..477da78 100644 --- a/forcebot_core/src/bin/simple_module.rs +++ b/forcebot_core/src/bin/simple_module.rs @@ -1,19 +1,19 @@ //! Simple Module with a Command -//! -//! Adding objects through packages provides controls , +//! +//! Adding objects through packages provides controls , //! such as moderators, and brodcasters can disable or enable mods -//! -//! Here, moderators or above can enable or disable the `test` +//! +//! Here, moderators or above can enable or disable the `test` //! module with the command `<prefix> disable test` -//! -//! Be sure the followig is defined in `.env` +//! +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> @@ -21,7 +21,6 @@ use forcebot_core::Bot; #[tokio::main] pub async fn main() { - /* Create the bot using env */ let bot = Bot::new().await; @@ -30,43 +29,41 @@ pub async fn main() { /* Run the bot */ bot.run().await; - } - pub mod custom_mod { use std::sync::Arc; use forcebot_core::{execution_async, Badge, Bot, Command, Module}; use twitch_irc::message::ServerMessage; - /// Module definition with a loaded command pub fn new() -> Module { /* 1. Create a new module */ - let mut custom_mod = Module::new( - vec!["test".to_string()], - "".to_string()); + let mut custom_mod = Module::new(vec!["test".to_string()], "".to_string()); /* 2. Load the cmd into a new module */ custom_mod.load_command(cmd_test()); custom_mod - } - /// Command definition + /// Command definition pub fn cmd_test() -> Command { /* 1. Create a new cmd */ - let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["test".to_string()], "".to_string()); /* 2. Define exec callback */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - let _= bot.chat.lock().await.say_in_reply_to( - &msg, "test return".to_string()).await; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, "test return".to_string()) + .await; } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set Command flags */ @@ -76,4 +73,4 @@ pub mod custom_mod { cmd } -} \ No newline at end of file +} diff --git a/forcebot_core/src/botcore.rs b/forcebot_core/src/botcore.rs index 99449f0..a750843 100644 --- a/forcebot_core/src/botcore.rs +++ b/forcebot_core/src/botcore.rs @@ -1,5 +1,5 @@ pub mod bot; pub mod bot_objects; -pub mod modules; pub mod built_in_mods; -pub mod chat; \ No newline at end of file +pub mod chat; +pub mod modules; diff --git a/forcebot_core/src/botcore/bot.rs b/forcebot_core/src/botcore/bot.rs index cccc61f..f3774a1 100644 --- a/forcebot_core/src/botcore/bot.rs +++ b/forcebot_core/src/botcore/bot.rs @@ -1,37 +1,44 @@ - - // use async_recursion::async_recursion; -use tokio::sync::{mpsc::UnboundedReceiver, Mutex}; -use twitch_irc::{login::StaticLoginCredentials, message::{PrivmsgMessage, ServerMessage}, SecureTCPTransport, TwitchIRCClient}; use dotenv::dotenv; -use std::{env, sync::{Arc, RwLock}, time::{Duration, Instant}}; +use std::{ + env, + sync::{Arc, RwLock}, + time::{Duration, Instant}, +}; +use tokio::sync::{mpsc::UnboundedReceiver, Mutex}; +use twitch_irc::{ + login::StaticLoginCredentials, + message::{PrivmsgMessage, ServerMessage}, + SecureTCPTransport, TwitchIRCClient, +}; // use crate::{Badge, Command, Listener, Module}; use super::{bot_objects::command::Command, built_in_mods, chat::Chat}; -use crate::botcore::{bot_objects::Badge, chat}; -use crate::botcore::bot_objects::listener::Listener; use super::super::botcore::modules::Module; +use crate::botcore::bot_objects::listener::Listener; +use crate::botcore::{bot_objects::Badge, chat}; // use super:: -use super:: {bot_objects::built_in_objects, modules::{self, Status}}; - +use super::{ + bot_objects::built_in_objects, + modules::{self, Status}, +}; /// Twitch chat bot -pub struct Bot -{ +pub struct Bot { /// Prefix for commands prefix: String, /// inbound chat msg stream incoming_msgs: Mutex<UnboundedReceiver<ServerMessage>>, /// outbound chat client msg stream - pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>, + pub client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>, /// *preferred* bot enforced outbound chat client msg stream - pub chat : Mutex<Chat>, + pub chat: Mutex<Chat>, /// joined channels botchannels: Vec<String>, /// admin chatters - admins : Vec<String>, + admins: Vec<String>, /// listeners listeners: Mutex<Vec<Listener>>, /// commands @@ -39,21 +46,18 @@ pub struct Bot /// modules modules: RwLock<Vec<Module>>, /// channel module status - channel_module_status: RwLock<Vec<(String,String,modules::Status)>>, + channel_module_status: RwLock<Vec<(String, String, modules::Status)>>, /// chatter guest badges - chatter,channel,Badge,start_time,duration - chatter_guest_badges: Mutex<Vec<(String,String,Badge,Instant,Duration)>>, + chatter_guest_badges: Mutex<Vec<(String, String, Badge, Instant, Duration)>>, /// Message cache message_cache: Mutex<Vec<PrivmsgMessage>>, // /// channel_quiet // channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>, - } - -impl Bot -{ +impl Bot { /// Creates a new `Bot` using env variables - /// + /// /// Be sure the following is defined in an `.env` file /// - login_name /// - access_token @@ -62,35 +66,29 @@ impl Bot /// - bot_admins // #[async_recursion] pub async fn new() -> Arc<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(); + let prefix = env::var("prefix").unwrap().to_owned(); let mut botchannels = Vec::new(); for chnl in env::var("bot_channels").unwrap().split(',') { - botchannels.push(chnl.to_owned()); + botchannels.push(chnl.to_owned()); } Bot::new_from(bot_login_name, oauth_token, prefix, botchannels).await - - } /// Creates a new `Bot` using bot information - /// + /// /// Bot will join `botchannels` argument - pub async fn new_from(bot_login_name:String, - oauth_token:String, - prefix:String, - botchannels:Vec<String>) -> Arc<Bot> { - + pub async fn new_from( + bot_login_name: String, + oauth_token: String, + prefix: String, + botchannels: Vec<String>, + ) -> Arc<Bot> { dotenv().ok(); let bot_login_name = bot_login_name; @@ -105,49 +103,45 @@ impl Bot let mut botchannels_all = Vec::new(); botchannels_all.extend(botchannels); - let mut admins = Vec::new(); if let Ok(value) = env::var("bot_admins") { for admin in value.split(',') { - admins.push(String::from(admin)) + admins.push(String::from(admin)) } } - let bot = Bot { - prefix, - incoming_msgs : Mutex::new(incoming_messages), - client : client.clone(), - chat : Mutex::new(Chat::new(client).await), - botchannels : botchannels_all, - listeners : Mutex::new(vec![]), - commands : Mutex::new(vec![]), - admins, - modules: RwLock::new(vec![]), - channel_module_status: RwLock::new(vec![]), - chatter_guest_badges: Mutex::new(vec![]), - message_cache : Mutex::new(vec![]), + prefix, + incoming_msgs: Mutex::new(incoming_messages), + client: client.clone(), + chat: Mutex::new(Chat::new(client).await), + botchannels: botchannels_all, + listeners: Mutex::new(vec![]), + commands: Mutex::new(vec![]), + admins, + modules: RwLock::new(vec![]), + channel_module_status: RwLock::new(vec![]), + chatter_guest_badges: Mutex::new(vec![]), + message_cache: Mutex::new(vec![]), // channel_quiet_yn : RwLock::new(vec![]), }; - async fn load_modules(bot:Bot) -> Bot { + async fn load_modules(bot: Bot) -> Bot { // let mut bot1 = bot; - // bot1.chat = Some(Chat::new(client, bot1)); + // bot1.chat = Some(Chat::new(client, bot1)); - for cmd in built_in_objects::create_commands() { - bot.load_command(cmd).await; - } - built_in_mods::load_built_in_mods(&bot).await; - - bot + for cmd in built_in_objects::create_commands() { + bot.load_command(cmd).await; + } + built_in_mods::load_built_in_mods(&bot).await; + bot } let bot = load_modules(bot).await; - let bot = Arc::new(bot); // let lock = bot.chat.lock().await; @@ -160,15 +154,13 @@ impl Bot // lock.set_parent_bot(bot.clone()); - println!("Joined - {:?}",bot.botchannels); - + println!("Joined - {:?}", bot.botchannels); bot.clone() } - /// Runs the bot - pub async fn run(self:Arc<Self>) { - + /// Runs the bot + pub async fn run(self: Arc<Self>) { for chnl in &self.botchannels { self.client.join(chnl.to_owned()).unwrap(); } @@ -177,24 +169,21 @@ impl Bot let bot = self; let join_handle = tokio::spawn(async move { - let a = bot.clone(); let mut in_msgs_lock = a.incoming_msgs.lock().await; - - while let Some(message) = in_msgs_lock.recv().await { + + while let Some(message) = in_msgs_lock.recv().await { // dbg!(message.clone()) ; let bot_listener_lock = bot.listeners.lock().await; for listener in bot_listener_lock.iter() { - let a = listener.clone(); - if a.cond_triggered(bot.clone(),message.clone()).await { - let _ = listener.execute_fn(bot.clone(),message.clone()).await; + if a.cond_triggered(bot.clone(), message.clone()).await { + let _ = listener.execute_fn(bot.clone(), message.clone()).await; } } if let ServerMessage::Privmsg(msg) = message.clone() { - // let mut cache_lock = bot.message_cache.lock().await; let mut cache_lock = bot.message_cache.lock().await; cache_lock.push(msg.clone()); @@ -203,91 +192,78 @@ impl Bot let cmd_lock = bot.commands.lock().await; for cmd in cmd_lock.iter() { - let a = cmd.clone(); - if a.command_triggered(bot.clone(),msg.clone()).await { - - let _ = cmd.execute_fn(bot.clone(),message.clone()).await; + if a.command_triggered(bot.clone(), msg.clone()).await { + let _ = cmd.execute_fn(bot.clone(), message.clone()).await; } } + fn get_enabled_channel_modules(bot: Arc<Bot>, channel: String) -> Vec<Module> { + let botmodules_lock = bot.modules.read().unwrap(); + let botmodules_cpy = botmodules_lock.clone(); + drop(botmodules_lock); - fn get_enabled_channel_modules(bot: Arc<Bot>,channel:String) -> Vec<Module> { + let mut enabled_mods = Vec::new(); - let botmodules_lock = bot.modules.read().unwrap(); - let botmodules_cpy = botmodules_lock.clone(); - drop(botmodules_lock); + 'module_loop: for module in &*botmodules_cpy { + // dbg!("try cms read"); + let cms_lock = bot.channel_module_status.read().unwrap(); - let mut enabled_mods = Vec::new(); - - 'module_loop: for module in &*botmodules_cpy { - - // dbg!("try cms read"); - let cms_lock = bot.channel_module_status.read().unwrap(); - - for channel_flags in cms_lock.iter() { - if channel_flags.0 == channel { - - if module.get_names().contains(&channel_flags.1) && channel_flags.2 == Status::Disabled { - continue 'module_loop; - + for channel_flags in cms_lock.iter() { + if channel_flags.0 == channel { + if module.get_names().contains(&channel_flags.1) + && channel_flags.2 == Status::Disabled + { + continue 'module_loop; + } } } + enabled_mods.push(module.clone()); } - enabled_mods.push(module.clone()); + + enabled_mods } - enabled_mods - - - } - - - for module in get_enabled_channel_modules(bot.clone(), msg.clone().channel_login) { - - for listener in module.get_listeners() { - - let a = listener.clone(); - if a.cond_triggered(bot.clone(),message.clone()).await { - - let _ = listener.execute_fn(bot.clone(),message.clone()).await; + for module in + get_enabled_channel_modules(bot.clone(), msg.clone().channel_login) + { + for listener in module.get_listeners() { + let a = listener.clone(); + if a.cond_triggered(bot.clone(), message.clone()).await { + let _ = listener.execute_fn(bot.clone(), message.clone()).await; + } + } + for cmd in module.get_commands() { + let a = cmd.clone(); + if a.command_triggered(bot.clone(), msg.clone()).await { + let _ = cmd.execute_fn(bot.clone(), message.clone()).await; + } } } - for cmd in module.get_commands() { - - let a = cmd.clone(); - if a.command_triggered(bot.clone(),msg.clone()).await { - - let _ = cmd.execute_fn(bot.clone(),message.clone()).await; - } - } - - } - } else {} ; - + } else { + }; } drop(in_msgs_lock); }); - + join_handle.await.unwrap(); } /// Loads a `Listener` into the bot - pub async fn load_listener(&self,l : Listener) { + pub async fn load_listener(&self, l: Listener) { let a = Arc::new(self); let mut listlock = a.listeners.lock().await; listlock.push(l); } /// Loads a `Command` into the bot - pub async fn load_command(&self,c : Command) { + pub async fn load_command(&self, c: Command) { let a = Arc::new(self); let mut cmdlock = a.commands.lock().await; cmdlock.push(c); } - - pub async fn get_module(&self,module:String) -> Option<Module> { + pub async fn get_module(&self, module: String) -> Option<Module> { let modlock = self.modules.read().unwrap(); for modl in modlock.iter() { if modl.get_names().contains(&module) { @@ -296,8 +272,6 @@ impl Bot } None } - - pub fn get_prefix(&self) -> String { self.prefix.clone() @@ -306,9 +280,9 @@ impl Bot pub fn get_admins(&self) -> Vec<String> { self.admins.clone() } - + /// loads a `Module` and its bot objects - pub async fn load_module(&self,m: Module) { + pub async fn load_module(&self, m: Module) { // dbg!("load module - start",m.get_names().first().unwrap()); let bot = Arc::new(self); // let bot_lock = bot.lock().await; @@ -316,10 +290,10 @@ impl Bot if m.get_status_by_default() == Status::Disabled { // dbg!("module fund disabled by default"); // dbg!("inner if"); - for (_index,chnl) in bot.botchannels.iter().enumerate() { + for (_index, chnl) in bot.botchannels.iter().enumerate() { // dbg!("iter - ",index); - bot.disable_module(chnl.clone(), - m.get_names().first().unwrap().clone()).await + bot.disable_module(chnl.clone(), m.get_names().first().unwrap().clone()) + .await } } // dbg!("aftee disable check"); @@ -328,11 +302,11 @@ impl Bot // dbg!(m); // dbg!("loading module ",m.get_names()); botmods.push(m); - } + } - pub async fn get_channel_module_status(&self,channel:String,module:String) -> Status { + pub async fn get_channel_module_status(&self, channel: String, module: String) -> Status { // dbg!("get channel module status"); - let found_disabled:bool = { + let found_disabled: bool = { // dbg!("try cms read"); let cms_lock = self.channel_module_status.read().unwrap(); // dbg!("cms read lock"); @@ -349,31 +323,31 @@ impl Bot found }; - let module_loaded:bool = { - + let module_loaded: bool = { let mut loaded_yn = false; for loaded_m in self.modules.read().unwrap().iter() { - if loaded_m.get_names().contains(&module) { + if loaded_m.get_names().contains(&module) { loaded_yn = true; } } loaded_yn - }; - - if found_disabled { return Status::Disabled;} - - else if !module_loaded { return Status::NotLoaded ;} - else { return Status::Enabled; }; + if found_disabled { + return Status::Disabled; + } else if !module_loaded { + return Status::NotLoaded; + } else { + return Status::Enabled; + }; } - pub async fn disable_module(&self,channel:String,module:String){ + pub async fn disable_module(&self, channel: String, module: String) { // dbg!("disable module called",channel.clone(),module.clone()); - let found_disabled:bool = { + let found_disabled: bool = { // dbg!("finding disabled mod"); // dbg!("try cms read"); let cms_lock = self.channel_module_status.read().unwrap(); @@ -394,62 +368,63 @@ impl Bot }; if !found_disabled { - - let mut cms_lock = self.channel_module_status.write().unwrap(); - - cms_lock.push((channel,module.clone(),Status::Disabled)); - + + cms_lock.push((channel, module.clone(), Status::Disabled)); + drop(cms_lock); - - - } - - + } } - pub async fn enable_module(&self,channel:String,module:String){ + pub async fn enable_module(&self, channel: String, module: String) { // dbg!("enable module called",channel.clone(),module.clone()); // dbg!("try cms write"); let mut lock = self.channel_module_status.write().unwrap(); // dbg!("cms write lock"); // dbg!(module.clone()); - while lock.contains(&(channel.clone(),module.clone(),Status::Disabled)) { - + while lock.contains(&(channel.clone(), module.clone(), Status::Disabled)) { let index = lock .iter() - .position(|x| *x == - (channel.clone(),module.clone(),Status::Disabled)) + .position(|x| *x == (channel.clone(), module.clone(), Status::Disabled)) .unwrap(); lock.remove(index); } drop(lock); } - pub async fn get_channel_guest_badges(&self,chatter:String,channel:String) -> Vec<(Badge,Instant,Duration)> { - + pub async fn get_channel_guest_badges( + &self, + chatter: String, + channel: String, + ) -> Vec<(Badge, Instant, Duration)> { let bot = Arc::new(self); let guest_badges_lock = bot.chatter_guest_badges.lock().await; let mut badges = vec![]; for temp_badge in guest_badges_lock.iter() { - if temp_badge.0 == chatter && temp_badge.1 == channel && - temp_badge.3 + temp_badge.4 > Instant::now() + if temp_badge.0 == chatter + && temp_badge.1 == channel + && temp_badge.3 + temp_badge.4 > Instant::now() { - badges.push((temp_badge.2.clone(),temp_badge.3,temp_badge.4)); + badges.push((temp_badge.2.clone(), temp_badge.3, temp_badge.4)); } } badges } - - pub async fn issue_new_guest_badge(&self,chatter:String,channel:String,badge:Badge,start:Instant,dur:Duration) { + pub async fn issue_new_guest_badge( + &self, + chatter: String, + channel: String, + badge: Badge, + start: Instant, + dur: Duration, + ) { let bot = Arc::new(self); let mut guest_badges_lock = bot.chatter_guest_badges.lock().await; - guest_badges_lock.push((chatter,channel,badge,start,dur)); - + guest_badges_lock.push((chatter, channel, badge, start, dur)); } pub fn get_message_cache(&self) -> &Mutex<Vec<PrivmsgMessage>> { @@ -457,12 +432,16 @@ impl Bot } /// get message cache newest to oldest for a channel - pub async fn get_message_cache_per_channel(&self,channel:String) -> Vec<PrivmsgMessage> { + pub async fn get_message_cache_per_channel(&self, channel: String) -> Vec<PrivmsgMessage> { let cache = self.message_cache.lock().await; let mut rslt = vec![]; - for a in cache.iter().rev().filter(|x| { x.channel_login==channel }).into_iter() { + for a in cache + .iter() + .rev() + .filter(|x| x.channel_login == channel) + .into_iter() + { rslt.push(a.clone()); - } rslt } @@ -476,7 +455,7 @@ impl Bot // } // return false; // } - + // /// Get the quiet status of a channel // pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) { // let mut found = false; @@ -491,16 +470,13 @@ impl Bot // } // } // drop(chnlquiet); - + // if !found { // // dbg!("set chn quiet > !found channel quiet status"); // let mut chnlquiet = self.channel_quiet_yn.write().unwrap(); // chnlquiet.push((channel,RwLock::new(quiet_on))); // drop(chnlquiet); // } - + // } - } - - diff --git a/forcebot_core/src/botcore/bot_objects.rs b/forcebot_core/src/botcore/bot_objects.rs index dd4e6db..77de39c 100644 --- a/forcebot_core/src/botcore/bot_objects.rs +++ b/forcebot_core/src/botcore/bot_objects.rs @@ -1,6 +1,5 @@ -pub mod listener; pub mod command; - +pub mod listener; use std::boxed::Box; use std::future::Future; @@ -11,25 +10,24 @@ use twitch_irc::message::{PrivmsgMessage, ServerMessage}; use super::bot::Bot; - /// chat badge -#[derive(Clone,PartialEq, Eq,Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum Badge { Moderator, Broadcaster, - Vip + Vip, } - - pub type ExecBody = Box< - dyn Fn(Arc<Bot>,ServerMessage) -> Pin<Box<dyn Future<Output = Result<String,String>> + Send>> + Send + Sync, + dyn Fn(Arc<Bot>, ServerMessage) -> Pin<Box<dyn Future<Output = Result<String, String>> + Send>> + + Send + + Sync, >; /// used to store async execution functions. Primarily used for `Command` -/// +/// /// call this to store execution functions in `Commands` -/// +/// /// # example /// ``` /// /* 2. Define exec callback */ @@ -40,20 +38,20 @@ pub type ExecBody = Box< /// /* 3. Set Command flags */ /// cmd.set_exec_fn(execution_async(execbody)); /// ``` -/// -pub fn execution_async<T>(f: fn(Arc<Bot>,ServerMessage) -> T) -> ExecBody +/// +pub fn execution_async<T>(f: fn(Arc<Bot>, ServerMessage) -> T) -> ExecBody where - T: Future<Output = Result<String,String>> + Send + 'static, + T: Future<Output = Result<String, String>> + Send + 'static, { - Box::new(move |a,b| Box::pin(f(a,b))) + Box::new(move |a, b| Box::pin(f(a, b))) } pub type CommandTrigger = Box< - dyn Fn(Arc<Bot>,PrivmsgMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync, + dyn Fn(Arc<Bot>, PrivmsgMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync, >; /// used to store async trigger condition callback functions. Primarily used for `Command` -/// +/// /// # example /// ``` /// /* 2. Define condition callback */ @@ -64,21 +62,20 @@ pub type CommandTrigger = Box< /// /* 3. Set Command flags */ /// cmd.set_custom_cond_async(command_condition_async(condition01)); /// ``` -/// -pub fn command_condition_async<T>(f: fn(Arc<Bot>,PrivmsgMessage) -> T) -> CommandTrigger +/// +pub fn command_condition_async<T>(f: fn(Arc<Bot>, PrivmsgMessage) -> T) -> CommandTrigger where T: Future<Output = bool> + Send + 'static, { - Box::new(move |a,b| Box::pin(f(a,b))) + Box::new(move |a, b| Box::pin(f(a, b))) } - pub type ListenerTrigger = Box< - dyn Fn(Arc<Bot>,ServerMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync, + dyn Fn(Arc<Bot>, ServerMessage) -> Pin<Box<dyn Future<Output = bool> + Send>> + Send + Sync, >; /// used to store async trigger condition callback functions. Primarily used for `Listener` -/// +/// /// # example /// ``` /// /* 2. Define condition callback */ @@ -89,30 +86,29 @@ pub type ListenerTrigger = Box< /// /* 3. Set Command flags */ /// cmd.set_custom_cond_async(listener_condition_async(condition01)); /// ``` -/// -pub fn listener_condition_async<T>(f: fn(Arc<Bot>,ServerMessage) -> T) -> ListenerTrigger +/// +pub fn listener_condition_async<T>(f: fn(Arc<Bot>, ServerMessage) -> T) -> ListenerTrigger where T: Future<Output = bool> + Send + 'static, { - Box::new(move |a,b| Box::pin(f(a,b))) + Box::new(move |a, b| Box::pin(f(a, b))) } - - /// collection of functions to create built in objects pub mod built_in_objects { - const TEMP_BADGE_DUR_MIN:u64 = 30; + const TEMP_BADGE_DUR_MIN: u64 = 30; - use std::{sync::Arc, time::{Duration, Instant}}; + use std::{ + sync::Arc, + time::{Duration, Instant}, + }; use twitch_irc::message::ServerMessage; - - use super::{execution_async,command::Command,Bot,Badge,super::modules::Status}; + use super::{super::modules::Status, command::Command, execution_async, Badge, Bot}; /// create a vector of command build in objects - pub fn create_commands() -> Vec<Command> - { + pub fn create_commands() -> Vec<Command> { let mut cmds = vec![]; cmds.push(create_disable_cmd()); @@ -120,31 +116,45 @@ pub mod built_in_objects { cmds.push(create_iam_role_cmd()); cmds - } fn create_disable_cmd() -> Command { /* 1. Create a new blank cmd */ - let mut cmd = Command::new(vec!["disable".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["disable".to_string()], "".to_string()); /* 2. Define an async fn callback execution */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { let mut action_taken = false; - for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { + for (i, arg) in msg + .message_text + .replace("\u{e0000}", "") + .trim() + .split(" ") + .enumerate() + { if i > 1 { - if bot.get_channel_module_status(msg.channel_login.clone(), arg.to_string()).await == Status::Enabled { + if bot + .get_channel_module_status(msg.channel_login.clone(), arg.to_string()) + .await + == Status::Enabled + { action_taken = true; - bot.disable_module(msg.channel_login.clone(), arg.to_string()).await; + bot.disable_module(msg.channel_login.clone(), arg.to_string()) + .await; } - } } if action_taken { - let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("Disabled!")).await ; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, String::from("Disabled!")) + .await; } } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set and Store the execution body using `execution_async()` */ @@ -156,50 +166,61 @@ pub mod built_in_objects { /* 5. optionally, set min badge*/ cmd.set_min_badge(Badge::Moderator /* ::Moderator */); cmd - - } + } fn create_enable_cmd() -> Command { /* 1. Create a new blank cmd */ - let mut cmd = Command::new(vec!["enable".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["enable".to_string()], "".to_string()); /* 2. Define an async fn callback execution */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - - let mut bot_message="".to_string(); + let mut bot_message = "".to_string(); let mut re_enabled = false; - for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { + for (i, arg) in msg + .message_text + .replace("\u{e0000}", "") + .trim() + .split(" ") + .enumerate() + { if i > 1 { + if Status::Disabled + == bot + .get_channel_module_status( + msg.channel_login.clone(), + arg.to_string(), + ) + .await + { + bot.enable_module(msg.channel_login.clone(), arg.to_string()) + .await; - if Status::Disabled == bot.get_channel_module_status(msg.channel_login.clone(), arg.to_string()).await { - bot.enable_module(msg.channel_login.clone(), arg.to_string()).await; - //bot.get_modules() if let Some(found_mod) = bot.get_module(arg.to_string()).await { - bot_message = bot_message.to_string() + found_mod.get_bot_read_description().as_str(); + bot_message = bot_message.to_string() + + found_mod.get_bot_read_description().as_str(); } re_enabled = true; } - } } if re_enabled { - - if bot_message.len() > 250 { + if bot_message.len() > 250 { bot_message = bot_message[..250].to_string(); } - let _ = bot.chat.lock().await.say_in_reply_to(&msg, - format!("Enabled! {}", bot_message) - ).await ; - + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, format!("Enabled! {}", bot_message)) + .await; } - - } - Result::Err("Not Valid message type".to_string()) + } + Result::Err("Not Valid message type".to_string()) } /* 3. Set and Store the execution body using `execution_async()` */ @@ -211,98 +232,158 @@ pub mod built_in_objects { /* 5. optionally, set min badge*/ cmd.set_min_badge(Badge::Moderator); cmd - } - + } /// adminonly command that grants a temporary role fn create_iam_role_cmd() -> Command { /* 1. Create a new blank cmd */ - let mut cmd = Command::new(vec![ - "I am ".to_string(), - "I'm ".to_string(), - "Im a ".to_string(), - ],"".to_string()); + let mut cmd = Command::new( + vec!["I am ".to_string(), "I'm ".to_string(), "Im a ".to_string()], + "".to_string(), + ); /* 2. Define an async fn callback execution */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { + for (i, arg) in msg + .message_text + .replace("\u{e0000}", "") + .trim() + .split(" ") + .enumerate() + { if i > 1 { // bot.disable_module(msg.channel_login.clone(), arg.to_string()).await; // #todo - // if not dont have the badge or have a lower priviledge badge + // if not dont have the badge or have a lower priviledge badge // and they dont have an active guest badge, ths admin can be // recognzed wth that badge if arg == "mod" || arg == "moderator" { - let curr_temp_badges = bot.get_channel_guest_badges(msg.sender.login.clone(), msg.channel_login.clone()).await; + let curr_temp_badges = bot + .get_channel_guest_badges( + msg.sender.login.clone(), + msg.channel_login.clone(), + ) + .await; let mut found = false; for temp_badge in curr_temp_badges { if temp_badge.0 == Badge::Moderator { found = true; - } + } } if found { /* do nothing */ } else { bot.issue_new_guest_badge( - msg.sender.login.clone(), - msg.channel_login.clone(), - Badge::Moderator, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await; + msg.sender.login.clone(), + msg.channel_login.clone(), + Badge::Moderator, + Instant::now(), + Duration::from_secs(60 * TEMP_BADGE_DUR_MIN), + ) + .await; - let _ = bot.chat.lock().await.say_in_reply_to(&msg, - format!("Temp {:?} issued for {:?} minutes",Badge::Moderator,TEMP_BADGE_DUR_MIN) - ).await ; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to( + &msg, + format!( + "Temp {:?} issued for {:?} minutes", + Badge::Moderator, + TEMP_BADGE_DUR_MIN + ), + ) + .await; } - } if arg == "vip" { - let curr_temp_badges = bot.get_channel_guest_badges(msg.sender.login.clone(), msg.channel_login.clone()).await; + let curr_temp_badges = bot + .get_channel_guest_badges( + msg.sender.login.clone(), + msg.channel_login.clone(), + ) + .await; let mut found = false; for temp_badge in curr_temp_badges { if temp_badge.0 == Badge::Vip { found = true; - } + } } if found { /* do nothing */ } else { bot.issue_new_guest_badge( - msg.sender.login.clone(), - msg.channel_login.clone(), - Badge::Vip, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await; + msg.sender.login.clone(), + msg.channel_login.clone(), + Badge::Vip, + Instant::now(), + Duration::from_secs(60 * TEMP_BADGE_DUR_MIN), + ) + .await; - let _ = bot.chat.lock().await.say_in_reply_to(&msg, - format!("Temp {:?} issued for {:?} minutes for the bot admin",Badge::Vip,TEMP_BADGE_DUR_MIN) - ).await ; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to( + &msg, + format!( + "Temp {:?} issued for {:?} minutes for the bot admin", + Badge::Vip, + TEMP_BADGE_DUR_MIN + ), + ) + .await; } } if arg == "broadcaster" || arg == "strimmer" || arg == "streamer" { - let curr_temp_badges = bot.get_channel_guest_badges(msg.sender.login.clone(), msg.channel_login.clone()).await; + let curr_temp_badges = bot + .get_channel_guest_badges( + msg.sender.login.clone(), + msg.channel_login.clone(), + ) + .await; let mut found = false; for temp_badge in curr_temp_badges { if temp_badge.0 == Badge::Broadcaster { found = true; - } + } } if found { /* do nothing */ } else { bot.issue_new_guest_badge( - msg.sender.login.clone(), - msg.channel_login.clone(), - Badge::Broadcaster, Instant::now(), Duration::from_secs(60*TEMP_BADGE_DUR_MIN)).await; - - let _ = bot.chat.lock().await.say_in_reply_to(&msg, - format!("Temp {:?} issued for {:?} minutes for the bot admin",Badge::Broadcaster,TEMP_BADGE_DUR_MIN) - ).await ; + msg.sender.login.clone(), + msg.channel_login.clone(), + Badge::Broadcaster, + Instant::now(), + Duration::from_secs(60 * TEMP_BADGE_DUR_MIN), + ) + .await; + + let _ = bot + .chat + .lock() + .await + .say_in_reply_to( + &msg, + format!( + "Temp {:?} issued for {:?} minutes for the bot admin", + Badge::Broadcaster, + TEMP_BADGE_DUR_MIN + ), + ) + .await; } } } } // let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("Disabled!")).await ; } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set and Store the execution body using `execution_async()` */ @@ -314,8 +395,5 @@ pub mod built_in_objects { // /* 5. optionally, set min badge*/ // cmd.set_min_badge(Badge::Moderator); cmd - - } - - -} \ No newline at end of file + } +} diff --git a/forcebot_core/src/botcore/bot_objects/command.rs b/forcebot_core/src/botcore/bot_objects/command.rs index b72cc8a..10a1e6b 100644 --- a/forcebot_core/src/botcore/bot_objects/command.rs +++ b/forcebot_core/src/botcore/bot_objects/command.rs @@ -2,131 +2,124 @@ use std::sync::Arc; use twitch_irc::message::{PrivmsgMessage, ServerMessage}; - -use super::{execution_async,Bot,Badge,command_condition_async}; - +use super::{command_condition_async, execution_async, Badge, Bot}; use super::{CommandTrigger, ExecBody}; /// Bot `Command` that stores trigger condition callback and a execution functon -/// +/// /// A prefix character or phrase can be defined for the bot to evaluate a trigger condition -/// +/// /// A command or command phrase defines the phrase after the prefix phrase -/// +/// /// If no min badge role is provided, Broadcaster is defaulted. All commands require at least a vip role -/// -/// AdminOnly commands can only be ran by admin -/// +/// +/// AdminOnly commands can only be ran by admin +/// /// Use `execution_async()` on custom async execution bodies #[derive(Clone)] -pub struct Command -{ - commands : Vec<String>, - exec_fn : Arc<ExecBody>, - min_badge : Badge, +pub struct Command { + commands: Vec<String>, + exec_fn: Arc<ExecBody>, + min_badge: Badge, /// only admins can run - default : `true` - admin_only : bool, + admin_only: bool, /// admin role overrides channel badge - default : `false` - admin_override : bool, - prefix : String, - custom_cond_fn : fn(Arc<Bot>,PrivmsgMessage) -> bool, - custom_cond_async : Arc<CommandTrigger>, + admin_override: bool, + prefix: String, + custom_cond_fn: fn(Arc<Bot>, PrivmsgMessage) -> bool, + custom_cond_async: Arc<CommandTrigger>, } -impl Command -{ - +impl Command { /// Creates a new empty `Command` using command `String` and prefix `String` /// Pass an empty string prefix if the bot should use the bot default /// /// Call `set_trigger_cond_fn()` and `set_exec_fn()` to trigger & execution function callbacks /// if a blank prefix is given, the bot will look for the bot prefix instead - /// + /// /// By default, the new command is admin_only - pub fn new(commands:Vec<String>,prefix:String) -> Command { - - async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> - { Result::Ok("success".to_string()) } - async fn condition01(_:Arc<Bot>,_:PrivmsgMessage) -> bool { true } + pub fn new(commands: Vec<String>, prefix: String) -> Command { + async fn execbody(_: Arc<Bot>, _: ServerMessage) -> Result<String, String> { + Result::Ok("success".to_string()) + } + async fn condition01(_: Arc<Bot>, _: PrivmsgMessage) -> bool { + true + } Command { - commands , - prefix , - exec_fn : Arc::new(execution_async(execbody)), - min_badge : Badge::Vip, - admin_only : true, - admin_override : false , - custom_cond_fn : |_:Arc<Bot>,_:PrivmsgMessage| true, - custom_cond_async : Arc::new(command_condition_async(condition01)), + commands, + prefix, + exec_fn: Arc::new(execution_async(execbody)), + min_badge: Badge::Vip, + admin_only: true, + admin_override: false, + custom_cond_fn: |_: Arc<Bot>, _: PrivmsgMessage| true, + custom_cond_async: Arc::new(command_condition_async(condition01)), } } /// set a trigger condition callback that returns true if the command should trigger - pub fn set_custom_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,PrivmsgMessage) -> bool) { + pub fn set_custom_cond_fn(&mut self, cond_fn: fn(Arc<Bot>, PrivmsgMessage) -> bool) { self.custom_cond_fn = cond_fn; } - /// sets the async trigger condition for listener - /// + /// /// Same as `set_custom_cond_fn()` , but async define - /// + /// /// Use`execution_async()` on the async fn when storing - /// - /// Example - + /// + /// Example - /// ```rust /// /* 1. Create a new blank Listener */ /// let mut cmd = Command::new(); /// /// /* 2. define an async function */ /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } - /// + /// /// /* 3. Set and Store the execution body using `execution_async()` */ /// cmd.set_custom_cond_async(condition_async(condition01)); /// ``` - /// - pub fn set_custom_cond_async(&mut self,condition:CommandTrigger ) { + /// + pub fn set_custom_cond_async(&mut self, condition: CommandTrigger) { self.custom_cond_async = Arc::new(condition); } /// sets the execution body of the listener for when it triggers - /// + /// /// Use`execution_async()` on the async fn when storing - /// - /// - pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) { + /// + /// + pub fn set_exec_fn(&mut self, exec_fn: ExecBody) { self.exec_fn = Arc::new(exec_fn); } /// checks if the trigger condition is met /// specifically if the message is a valid command and min badge roles provided - /// - pub async fn command_triggered(&self,bot:Arc<Bot>,msg:PrivmsgMessage) -> bool { - - fn cmd_called(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { - let mut prefixed_cmd = "".to_string(); - if cmd.prefix == "" { - prefixed_cmd.push_str(&bot.get_prefix()); - } else { - prefixed_cmd.push_str(&cmd.prefix); + /// + pub async fn command_triggered(&self, bot: Arc<Bot>, msg: PrivmsgMessage) -> bool { + fn cmd_called(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool { + let mut prefixed_cmd = "".to_string(); + if cmd.prefix == "" { + prefixed_cmd.push_str(&bot.get_prefix()); + } else { + prefixed_cmd.push_str(&cmd.prefix); + } + for cmd_nm in &cmd.commands { + prefixed_cmd.push_str(cmd_nm); + if message.message_text.starts_with(prefixed_cmd.as_str()) { + return true; } - for cmd_nm in &cmd.commands { - prefixed_cmd.push_str(cmd_nm); - if message.message_text.starts_with(prefixed_cmd.as_str()) { - return true; - } - }; - return false; + } + return false; } - - async fn caller_badge_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { - + async fn caller_badge_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool { // senders that are admins skip badge check if the command is adminonly - if cmd.admin_only && bot.get_admins().contains(&message.sender.login) { + if cmd.admin_only && bot.get_admins().contains(&message.sender.login) { return true; - } ; + }; // adminOnly commands will can only be ran by admins if cmd.admin_only && bot.get_admins().contains(&message.sender.login) { @@ -134,35 +127,41 @@ impl Command } // admin role overrides badge check if enabled - if cmd.admin_override && bot.get_admins().contains( &message.sender.login) { return true; } + if cmd.admin_override && bot.get_admins().contains(&message.sender.login) { + return true; + } for badge in message.badges { - match cmd.min_badge { Badge::Broadcaster => { - if badge.name == "broadcaster" { return true } - else { return false } - }, - Badge::Moderator => { - match badge.name.as_str() { - "moderator" | "broadcaster" => return true, - _ => (), + if badge.name == "broadcaster" { + return true; + } else { + return false; } + } + Badge::Moderator => match badge.name.as_str() { + "moderator" | "broadcaster" => return true, + _ => (), }, - Badge::Vip => { - match badge.name.as_str() { - "vip" | "moderator" | "broadcaster" => return true, - _ => (), - } + Badge::Vip => match badge.name.as_str() { + "vip" | "moderator" | "broadcaster" => return true, + _ => (), }, } } - for temp_badge in bot.get_channel_guest_badges(message.sender.login, message.channel_login).await { - match (cmd.min_badge.clone(),temp_badge.0) { - (Badge::Broadcaster,Badge::Broadcaster) => return true, - (Badge::Moderator,Badge::Moderator) | (Badge::Moderator,Badge::Broadcaster) => return true, - (Badge::Vip,Badge::Vip)|(Badge::Vip,Badge::Moderator)|(Badge::Vip,Badge::Broadcaster) => return true, + for temp_badge in bot + .get_channel_guest_badges(message.sender.login, message.channel_login) + .await + { + match (cmd.min_badge.clone(), temp_badge.0) { + (Badge::Broadcaster, Badge::Broadcaster) => return true, + (Badge::Moderator, Badge::Moderator) + | (Badge::Moderator, Badge::Broadcaster) => return true, + (Badge::Vip, Badge::Vip) + | (Badge::Vip, Badge::Moderator) + | (Badge::Vip, Badge::Broadcaster) => return true, _ => (), } } @@ -170,59 +169,58 @@ impl Command return false; } - - /// determines if the command caller can run the command + /// determines if the command caller can run the command /// based on admin_only flag - /// + /// /// callers who are admins can run admin_only commands /// callers can run non-admin_only commands - fn admin_only_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { - if (cmd.admin_only && bot.get_admins().contains(&message.sender.login)) || !cmd.admin_only { + fn admin_only_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool { + if (cmd.admin_only && bot.get_admins().contains(&message.sender.login)) + || !cmd.admin_only + { return true; } else { return false; } } - async fn custom_cond_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { - (cmd.custom_cond_fn)(bot.clone(),message.clone()) && (cmd.custom_cond_async)(bot,message).await + async fn custom_cond_ok(cmd: &Command, bot: Arc<Bot>, message: PrivmsgMessage) -> bool { + (cmd.custom_cond_fn)(bot.clone(), message.clone()) + && (cmd.custom_cond_async)(bot, message).await } // async fn quiet_off_ok(cmd:&Command,bot:Arc<Bot>,message:PrivmsgMessage) -> bool { - // !bot.chat.lock().await.get_channel_quiet(message.channel_login.clone()) + // !bot.chat.lock().await.get_channel_quiet(message.channel_login.clone()) // || bot.chat.lock().await.get_channel_quiet(message.channel_login.clone()) && cmd.commands.contains(&("quiet off".to_string())) // } - - cmd_called(self, bot.clone(), msg.clone()) && - caller_badge_ok(self, bot.clone(), msg.clone()).await && - admin_only_ok(self, bot.clone(), msg.clone()) && - custom_cond_ok(self, bot.clone(), msg.clone()).await + cmd_called(self, bot.clone(), msg.clone()) + && caller_badge_ok(self, bot.clone(), msg.clone()).await + && admin_only_ok(self, bot.clone(), msg.clone()) + && custom_cond_ok(self, bot.clone(), msg.clone()).await // && // quiet_off_ok(self, bot, msg).await - } /// executes the listeners executon body - pub async fn execute_fn(&self,bot:Arc<Bot>,msg:ServerMessage) -> Result<String, String> { - (self.exec_fn)(bot,msg).await + pub async fn execute_fn(&self, bot: Arc<Bot>, msg: ServerMessage) -> Result<String, String> { + (self.exec_fn)(bot, msg).await } - /// sets min_badge to run the cmd // pub fn set_min_badge(&mut self,min_badge:String) { - pub fn set_min_badge(&mut self,min_badge:Badge) { + pub fn set_min_badge(&mut self, min_badge: Badge) { self.min_badge = min_badge } /// sets admin_only - pub fn set_admin_only(&mut self,admin_only:bool) { + pub fn set_admin_only(&mut self, admin_only: bool) { self.admin_only = admin_only } - /// sets admin_override . This lets admins bypass + /// sets admin_override . This lets admins bypass /// badge restrictions - pub fn set_admin_override(&mut self,admin_override:bool) { + pub fn set_admin_override(&mut self, admin_override: bool) { self.admin_override = admin_override } } diff --git a/forcebot_core/src/botcore/bot_objects/listener.rs b/forcebot_core/src/botcore/bot_objects/listener.rs index 24f7ce3..2633b3b 100644 --- a/forcebot_core/src/botcore/bot_objects/listener.rs +++ b/forcebot_core/src/botcore/bot_objects/listener.rs @@ -1,124 +1,126 @@ use std::sync::Arc; - use twitch_irc::message::ServerMessage; use crate::Module; -use super::{execution_async,Bot,listener_condition_async}; - +use super::{execution_async, listener_condition_async, Bot}; + use super::{ExecBody, ListenerTrigger}; /// Bot `Listener` that stores trigger condition callback and a execution functon -/// -/// Use `Listener` functions to define the Trigger Condition & Execution callbacks. -/// When the Trigger callback is `true`, the Execution callback runs in the bot loop -/// +/// +/// Use `Listener` functions to define the Trigger Condition & Execution callbacks. +/// When the Trigger callback is `true`, the Execution callback runs in the bot loop +/// /// Create a new empty `Listener` with `new()` -/// +/// /// Use the following on the empty listener before loading it into the bot to set the callbacks -/// -/// - `set_trigger_cond_fn()` - to define the Trigger condition callback -/// +/// +/// - `set_trigger_cond_fn()` - to define the Trigger condition callback +/// /// - `set_exec_fn()` - to define the Execution Callback #[derive(Clone)] -pub struct Listener -{ +pub struct Listener { /// trigger condition - trigger_cond_fn : fn(Arc<Bot>,ServerMessage) -> bool, + trigger_cond_fn: fn(Arc<Bot>, ServerMessage) -> bool, /// trigger condition for async - trigger_cond_async : Arc<ListenerTrigger> , + trigger_cond_async: Arc<ListenerTrigger>, /// execution body - exec_fn : Arc<ExecBody>, - parent_module : Arc<Option<Module>>, + exec_fn: Arc<ExecBody>, + parent_module: Arc<Option<Module>>, } -impl Listener -{ - - /// Creates a new empty `Listener` - /// - /// Use `Listener` functions to define the Trigger Condition & Execution callbacks. - /// When the Trigger callback is `true`, the Execution callback runs in the bot loop - /// +impl Listener { + /// Creates a new empty `Listener` + /// + /// Use `Listener` functions to define the Trigger Condition & Execution callbacks. + /// When the Trigger callback is `true`, the Execution callback runs in the bot loop + /// /// Use the following on the empty listener before loading it into the bot to set the callbacks - /// - /// - `set_trigger_cond_fn()` - to define the Trigger condition callback - /// + /// + /// - `set_trigger_cond_fn()` - to define the Trigger condition callback + /// /// - `set_exec_fn()` - to define the Execution Callback pub fn new() -> Listener { - - async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } - async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } + async fn execbody(_: Arc<Bot>, _: ServerMessage) -> Result<String, String> { + Result::Ok("success".to_string()) + } + async fn condition01(_: Arc<Bot>, _: ServerMessage) -> bool { + true + } Listener { - trigger_cond_fn : |_:Arc<Bot>,_:ServerMessage| true, - trigger_cond_async : Arc::new(listener_condition_async(condition01)), - exec_fn : Arc::new(execution_async(execbody)), - parent_module : Arc::new(None), + trigger_cond_fn: |_: Arc<Bot>, _: ServerMessage| true, + trigger_cond_async: Arc::new(listener_condition_async(condition01)), + exec_fn: Arc::new(execution_async(execbody)), + parent_module: Arc::new(None), } } /// set a trigger conditin callback that returns true if the listener shoud trigger - pub fn set_trigger_cond_fn(&mut self,cond_fn: fn(Arc<Bot>,ServerMessage) -> bool) { + pub fn set_trigger_cond_fn(&mut self, cond_fn: fn(Arc<Bot>, ServerMessage) -> bool) { self.trigger_cond_fn = cond_fn; } /// sets the async trigger condition for listener - /// + /// /// Same as `set_trigger_cond_fn()` , but async define - /// + /// /// Use`condition_async()` on the async fn when storing - /// - /// Example - + /// + /// Example - /// ```rust /// /* 1. Create a new blank Listener */ /// let mut listener = Listener::new(); /// /// /* 2. define an async function */ /// async fn condition01(_:Arc<Bot>,_:ServerMessage) -> bool { true } - /// + /// /// /* 3. Set and Store the execution body using `execution_async()` */ /// listener.set_trigger_cond_async(condition_async(condition01)); /// ``` - /// - pub fn set_trigger_cond_async(&mut self,condition:ListenerTrigger ) { + /// + pub fn set_trigger_cond_async(&mut self, condition: ListenerTrigger) { self.trigger_cond_async = Arc::new(condition); } - /// sets the execution body of the listener for when it triggers - /// + /// /// Use`execution_async()` on the async fn when storing - /// - /// Example - + /// + /// Example - /// ```rust /// /* 1. Create a new blank Listener */ /// let mut listener = Listener::new(); /// /// /* 2. define an async function */ /// async fn execbody(_:Arc<Bot>,_:ServerMessage) -> Result<String,String> {Result::Ok("success".to_string()) } - /// + /// /// /* 3. Set and Store the execution body using `execution_async()` */ /// listener.set_exec_fn(execution_async(execbody)); /// ``` - /// - pub fn set_exec_fn(&mut self,exec_fn:ExecBody ) { + /// + pub fn set_exec_fn(&mut self, exec_fn: ExecBody) { self.exec_fn = Arc::new(exec_fn); } /// checks if the trigger condition is met - pub async fn cond_triggered(&self,bot:Arc<Bot>,msg:ServerMessage) -> bool { - + pub async fn cond_triggered(&self, bot: Arc<Bot>, msg: ServerMessage) -> bool { let list = Arc::new(self.clone()); - async fn defined_conditions_ok(list:Arc<Listener>,bot:Arc<Bot>,msg:ServerMessage) -> bool { + async fn defined_conditions_ok( + list: Arc<Listener>, + bot: Arc<Bot>, + msg: ServerMessage, + ) -> bool { // let list = Arc::new(self); - (list.trigger_cond_fn)(bot.clone(),msg.clone()) && (list.trigger_cond_async)(bot,msg).await + (list.trigger_cond_fn)(bot.clone(), msg.clone()) + && (list.trigger_cond_async)(bot, msg).await } // async fn quiet_off_ok(list:Arc<Listener>,bot:Arc<Bot>,message:ServerMessage) -> bool { // if let ServerMessage::Privmsg(msg) = message { - + // if let Some(parent_mod) = &*list.parent_module { // return !bot.chat.lock().await.get_channel_quiet(msg.channel_login) || parent_mod.get_names().contains(&"debug".to_string()); // } @@ -128,22 +130,18 @@ impl Listener // return true; /* quiet is off for non chat msgs */ // } - defined_conditions_ok(list.clone(), bot.clone(), msg.clone()).await + defined_conditions_ok(list.clone(), bot.clone(), msg.clone()).await // && // quiet_off_ok(list, bot, msg).await } /// executes the listeners executon body - pub async fn execute_fn(&self,bot:Arc<Bot>,msg:ServerMessage) -> Result<String, String> { - - (self.exec_fn)(bot,msg).await + pub async fn execute_fn(&self, bot: Arc<Bot>, msg: ServerMessage) -> Result<String, String> { + (self.exec_fn)(bot, msg).await } /// sets parent module - pub fn set_parent_module(&mut self,module:Module) { + pub fn set_parent_module(&mut self, module: Module) { self.parent_module = Arc::new(Some(module)); } - - } - diff --git a/forcebot_core/src/botcore/built_in_mods.rs b/forcebot_core/src/botcore/built_in_mods.rs index 53e04a3..03b8d28 100644 --- a/forcebot_core/src/botcore/built_in_mods.rs +++ b/forcebot_core/src/botcore/built_in_mods.rs @@ -4,11 +4,7 @@ use crate::Bot; pub mod quiet; - /// used to internally load internal modules -pub async fn load_built_in_mods(bot:&Bot){ - +pub async fn load_built_in_mods(bot: &Bot) { bot.load_module(quiet::create_module()).await; - } - diff --git a/forcebot_core/src/botcore/built_in_mods/quiet.rs b/forcebot_core/src/botcore/built_in_mods/quiet.rs index 865c81b..7a12cc1 100644 --- a/forcebot_core/src/botcore/built_in_mods/quiet.rs +++ b/forcebot_core/src/botcore/built_in_mods/quiet.rs @@ -4,18 +4,17 @@ use twitch_irc::message::ServerMessage; use crate::{execution_async, Badge, Bot, Command, Module}; - /// quiet the bot in a channel /// -/// use +/// use /// `quiet on` /// `quiet off` -/// -/// -/// +/// +/// +/// /// Use this function when loading modules into the bot -/// +/// /// For example /// ```rust /// bot.load_module(quiet::create_module()); @@ -23,38 +22,33 @@ use crate::{execution_async, Badge, Bot, Command, Module}; /// pub fn create_module() -> Module { /* 1. Create a new module */ - let mut custom_mod = Module::new( - vec!["quiet".to_string()], - "".to_string()); + let mut custom_mod = Module::new(vec!["quiet".to_string()], "".to_string()); /* 2. Load the cmd into a new module */ custom_mod.load_command(cmd_quiet_on()); custom_mod.load_command(cmd_quiet_off()); custom_mod - } /// Command definition for quiet command fn cmd_quiet_on() -> Command { /* 1. Create a new cmd */ - let mut cmd = Command::new(vec!["quiet on".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["quiet on".to_string()], "".to_string()); /* 2. Define exec callback */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - // dbg!("quiet on called"); let chatlock = bot.chat.lock().await; - let _=chatlock.say_in_reply_to(&msg, "Shush ".to_string()).await; - + let _ = chatlock.say_in_reply_to(&msg, "Shush ".to_string()).await; + chatlock.set_channel_quiet(msg.channel_login.clone(), true); - println!("channel {} set quiet true",msg.channel_login); - + println!("channel {} set quiet true", msg.channel_login); return Result::Ok("Success".to_string()); } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set Command flags */ @@ -69,21 +63,21 @@ fn cmd_quiet_on() -> Command { /// Command definition for quiet command fn cmd_quiet_off() -> Command { /* 1. Create a new cmd */ - let mut cmd = Command::new(vec!["quiet off".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["quiet off".to_string()], "".to_string()); /* 2. Define exec callback */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - let chatlock = bot.chat.lock().await; - + chatlock.set_channel_quiet(msg.channel_login.clone(), false); - let _=chatlock.say_in_reply_to(&msg, "GoodGirl I'll be good for u chat rar ".to_string()).await; - - - println!("channel {} set quiet false",msg.channel_login); + let _ = chatlock + .say_in_reply_to(&msg, "GoodGirl I'll be good for u chat rar ".to_string()) + .await; + + println!("channel {} set quiet false", msg.channel_login); } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set Command flags */ diff --git a/forcebot_core/src/botcore/chat.rs b/forcebot_core/src/botcore/chat.rs index d548a4f..42f1ec6 100644 --- a/forcebot_core/src/botcore/chat.rs +++ b/forcebot_core/src/botcore/chat.rs @@ -1,34 +1,36 @@ -use std::{fmt::Error, ops::Mul, rc::Rc, sync::{Arc, Mutex, RwLock}}; +use std::{ + fmt::Error, + ops::Mul, + rc::Rc, + sync::{Arc, Mutex, RwLock}, +}; -use twitch_irc::{login::StaticLoginCredentials, message::ReplyToMessage, SecureTCPTransport, TwitchIRCClient}; +use twitch_irc::{ + login::StaticLoginCredentials, message::ReplyToMessage, SecureTCPTransport, TwitchIRCClient, +}; use crate::Bot; /// Bot API to send messages to send messages to chat -/// +/// /// Uses TwitchIRCClient say_in_reply_to() but enforces controls like quiet -/// -/// +/// +/// -pub struct Chat -{ +pub struct Chat { /// outbound chat client msg stream - pub client: TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>, + pub client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>, /// channel_quiet - channel_quiet_yn: RwLock<Vec<(String,RwLock<bool>)>>, - + channel_quiet_yn: RwLock<Vec<(String, RwLock<bool>)>>, } impl Chat { - - - pub async fn new(client:TwitchIRCClient<SecureTCPTransport,StaticLoginCredentials>) - -> Chat { - Chat { + pub async fn new(client: TwitchIRCClient<SecureTCPTransport, StaticLoginCredentials>) -> Chat { + Chat { client, // parent_bot : Mutex::new(Bot::new().await) , - channel_quiet_yn : RwLock::new(vec![]), - } + channel_quiet_yn: RwLock::new(vec![]), + } } // pub fn set_parent_bot(&self,parent_bot_in:Arc<Bot>) @@ -38,23 +40,20 @@ impl Chat { // } /// helper - fn ok_to_send(&self,channel_login: String) -> bool { - - fn not_quiet_ok(chat:&Chat,channel_login:String) -> bool { + fn ok_to_send(&self, channel_login: String) -> bool { + fn not_quiet_ok(chat: &Chat, channel_login: String) -> bool { // let lock = chat.parent_bot.lock().unwrap(); // let a = lock.as_ref(); // if let Some(bot) = &*lock { return !chat.get_channel_quiet(channel_login); // } - // true + // true } not_quiet_ok(self, channel_login) - } - /// Get the quiet status of a channel - pub fn get_channel_quiet(&self,channel:String) -> bool { + pub fn get_channel_quiet(&self, channel: String) -> bool { for a in self.channel_quiet_yn.read().unwrap().iter() { if a.0 == channel { return a.1.read().unwrap().clone(); @@ -62,9 +61,9 @@ impl Chat { } return false; } - + /// Get the quiet status of a channel - pub fn set_channel_quiet(&self,channel:String,quiet_on:bool) { + pub fn set_channel_quiet(&self, channel: String, quiet_on: bool) { let mut found = false; let chnlquiet = self.channel_quiet_yn.read().unwrap(); @@ -77,22 +76,20 @@ impl Chat { } } drop(chnlquiet); - + if !found { // dbg!("set chn quiet > !found channel quiet status"); let mut chnlquiet = self.channel_quiet_yn.write().unwrap(); - chnlquiet.push((channel,RwLock::new(quiet_on))); + chnlquiet.push((channel, RwLock::new(quiet_on))); drop(chnlquiet); } - } - - - pub async fn say_in_reply_to(&self, - reply_to: &impl ReplyToMessage, - message: String - ) -> Result<(),()> { + pub async fn say_in_reply_to( + &self, + reply_to: &impl ReplyToMessage, + message: String, + ) -> Result<(), ()> { // reply_to.channel_login() if self.ok_to_send(reply_to.channel_login().to_string()) { match self.client.say_in_reply_to(reply_to, message).await { @@ -102,50 +99,42 @@ impl Chat { } else { return Err(()); } - } - pub async fn say(&self, - channel_login: String, - message: String, - ) -> Result<(),()> { + pub async fn say(&self, channel_login: String, message: String) -> Result<(), ()> { if self.ok_to_send(channel_login.to_string()) { -match self.client.say(channel_login, message).await { - Ok(_) => return Ok(()), - Err(_) => return Err(()), - } + match self.client.say(channel_login, message).await { + Ok(_) => return Ok(()), + Err(_) => return Err(()), + } } else { return Err(()); } } - pub async fn me(&self, - channel_login: String, - message: String, - ) -> Result<(),()> { + pub async fn me(&self, channel_login: String, message: String) -> Result<(), ()> { if self.ok_to_send(channel_login.to_string()) { -match self.client.me(channel_login, message).await { - Ok(_) => return Ok(()), - Err(_) => return Err(()), - } + match self.client.me(channel_login, message).await { + Ok(_) => return Ok(()), + Err(_) => return Err(()), + } } else { return Err(()); } - } - pub async fn me_in_reply_to(&self, + pub async fn me_in_reply_to( + &self, reply_to: &impl ReplyToMessage, - message: String -) -> Result<(),()> { - if self.ok_to_send(reply_to.channel_login().to_string()) { - match self.client.me_in_reply_to(reply_to, message).await { - Ok(_) => return Ok(()), - Err(_) => return Err(()), + message: String, + ) -> Result<(), ()> { + if self.ok_to_send(reply_to.channel_login().to_string()) { + match self.client.me_in_reply_to(reply_to, message).await { + Ok(_) => return Ok(()), + Err(_) => return Err(()), + } + } else { + return Err(()); + } } - } else { - return Err(()); - } - - } -} \ No newline at end of file +} diff --git a/forcebot_core/src/botcore/modules.rs b/forcebot_core/src/botcore/modules.rs index d3802b5..dd9cc29 100644 --- a/forcebot_core/src/botcore/modules.rs +++ b/forcebot_core/src/botcore/modules.rs @@ -1,11 +1,9 @@ - // use std::sync::{Arc, Mutex}; use super::bot_objects::command::Command; use super::bot_objects::listener::Listener; - -#[derive(PartialEq, Eq,Debug,Clone)] +#[derive(PartialEq, Eq, Debug, Clone)] pub enum Status { Disabled, Enabled, @@ -13,24 +11,22 @@ pub enum Status { } /// Bot `Module` that groups a set of `bot_objects` -/// +/// /// Elevated chatters can disable modules by their name or chat alias #[derive(Clone)] -pub struct Module -{ +pub struct Module { name: Vec<String>, // _alias: String, - bot_read_description : String, + bot_read_description: String, listeners: Vec<Listener>, commands: Vec<Command>, // disable module at load for bot channels default_status_per_channel: Status, } -impl Module -{ +impl Module { /// create a new module - pub fn new(name:Vec<String>,bot_read_description:String) -> Module { + pub fn new(name: Vec<String>, bot_read_description: String) -> Module { Module { name, // _alias: alias, @@ -42,20 +38,20 @@ impl Module } /// Loads a `Listener` into the module - pub fn load_listener(&mut self,mut l : Listener) { + pub fn load_listener(&mut self, mut l: Listener) { l.set_parent_module(self.clone()); self.listeners.push(l); } /// Loads a `Command` into the module - pub fn load_command(&mut self,c : Command) { - self.commands.push(c); + pub fn load_command(&mut self, c: Command) { + self.commands.push(c); } pub fn get_listeners(&self) -> Vec<Listener> { self.listeners.clone() } - + pub fn get_commands(&self) -> Vec<Command> { self.commands.clone() } @@ -68,13 +64,11 @@ impl Module self.bot_read_description.clone() } - pub fn set_status_by_default(&mut self,status:Status){ + pub fn set_status_by_default(&mut self, status: Status) { self.default_status_per_channel = status; } pub fn get_status_by_default(&self) -> Status { self.default_status_per_channel.clone() } - - -} \ No newline at end of file +} diff --git a/forcebot_core/src/custom_mods.rs b/forcebot_core/src/custom_mods.rs index 754b7b9..fdbd664 100644 --- a/forcebot_core/src/custom_mods.rs +++ b/forcebot_core/src/custom_mods.rs @@ -1,4 +1,4 @@ +pub mod debug; pub mod guest_badge; pub mod pyramid; -pub mod debug; -// pub mod quiet; \ No newline at end of file +// pub mod quiet; diff --git a/forcebot_core/src/custom_mods/debug.rs b/forcebot_core/src/custom_mods/debug.rs index 4bbfc73..0457e54 100644 --- a/forcebot_core/src/custom_mods/debug.rs +++ b/forcebot_core/src/custom_mods/debug.rs @@ -1,23 +1,20 @@ - - use std::sync::Arc; use crate::{execution_async, modules::Status, Bot, Command, Listener, Module}; use twitch_irc::message::ServerMessage; /// debug module -/// +/// /// Commands to enable debugging messages in chat -/// +/// /// `debug on` to start -/// +/// /// `debug off` to stop -/// -/// - +/// +/// /// Use this function when loading modules into the bot -/// +/// /// For example /// ```rust /// bot.load_module(debug::create_module()); @@ -25,38 +22,42 @@ use twitch_irc::message::ServerMessage; /// pub fn create_module() -> Module { /* 1. Create a new module */ - let mut custom_mod = Module::new( - vec!["debug".to_string()], - "".to_string()); + let mut custom_mod = Module::new(vec!["debug".to_string()], "".to_string()); /* 2. Load the cmd into a new module */ custom_mod.load_command(cmd_debug_on()); custom_mod.load_command(cmd_debug_off()); custom_mod - } /// Command definition for debug command fn cmd_debug_on() -> Command { /* 1. Create a new cmd */ - let mut cmd = Command::new(vec!["debug on".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["debug on".to_string()], "".to_string()); /* 2. Define exec callback */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { // dbg!("debug cmd on executed"); - let modulename="debug listener".to_string(); + let modulename = "debug listener".to_string(); - if let Status::NotLoaded = bot.get_channel_module_status(msg.channel_login.clone(), modulename.clone()).await { + if let Status::NotLoaded = bot + .get_channel_module_status(msg.channel_login.clone(), modulename.clone()) + .await + { let module = create_listener_module(modulename.clone()); bot.load_module(module.clone()).await; } let modl = bot.get_module(modulename).await.unwrap(); - bot.enable_module(msg.channel_login.clone(), modl.get_names().first().unwrap().clone()).await; - println!("Debug enabled for channel {}",msg.channel_login); + bot.enable_module( + msg.channel_login.clone(), + modl.get_names().first().unwrap().clone(), + ) + .await; + println!("Debug enabled for channel {}", msg.channel_login); } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set Command flags */ @@ -71,24 +72,28 @@ fn cmd_debug_on() -> Command { /// Command definition for debug off command fn cmd_debug_off() -> Command { /* 1. Create a new cmd */ - let mut cmd = Command::new(vec!["debug off".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["debug off".to_string()], "".to_string()); /* 2. Define exec callback */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { // dbg!("debug cmd on executed"); - let modulename="debug listener".to_string(); + let modulename = "debug listener".to_string(); // if let Status::NotLoaded = bot.get_channel_module_status(msg.channel_login.clone(), modulename.clone()).await { // let module = create_listener_module(modulename.clone()); // bot.load_module(module.clone()).await; // } let modl = bot.get_module(modulename).await.unwrap(); - bot.disable_module(msg.channel_login.clone(), modl.get_names().first().unwrap().clone()).await; - println!("Debug disabled for channel {}",msg.channel_login); + bot.disable_module( + msg.channel_login.clone(), + modl.get_names().first().unwrap().clone(), + ) + .await; + println!("Debug disabled for channel {}", msg.channel_login); } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set Command flags */ @@ -100,41 +105,34 @@ fn cmd_debug_off() -> Command { cmd } -fn create_listener_module(name:String) -> Module { - - let mut custom_mod = Module::new( - vec![name], - "".to_string()); - // dbg!("debug listener module created"); +fn create_listener_module(name: String) -> Module { + let mut custom_mod = Module::new(vec![name], "".to_string()); + // dbg!("debug listener module created"); custom_mod.load_listener(cmd_debug_listener()); custom_mod.set_status_by_default(Status::Disabled); custom_mod - } /// Listener for debug fn cmd_debug_listener() -> Listener { - // dbg!("Creating debug listener"); - /* 2a. Create a new blank Listener */ - let mut listener = Listener::new(); + // dbg!("Creating debug listener"); + /* 2a. Create a new blank Listener */ + let mut listener = Listener::new(); - /* 2b. Set a trigger condition function for listener */ - listener.set_trigger_cond_fn( - |_:Arc<Bot>,_:ServerMessage| true - ); - - /* 2c. Define an async fn callback execution */ - async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { - if let ServerMessage::Privmsg(msg) = message { - dbg!(msg); /* outputs message to debug */ - } - Result::Err("Not Valid message type".to_string()) - } - - /* 2d. Set and Store the execution body using `execution_async()` */ - listener.set_exec_fn(execution_async(execbody)); + /* 2b. Set a trigger condition function for listener */ + listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true); - listener + /* 2c. Define an async fn callback execution */ + async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> { + if let ServerMessage::Privmsg(msg) = message { + dbg!(msg); /* outputs message to debug */ + } + Result::Err("Not Valid message type".to_string()) + } + + /* 2d. Set and Store the execution body using `execution_async()` */ + listener.set_exec_fn(execution_async(execbody)); + + listener } - diff --git a/forcebot_core/src/custom_mods/guest_badge.rs b/forcebot_core/src/custom_mods/guest_badge.rs index 39c121d..2cf4ae7 100644 --- a/forcebot_core/src/custom_mods/guest_badge.rs +++ b/forcebot_core/src/custom_mods/guest_badge.rs @@ -1,91 +1,109 @@ -use std::{sync::Arc, time::{Duration, Instant}}; +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; use twitch_irc::message::ServerMessage; use crate::{execution_async, Badge, Bot, Command, Module}; /// guest_badge / guest module -/// +/// /// Temporary badges can be issued to chatters. The bot then opens functionality /// to that chatter based on the recognized role /// -/// Chatters with real badge roles will be able to share guest +/// Chatters with real badge roles will be able to share guest /// badges based on their role -/// -/// -/// - -const VIP_GIVEN_DUR_MIN:u64 = 15; -const MOD_GIVEN_DUR_MIN:u64 = 30; +/// +/// +/// +const VIP_GIVEN_DUR_MIN: u64 = 15; +const MOD_GIVEN_DUR_MIN: u64 = 30; /// Use this function when loading modules into the bot -/// +/// /// For example /// ```rust /// bot.load_module(guest_badge::create_module()); /// ``` -/// +/// pub fn create_module() -> Module { - let mut custom_mod = Module::new( - vec!["guests".to_string()], - "Temp Guest badges can be given by chatters with badges. ".to_string()); + vec!["guests".to_string()], + "Temp Guest badges can be given by chatters with badges. ".to_string(), + ); custom_mod.load_command(create_cmd_mod()); custom_mod.load_command(create_cmd_vip()); - - custom_mod + custom_mod } fn create_cmd_vip() -> Command { + let mut cmd = Command::new(vec!["vip".to_string()], "".to_string()); - let mut cmd = Command::new(vec!["vip".to_string()],"".to_string()); - - - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - let guest_dur_min = { - let mut result=VIP_GIVEN_DUR_MIN; + let mut result = VIP_GIVEN_DUR_MIN; for badge in msg.clone().badges { - if badge.name == "vip" { result = VIP_GIVEN_DUR_MIN ; } - if badge.name == "moderator" { result = MOD_GIVEN_DUR_MIN ; } + if badge.name == "vip" { + result = VIP_GIVEN_DUR_MIN; + } + if badge.name == "moderator" { + result = MOD_GIVEN_DUR_MIN; + } } result }; - - - let mut badges_issued =false; - for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { + + let mut badges_issued = false; + for (i, arg) in msg + .message_text + .replace("\u{e0000}", "") + .trim() + .split(" ") + .enumerate() + { if i > 1 { let mut already_vip = false; - - - for guest_badge in bot.get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone()).await { - if guest_badge.0 == Badge::Vip { already_vip = true } + + for guest_badge in bot + .get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone()) + .await + { + if guest_badge.0 == Badge::Vip { + already_vip = true + } } if !already_vip { - badges_issued= true; + badges_issued = true; bot.issue_new_guest_badge( - arg.trim().to_string(), - msg.channel_login.clone(), - Badge::Vip, Instant::now(), Duration::from_secs(60*guest_dur_min)).await; - + arg.trim().to_string(), + msg.channel_login.clone(), + Badge::Vip, + Instant::now(), + Duration::from_secs(60 * guest_dur_min), + ) + .await; } } } - if badges_issued { - - - let _= bot.chat.lock().await.say_in_reply_to( - &msg.clone(), format!("Guest badges issued for {} min",guest_dur_min)).await; + if badges_issued { + let _ = bot + .chat + .lock() + .await + .say_in_reply_to( + &msg.clone(), + format!("Guest badges issued for {} min", guest_dur_min), + ) + .await; return Result::Ok("Success".to_string()); } - } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } cmd.set_exec_fn(execution_async(execbody)); @@ -94,41 +112,58 @@ fn create_cmd_vip() -> Command { cmd.set_admin_override(true); cmd.set_min_badge(Badge::Vip); cmd - } fn create_cmd_mod() -> Command { + let mut cmd = Command::new(vec!["mod".to_string()], "".to_string()); - let mut cmd = Command::new(vec!["mod".to_string()],"".to_string()); - - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - - - let mut badges_issued =false; - for (i,arg) in msg.message_text.replace("\u{e0000}","").trim().split(" ").enumerate() { + let mut badges_issued = false; + for (i, arg) in msg + .message_text + .replace("\u{e0000}", "") + .trim() + .split(" ") + .enumerate() + { if i > 1 { - let mut already_mod = false; - for guest_badge in bot.get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone()).await { - if guest_badge.0 == Badge::Moderator { already_mod = true } + for guest_badge in bot + .get_channel_guest_badges(arg.trim().to_string(), msg.channel_login.clone()) + .await + { + if guest_badge.0 == Badge::Moderator { + already_mod = true + } } if !already_mod { - badges_issued= true; + badges_issued = true; bot.issue_new_guest_badge( - arg.trim().to_string(), - msg.channel_login.clone(), - Badge::Moderator, Instant::now(), Duration::from_secs(60*MOD_GIVEN_DUR_MIN)).await; + arg.trim().to_string(), + msg.channel_login.clone(), + Badge::Moderator, + Instant::now(), + Duration::from_secs(60 * MOD_GIVEN_DUR_MIN), + ) + .await; } } - } + } if badges_issued { - let _= bot.chat.lock().await.say_in_reply_to( - &msg, format!("Guest badges issued for {} min",MOD_GIVEN_DUR_MIN)).await; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to( + &msg, + format!("Guest badges issued for {} min", MOD_GIVEN_DUR_MIN), + ) + .await; return Result::Ok("Success".to_string()); } } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } cmd.set_exec_fn(execution_async(execbody)); @@ -137,6 +172,4 @@ fn create_cmd_mod() -> Command { cmd.set_admin_override(true); cmd.set_min_badge(Badge::Moderator); cmd - - -} \ No newline at end of file +} diff --git a/forcebot_core/src/custom_mods/pyramid.rs b/forcebot_core/src/custom_mods/pyramid.rs index 8b36395..99deb25 100644 --- a/forcebot_core/src/custom_mods/pyramid.rs +++ b/forcebot_core/src/custom_mods/pyramid.rs @@ -1,169 +1,174 @@ - - use std::sync::{Arc, Mutex}; use twitch_irc::message::{PrivmsgMessage, ServerMessage}; // use crate::{execution_async, listener_condition_async, Badge, Bot, Command, Listener, Module}; -use super::super::botcore::bot_objects::execution_async; -use super::super::botcore::bot_objects::listener_condition_async; -use super::super::botcore::bot_objects::listener::Listener; -use super::super::botcore::modules::Module; use super::super::botcore::bot::Bot; use super::super::botcore::bot_objects::command::Command; +use super::super::botcore::bot_objects::execution_async; +use super::super::botcore::bot_objects::listener::Listener; +use super::super::botcore::bot_objects::listener_condition_async; use super::super::botcore::bot_objects::Badge; +use super::super::botcore::modules::Module; /// pyramid module -/// +/// /// for detecting & handling pyramids -/// +/// /// - listener - detects pyramid /// - cmd & listener - interrupts some chatters temporarily -/// -/// +/// +/// use lazy_static::lazy_static; - /// Use this function when loading modules into the bot -/// +/// /// For example /// ```rust /// bot.load_module(pyramid::create_module()); /// ``` -/// +/// pub fn create_module() -> Module { - let mut custom_mod = Module::new( - vec!["pyramid".to_string(), - "pyramids".to_string()], - "o7 I can handle pyramids".to_string()); + vec!["pyramid".to_string(), "pyramids".to_string()], + "o7 I can handle pyramids".to_string(), + ); custom_mod.load_listener(create_pyramid_detector()); custom_mod - } fn create_pyramid_detector() -> Listener { + /* 1. Create a new blank Listener */ + let mut listener = Listener::new(); - /* 1. Create a new blank Listener */ - let mut listener = Listener::new(); - - /* 2. Define an async trigger condition callback */ - async fn condition01(bot:Arc<Bot>,message:ServerMessage) -> bool { - if let ServerMessage::Privmsg(msg) = message { - if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await && get_pyramid_size(msg.channel_login) > 3 { - return true; - } + /* 2. Define an async trigger condition callback */ + async fn condition01(bot: Arc<Bot>, message: ServerMessage) -> bool { + if let ServerMessage::Privmsg(msg) = message { + if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await + && get_pyramid_size(msg.channel_login) > 3 + { + return true; } - false } + false + } - /* 3. Set a trigger condition function for listener */ - listener.set_trigger_cond_async(listener_condition_async(condition01)); + /* 3. Set a trigger condition function for listener */ + listener.set_trigger_cond_async(listener_condition_async(condition01)); - - /* 4. Define an async fn callback execution */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { - if let ServerMessage::Privmsg(msg) = message { - dbg!("enter pyramid listener execution - after pyramid complete"); - // if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await { + /* 4. Define an async fn callback execution */ + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { + if let ServerMessage::Privmsg(msg) = message { + dbg!("enter pyramid listener execution - after pyramid complete"); + // if detect_pyramid_complete_ok(bot.clone(), msg.clone()).await { - // let _ = bot.chat.lock().await. - dbg!("> get start pattern"); - let pattern = get_start_pattern(msg.channel_login.clone()); - let mut outmsg ; + // let _ = bot.chat.lock().await. + dbg!("> get start pattern"); + let pattern = get_start_pattern(msg.channel_login.clone()); + let mut outmsg; - /* Prefer emote before pattern in case pattern is command */ - if pattern.len() < 50 { - outmsg = format!("Clap {}",pattern); - } else { - outmsg = "Clap".to_string(); - } - - dbg!(get_pyramid_size(msg.channel_login.clone())); - if get_pyramid_size(msg.channel_login.clone()) < 4 { - outmsg = format!("{} annytfMagniGlass",outmsg); - } - - dbg!("> start pattern :",pattern); - - dbg!("> say_in_reply_to completed :",outmsg.clone()); - let _ = bot.chat.lock().await.say_in_reply_to(&msg, outmsg).await ; - - dbg!("> set pyramid started - false"); - set_pyramid_started(msg.channel_login.clone(),false); - - return Result::Ok("Success".to_string()) ; - // } + /* Prefer emote before pattern in case pattern is command */ + if pattern.len() < 50 { + outmsg = format!("Clap {}", pattern); + } else { + outmsg = "Clap".to_string(); } - Result::Err("Not Valid message type".to_string()) + + dbg!(get_pyramid_size(msg.channel_login.clone())); + if get_pyramid_size(msg.channel_login.clone()) < 4 { + outmsg = format!("{} annytfMagniGlass", outmsg); + } + + dbg!("> start pattern :", pattern); + + dbg!("> say_in_reply_to completed :", outmsg.clone()); + let _ = bot.chat.lock().await.say_in_reply_to(&msg, outmsg).await; + + dbg!("> set pyramid started - false"); + set_pyramid_started(msg.channel_login.clone(), false); + + return Result::Ok("Success".to_string()); + // } } - - /* 5. Set and Store the execution body using `execution_async()` */ - listener.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b)))); + Result::Err("Not Valid message type".to_string()) + } - listener + /* 5. Set and Store the execution body using `execution_async()` */ + listener.set_exec_fn(Box::new(move |a, b| Box::pin(execbody(a, b)))); + listener } /// detect pyramid based on latest message and channel -/// -/// -async fn detect_pyramid_complete_ok(_bot:Arc<Bot>,msg:PrivmsgMessage) -> bool { +/// +/// +async fn detect_pyramid_complete_ok(_bot: Arc<Bot>, msg: PrivmsgMessage) -> bool { dbg!("enter detect_pyramid_complete()"); - let msgtext = msg.message_text.replace("","").replace("\u{e0000}","").trim().to_string(); + let msgtext = msg + .message_text + .replace("", "") + .replace("\u{e0000}", "") + .trim() + .to_string(); let msgchannel = msg.channel_login; let msgchatter = msg.sender.login; // 1. Check if Pyramid started in chat > and recognize pyramid started - if !is_pyramid_started(msgchannel.clone()) & check_start_pyramid(msgchannel.clone(),msgtext.clone(),) { + if !is_pyramid_started(msgchannel.clone()) + & check_start_pyramid(msgchannel.clone(), msgtext.clone()) + { dbg!("> set pyramid started - true"); - set_pyramid_started(msgchannel.clone(),true); - push_to_compare(msgchannel.clone(),msgchatter.clone(),get_start_pattern(msgchannel.clone())); - - + set_pyramid_started(msgchannel.clone(), true); + push_to_compare( + msgchannel.clone(), + msgchatter.clone(), + get_start_pattern(msgchannel.clone()), + ); } if is_pyramid_started(msgchannel.clone()) { - push_to_compare(msgchannel.clone(),msgchatter.clone(),msgtext.clone()); + push_to_compare(msgchannel.clone(), msgchatter.clone(), msgtext.clone()); } // 2a. If Pyramid Not Started, Assume message is a potential start pattern if !is_pyramid_started(msgchannel.clone()) { - set_start_pattern(msgchannel.clone(),msgtext.clone()); + set_start_pattern(msgchannel.clone(), msgtext.clone()); } // 2b. If Pyramid is Started, and the latest message is the pattern, check for - // symmetry to determine pyramid + // symmetry to determine pyramid - if is_pyramid_started(msgchannel.clone()) && msgtext.clone() == get_start_pattern(msgchannel.clone()) { + if is_pyramid_started(msgchannel.clone()) + && msgtext.clone() == get_start_pattern(msgchannel.clone()) + { if symmetry_ok(msgchannel.clone()) { return true; } else { dbg!("> set pyramid started - false"); - set_pyramid_started(msgchannel,false); + set_pyramid_started(msgchannel, false); - return false ; + return false; } } // 2c. if Pyramid is strted but latest message does not ontain pattern - if is_pyramid_started(msgchannel.clone()) && !msgtext.clone().contains( get_start_pattern(msgchannel.clone()).as_str()) { - + if is_pyramid_started(msgchannel.clone()) + && !msgtext + .clone() + .contains(get_start_pattern(msgchannel.clone()).as_str()) + { dbg!("> set pyramid started - false"); - set_pyramid_started(msgchannel,false); + set_pyramid_started(msgchannel, false); - return false ; + return false; } else { return false; - }; - } - -lazy_static!{ +lazy_static! { /// Message Compare stack per channel (channel:String,msgstack:Vec<(chatter:String,message:String)>) pub static ref COMPARE_MSG_STACK_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<(String,String)>>)>> = Mutex::new(vec![]); #[derive(Debug)] @@ -173,35 +178,34 @@ lazy_static!{ pub static ref START_PATTERNS_PER_CHNL: Mutex<Vec<(String,Mutex<String>)>> = Mutex::new(vec![]); /// Pyramid sze per channel (channel:String,started:bool) pub static ref PYRAMID_SIZE_PER_CHNL: Mutex<Vec<(String,Mutex<i32>)>> = Mutex::new(vec![]); - /// temp message stack checker + /// temp message stack checker pub static ref TEMP_MSG_STACK: Mutex<Vec<String>> = Mutex::new(vec![]); - + /// interruptor targets - (channel:String,chatters:Vec<String>>) pub static ref INTERRUPT_TRG_PER_CHNL: Mutex<Vec<(String,Mutex<Vec<String>>)>> = Mutex::new(vec![]); } -fn read_top_of_compare(channel:String) -> Option<(String,String)> { - +fn read_top_of_compare(channel: String) -> Option<(String, String)> { let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); for rec in comp_perchnl.iter() { if rec.0 == channel { let msg_stack = rec.1.lock().unwrap(); - + return msg_stack.last().cloned(); } } None } -fn pop_top_of_compare(channel:String) -> Option<(String,String)> { +fn pop_top_of_compare(channel: String) -> Option<(String, String)> { let comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); for rec in comp_perchnl.iter() { if rec.0 == channel { let mut msg_stack = rec.1.lock().unwrap(); - + let popped = msg_stack.pop(); return popped; } @@ -209,7 +213,7 @@ fn pop_top_of_compare(channel:String) -> Option<(String,String)> { None } -fn set_pyramid_started(channel:String,started:bool) { +fn set_pyramid_started(channel: String, started: bool) { let mut start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap(); let mut found = false; for rec in start_perchnl.iter() { @@ -217,14 +221,14 @@ fn set_pyramid_started(channel:String,started:bool) { found = true; let mut rec_started = rec.1.lock().unwrap(); *rec_started = started; - } + } } if !found { - start_perchnl.push((channel,Mutex::new(started))); + start_perchnl.push((channel, Mutex::new(started))); } } -fn is_pyramid_started(channel:String) -> bool { +fn is_pyramid_started(channel: String) -> bool { let start_perchnl = PYRAMID_STARTED_PER_CHNL.lock().unwrap(); for rec in start_perchnl.iter() { if rec.0 == channel { @@ -235,42 +239,37 @@ fn is_pyramid_started(channel:String) -> bool { false } -fn set_start_pattern(channel:String,pattern:String) { +fn set_start_pattern(channel: String, pattern: String) { let mut start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap(); let mut found = false; for rec in start_patterns.iter() { - if rec.0 == channel { found = true; let mut patternlock = rec.1.lock().unwrap(); *patternlock = pattern.clone(); - } - - } + } + } if !found { - start_patterns.push((channel.clone(),Mutex::new(pattern.clone()))); + start_patterns.push((channel.clone(), Mutex::new(pattern.clone()))); } } - -fn get_start_pattern(channel:String) -> String { +fn get_start_pattern(channel: String) -> String { let start_patterns = START_PATTERNS_PER_CHNL.lock().unwrap(); for rec in start_patterns.iter() { - if rec.0 == channel { let patternlock = rec.1.lock().unwrap(); return patternlock.clone(); - } - } + } + } return "".to_string(); } - /// pushes message to compare stack -fn push_to_compare(channel:String,chatter:String,message:String) { +fn push_to_compare(channel: String, chatter: String, message: String) { let mut comp_perchnl = COMPARE_MSG_STACK_PER_CHNL.lock().unwrap(); let mut found = false; @@ -278,20 +277,23 @@ fn push_to_compare(channel:String,chatter:String,message:String) { if rec.0 == channel { found = true; let mut msg_stack = rec.1.lock().unwrap(); - msg_stack.push((chatter.clone(),message.clone())); + msg_stack.push((chatter.clone(), message.clone())); // dbg!("Push message to cmp stack ; result last cmp_pchnl - ",comp_perchnl.last()); } } if !found { - comp_perchnl.push((channel,Mutex::new(vec![(chatter,message)]))); + comp_perchnl.push((channel, Mutex::new(vec![(chatter, message)]))); } - } - /// checks latest and next latest messages for potential start -fn check_start_pyramid(channel:String,msgtext: String) -> bool { - msgtext == format!("{} {}",get_start_pattern(channel.clone()),get_start_pattern(channel.clone())) +fn check_start_pyramid(channel: String, msgtext: String) -> bool { + msgtext + == format!( + "{} {}", + get_start_pattern(channel.clone()), + get_start_pattern(channel.clone()) + ) // msgtext == format!("{} {} {}", // get_start_pattern(channel.clone()), // get_start_pattern(channel.clone()), @@ -299,60 +301,80 @@ fn check_start_pyramid(channel:String,msgtext: String) -> bool { // ) } - /// pops the compare stack to determine symmetry -fn symmetry_ok(channel:String) -> bool { +fn symmetry_ok(channel: String) -> bool { let mut temp_stack = TEMP_MSG_STACK.lock().unwrap(); let mut checking_started = false; - if !(read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone())) { + if !(read_top_of_compare(channel.clone()) + .unwrap_or(("".to_string(), "".to_string())) + .1 + == get_start_pattern(channel.clone())) + { return false; } let mut pyramid_size = 0; loop { - - if !checking_started && read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 == get_start_pattern(channel.clone()) { + if !checking_started + && read_top_of_compare(channel.clone()) + .unwrap_or(("".to_string(), "".to_string())) + .1 + == get_start_pattern(channel.clone()) + { checking_started = true; - } + } - if temp_stack.last().is_none() || read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1.len() > temp_stack.last().unwrap_or(&"".to_string()).len() { - temp_stack.push(pop_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1); + if temp_stack.last().is_none() + || read_top_of_compare(channel.clone()) + .unwrap_or(("".to_string(), "".to_string())) + .1 + .len() + > temp_stack.last().unwrap_or(&"".to_string()).len() + { + temp_stack.push( + pop_top_of_compare(channel.clone()) + .unwrap_or(("".to_string(), "".to_string())) + .1, + ); pyramid_size += 1; - - } else if temp_stack.last().is_some() && read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1.len() < temp_stack.last().unwrap_or(&"".to_string()).len() { - + } else if temp_stack.last().is_some() + && read_top_of_compare(channel.clone()) + .unwrap_or(("".to_string(), "".to_string())) + .1 + .len() + < temp_stack.last().unwrap_or(&"".to_string()).len() + { temp_stack.pop(); - if temp_stack.last().unwrap_or(&"".to_string()).clone() == read_top_of_compare(channel.clone()).unwrap_or(("".to_string(),"".to_string())).1 { + if temp_stack.last().unwrap_or(&"".to_string()).clone() + == read_top_of_compare(channel.clone()) + .unwrap_or(("".to_string(), "".to_string())) + .1 + { temp_stack.pop(); - + continue; } else { - set_pyramid_size(channel.clone(), 0); temp_stack.clear(); return false; } - - } else { + } else { set_pyramid_size(channel.clone(), 0); - return false; + return false; } - if checking_started && read_top_of_compare(channel.clone()).unwrap().1 == get_start_pattern(channel.clone()) { - + if checking_started + && read_top_of_compare(channel.clone()).unwrap().1 == get_start_pattern(channel.clone()) + { /* leave pyramid size set for exection */ - set_pyramid_size(channel.clone(), pyramid_size*2-1); + set_pyramid_size(channel.clone(), pyramid_size * 2 - 1); temp_stack.clear(); return true; - } - + } } - - } - -fn set_pyramid_size(channel:String,size:i32) { +fn set_pyramid_size(channel: String, size: i32) { let mut size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap(); let mut found = false; for rec in size_perchnl.iter() { @@ -360,14 +382,14 @@ fn set_pyramid_size(channel:String,size:i32) { found = true; let mut rec_started = rec.1.lock().unwrap(); *rec_started = size; - } + } } if !found { - size_perchnl.push((channel,Mutex::new(size))); + size_perchnl.push((channel, Mutex::new(size))); } } -fn get_pyramid_size(channel:String) -> i32 { +fn get_pyramid_size(channel: String) -> i32 { let size_perchnl = PYRAMID_SIZE_PER_CHNL.lock().unwrap(); for rec in size_perchnl.iter() { if rec.0 == channel { @@ -379,88 +401,85 @@ fn get_pyramid_size(channel:String) -> i32 { } /// #todo -/// -/// pyramid interruptor -/// +/// +/// pyramid interruptor +/// /// pick chatters that will be interrupted if they solo build -/// +/// /// takes in arguments as chatters -/// +/// /// chatters are then interrupted for a random duration under 15m -/// -/// if a duration is given, take that duration eg 15m , 25m -/// -/// +/// +/// if a duration is given, take that duration eg 15m , 25m +/// +/// fn _create_interruptor_cmd() -> Command { - let mut cmd = Command::new(vec![ - "no pyramid".to_string(), - "no pyramids".to_string() - ], - "".to_string()); + let mut cmd = Command::new( + vec!["no pyramid".to_string(), "no pyramids".to_string()], + "".to_string(), + ); - /* 2. Define an async fn callback execution */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { - if let ServerMessage::Privmsg(msg) = message { - let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("test success")).await; - return Result::Ok("Success".to_string()) ; - } - Result::Err("Not Valid message type".to_string()) + /* 2. Define an async fn callback execution */ + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { + if let ServerMessage::Privmsg(msg) = message { + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, String::from("test success")) + .await; + return Result::Ok("Success".to_string()); } + Result::Err("Not Valid message type".to_string()) + } - /* 3. Set and Store the execution body using `execution_async()` */ - cmd.set_exec_fn(Box::new(move |a,b| Box::pin(execbody(a,b)))); + /* 3. Set and Store the execution body using `execution_async()` */ + cmd.set_exec_fn(Box::new(move |a, b| Box::pin(execbody(a, b)))); - /* 4. optionally, remove admin only default flag */ - cmd.set_admin_only(false); - - /* 5. optionally, set min badge*/ - cmd.set_min_badge(Badge::Moderator); + /* 4. optionally, remove admin only default flag */ + cmd.set_admin_only(false); + /* 5. optionally, set min badge*/ + cmd.set_min_badge(Badge::Moderator); cmd } /// #todo -fn _create_interruptor_module(channel:String) -> Module { +fn _create_interruptor_module(channel: String) -> Module { /* 1. Create a new module */ - let modname = format!("interruptor {}",channel); - let mut custom_mod = Module::new( - vec![modname], - "".to_string()); + let modname = format!("interruptor {}", channel); + let mut custom_mod = Module::new(vec![modname], "".to_string()); /* 2. Load the cmd into a new module */ custom_mod.load_listener(_create_interruptor_listener()); custom_mod - } /// #todo -fn _create_interruptor_listener() -> Listener { +fn _create_interruptor_listener() -> Listener { /* 2a. Create a new blank Listener */ let mut listener = Listener::new(); /* 2b. Set a trigger condition function for listener */ - listener.set_trigger_cond_fn( - |_:Arc<Bot>,_:ServerMessage| true - ); + listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true); /* 2c. Define an async fn callback execution */ - async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> { dbg!(message); /* outputs message to debug */ - Result::Ok("Success".to_string()) + Result::Ok("Success".to_string()) } /* 2d. Set and Store the execution body using `execution_async()` */ listener.set_exec_fn(execution_async(execbody)); listener - } /// #todo -/// +/// /// Returns Some(chatter) if the pyramid in progress is being built by a solo -fn _solo_building(_channel:String) -> Option<String> { +fn _solo_building(_channel: String) -> Option<String> { None } diff --git a/forcebot_core/src/lib.rs b/forcebot_core/src/lib.rs index f33057e..6d3f317 100644 --- a/forcebot_core/src/lib.rs +++ b/forcebot_core/src/lib.rs @@ -1,32 +1,32 @@ //! `forcebot_core` library for `forcebot-rs-v2` Twitch chat bot -//! +//! //! Customize by adding additional bot objects -//! +//! //! # New Bot -//! +//! //! Uses Env defined variables to create and run the bot -//! +//! //! ```rust //! use forcebot_core::Bot; -//! +//! //! #[tokio::main] //! pub async fn main() { -//! +//! //! /* 1. Create the bot using env */ //! let bot = Bot::new(); -//! +//! //! /* 2. Run the bot */ //! bot.run().await; -//! +//! //! } -//! +//! //! ``` -//! -//! +//! +//! //! # Customize with Modules -//! +//! //! A `Module` is a group of bot objects (eg `Command`) that elevated users can manage through built in `disable` and `enable` commands -//! +//! //! Custom `Modules` can be loaded into a new bot with minimum coding : just load the modules and run the bot //! //! ```rust @@ -48,16 +48,16 @@ //! } //! ``` //! -//! +//! //! # Create your own Custom Modules -//! +//! //! Create a custom `Module` by : -//! +//! //! 1. Defining Functions that create the Custom Bot Objects (eg `Command`) -//! +//! //! 2. Define a function that creates a `Module` with the Custom Bot Objects loaded -//! -//! +//! +//! //! ```rust //! use forcebot_core::Bot; //! @@ -86,7 +86,7 @@ //! pub fn new() -> Module { //! /* 1. Create a new module */ //! let mut custom_mod = Module::new( -//! vec!["test".to_string()], +//! vec!["test".to_string()], //! "".to_string()); //! //! /* 2. Load the cmd into a new module */ @@ -96,7 +96,7 @@ //! //! } //! -//! /// Command definition +//! /// Command definition //! pub fn cmd_test() -> Command { //! /* 1. Create a new cmd */ //! let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); @@ -107,7 +107,7 @@ //! let _= bot.client.say_in_reply_to( //! &msg, "test return".to_string()).await; //! } -//! Result::Err("Not Valid message type".to_string()) +//! Result::Err("Not Valid message type".to_string()) //! } //! //! /* 3. Set Command flags */ @@ -119,99 +119,99 @@ //! } //! } //! -//! +//! //! ``` -//! +//! //! # Simple Debug Listener //! Bot with a simple listener that listens for all messages and prints in output -//! +//! //! ```rust //! use std::sync::Arc; -//! +//! //! use forcebot_core::{execution_async, Bot, Listener}; //! use twitch_irc::message::ServerMessage; -//! +//! //! #[tokio::main] //! pub async fn main() { -//! +//! //! /* 1. Create the bot using env */ //! let mut bot = Bot::new(); -//! +//! //! /* 2a. Create a new blank Listener */ //! let mut listener = Listener::new(); -//! +//! //! /* 2b. Set a trigger condition function for listener */ //! listener.set_trigger_cond_fn( //! |_:Arc<Bot>,_:ServerMessage| true //! ); -//! +//! //! /* 2c. Define an async fn callback execution */ //! async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { //! dbg!(message); /* outputs message to debug */ -//! Result::Ok("Success".to_string()) +//! Result::Ok("Success".to_string()) //! } -//! +//! //! /* 2d. Set and Store the execution body using `execution_async()` */ //! listener.set_exec_fn(execution_async(execbody)); -//! +//! //! /* 3. Load the listener into the bot */ //! bot.load_listener(listener); -//! +//! //! /* 4. Run the bot */ //! bot.run().await; -//! +//! //! } -//! +//! //! ``` -//! +//! //! # Moderator Reactor -//! +//! //! ``` -//! +//! //! use std::sync::Arc; -//! +//! //! use forcebot_core::Bot; //! use forcebot_core::execution_async; //! use forcebot_core::Listener; //! use twitch_irc::message::ServerMessage; -//! -//! +//! +//! //! #[tokio::main] //! pub async fn main() { -//! +//! //! /* Create the bot using env */ //! let mut bot = Bot::new(); -//! +//! //! /* 1. Create a new blank Listener */ //! let mut listener = Listener::new(); -//! +//! //! /* 2. Set a trigger condition function for listener */ -//! +//! //! listener.set_trigger_cond_fn( -//! |_:Arc<Bot>,message:ServerMessage| +//! |_:Arc<Bot>,message:ServerMessage| //! if let ServerMessage::Privmsg(msg) = message { //! for badge in msg.badges { //! if matches!(badge, x if x.name == "moderator") { //! // dbg!("moderator found"); //! return true; //! } -//! } +//! } //! false //! } else { false } //! ); -//! +//! //! /* 3. Define an async fn callback execution */ //! async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { //! if let ServerMessage::Privmsg(msg) = message { //! let _ = bot.client.say_in_reply_to(&msg, "pepeKneel".to_string()).await ; //! return Result::Ok("Success".to_string()) ; //! } -//! Result::Err("Not Valid message type".to_string()) +//! Result::Err("Not Valid message type".to_string()) //! } -//! +//! //! /* 4. Set and Store the execution body using `execution_async()` */ //! listener.set_exec_fn(execution_async(execbody)); -//! +//! //! /* 5. Load the listener into the bot */ //! bot.load_listener(listener); //! @@ -220,17 +220,15 @@ //! //! } - - pub mod botcore; pub mod custom_mods; pub use botcore::bot::Bot; -pub use botcore::bot_objects::execution_async; pub use botcore::bot_objects::command_condition_async; -pub use botcore::bot_objects::listener_condition_async; +pub use botcore::bot_objects::execution_async; pub use botcore::bot_objects::listener::Listener; +pub use botcore::bot_objects::listener_condition_async; // pub use crate::botcore::bot_objects::command::Command; pub use botcore::bot_objects::command::Command; -pub use botcore::modules::Module; pub use botcore::bot_objects::Badge; pub use botcore::modules; +pub use botcore::modules::Module; diff --git a/moderator_reactor/src/main.rs b/moderator_reactor/src/main.rs index 5705fbe..284dd0a 100644 --- a/moderator_reactor/src/main.rs +++ b/moderator_reactor/src/main.rs @@ -1,27 +1,25 @@ //! Simple bot with a custom listeners that listens for moderators and respond to the moderator -//! -//! Be sure the followig is defined in `.env` +//! +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> use std::sync::Arc; -use forcebot_core::Bot; use forcebot_core::execution_async; +use forcebot_core::Bot; use forcebot_core::Listener; use twitch_irc::message::ServerMessage; - #[tokio::main] pub async fn main() { - /* Create the bot using env */ let bot = Bot::new().await; @@ -30,26 +28,32 @@ pub async fn main() { /* 2. Set a trigger condition function for listener */ - listener.set_trigger_cond_fn( - |_:Arc<Bot>,message:ServerMessage| - if let ServerMessage::Privmsg(msg) = message { - for badge in msg.badges { - if matches!(badge, x if x.name == "moderator") { - // dbg!("moderator found"); - return true; - } - } - false - } else { false } - ); + listener.set_trigger_cond_fn(|_: Arc<Bot>, message: ServerMessage| { + if let ServerMessage::Privmsg(msg) = message { + for badge in msg.badges { + if matches!(badge, x if x.name == "moderator") { + // dbg!("moderator found"); + return true; + } + } + false + } else { + false + } + }); /* 3. Define an async fn callback execution */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - let _ = bot.chat.lock().await.say_in_reply_to(&msg, "pepeKneel".to_string()).await ; - return Result::Ok("Success".to_string()) ; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, "pepeKneel".to_string()) + .await; + return Result::Ok("Success".to_string()); } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 4. Set and Store the execution body using `execution_async()` */ @@ -60,5 +64,4 @@ pub async fn main() { /* Run the bot */ bot.run().await; - } diff --git a/new_empty_bot/src/main.rs b/new_empty_bot/src/main.rs index a81462e..856f6b1 100644 --- a/new_empty_bot/src/main.rs +++ b/new_empty_bot/src/main.rs @@ -1,12 +1,12 @@ //! Example simple Binary crate that creates & runs bot based on `.env` -//! Be sure the followig is defined in `.env` +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> @@ -14,11 +14,9 @@ use forcebot_core::Bot; #[tokio::main] pub async fn main() { - /* 1. Create the bot using env */ let bot = Bot::new().await; /* 2. Run the bot */ bot.run().await; - } diff --git a/simple_command_bot/src/main.rs b/simple_command_bot/src/main.rs index 418e1eb..c49e55c 100644 --- a/simple_command_bot/src/main.rs +++ b/simple_command_bot/src/main.rs @@ -1,43 +1,46 @@ //! Bot with custom example commands that responds to caller if allowed -//! +//! //! Commands that are passed a blank prefix will use the bot prefix -//! -//! Be sure the followig is defined in `.env` +//! +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> use std::sync::Arc; +use forcebot_core::execution_async; use forcebot_core::Badge; use forcebot_core::Bot; -use forcebot_core::execution_async; use forcebot_core::Command; use twitch_irc::message::ServerMessage; - #[tokio::main] pub async fn main() { - /* Create the bot using env */ let bot = Bot::new().await; /* 1. Create a new blank cmd */ - let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["test".to_string()], "".to_string()); /* 2. Define an async fn callback execution */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - let _ = bot.chat.lock().await.say_in_reply_to(&msg, String::from("test success")).await; - return Result::Ok("Success".to_string()) ; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, String::from("test success")) + .await; + return Result::Ok("Success".to_string()); } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set and Store the execution body using `execution_async()` */ @@ -54,5 +57,4 @@ pub async fn main() { /* Run the bot */ bot.run().await; - } diff --git a/simple_debug_listener/src/main.rs b/simple_debug_listener/src/main.rs index 27ab37e..b6dc626 100644 --- a/simple_debug_listener/src/main.rs +++ b/simple_debug_listener/src/main.rs @@ -1,12 +1,12 @@ //! Example simple Binary crate that creates & runs bot based on `.env` -//! Be sure the followig is defined in `.env` +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> @@ -17,7 +17,6 @@ use twitch_irc::message::ServerMessage; #[tokio::main] pub async fn main() { - /* 1. Create the bot using env */ let bot = Bot::new().await; @@ -25,14 +24,12 @@ pub async fn main() { let mut listener = Listener::new(); /* 2b. Set a trigger condition function for listener */ - listener.set_trigger_cond_fn( - |_:Arc<Bot>,_:ServerMessage| true - ); + listener.set_trigger_cond_fn(|_: Arc<Bot>, _: ServerMessage| true); /* 2c. Define an async fn callback execution */ - async fn execbody(_:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(_: Arc<Bot>, message: ServerMessage) -> Result<String, String> { dbg!(message); /* outputs message to debug */ - Result::Ok("Success".to_string()) + Result::Ok("Success".to_string()) } /* 2d. Set and Store the execution body using `execution_async()` */ @@ -43,5 +40,4 @@ pub async fn main() { /* 4. Run the bot */ bot.run().await; - } diff --git a/simple_module_example/src/main.rs b/simple_module_example/src/main.rs index e588b22..0c07084 100644 --- a/simple_module_example/src/main.rs +++ b/simple_module_example/src/main.rs @@ -1,19 +1,19 @@ //! Simple Module with a Command -//! -//! Adding objects through packages provides controls , +//! +//! Adding objects through packages provides controls , //! such as moderators, and brodcasters can disable or enable mods -//! -//! Here, moderators or above can enable or disable the `test` +//! +//! Here, moderators or above can enable or disable the `test` //! module with the command `<prefix> disable test` -//! -//! Be sure the followig is defined in `.env` +//! +//! Be sure the followig is defined in `.env` //! - login_name //! - access_token //! - bot_channels //! - prefix //! - bot_admins -//! -//! Bot access tokens be generated here - +//! +//! Bot access tokens be generated here - //! - Get a Bot Chat Token here - <https://twitchtokengenerator.com> //! - More Info - <https://dev.twitch.tv/docs/authentication> @@ -21,7 +21,6 @@ use forcebot_core::Bot; #[tokio::main] pub async fn main() { - /* Create the bot using env */ let bot = Bot::new().await; @@ -30,43 +29,41 @@ pub async fn main() { /* Run the bot */ bot.run().await; - } - pub mod custom_mod { use std::sync::Arc; use forcebot_core::{execution_async, Badge, Bot, Command, Module}; use twitch_irc::message::ServerMessage; - /// Module definition with a loaded command pub fn new() -> Module { /* 1. Create a new module */ - let mut custom_mod = Module::new( - vec!["test".to_string()], - "".to_string()); + let mut custom_mod = Module::new(vec!["test".to_string()], "".to_string()); /* 2. Load the cmd into a new module */ custom_mod.load_command(cmd_test()); custom_mod - } - /// Command definition + /// Command definition pub fn cmd_test() -> Command { /* 1. Create a new cmd */ - let mut cmd = Command::new(vec!["test".to_string()],"".to_string()); + let mut cmd = Command::new(vec!["test".to_string()], "".to_string()); /* 2. Define exec callback */ - async fn execbody(bot:Arc<Bot>,message:ServerMessage) -> Result<String,String> { + async fn execbody(bot: Arc<Bot>, message: ServerMessage) -> Result<String, String> { if let ServerMessage::Privmsg(msg) = message { - let _= bot.chat.lock().await.say_in_reply_to( - &msg, "test return".to_string()).await; + let _ = bot + .chat + .lock() + .await + .say_in_reply_to(&msg, "test return".to_string()) + .await; } - Result::Err("Not Valid message type".to_string()) + Result::Err("Not Valid message type".to_string()) } /* 3. Set Command flags */ @@ -76,4 +73,4 @@ pub mod custom_mod { cmd } -} \ No newline at end of file +}