diff --git a/Cargo.lock b/Cargo.lock index 018b9dc..da35376 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,17 @@ dependencies = [ "libc", ] +[[package]] +name = "async-recursion" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-trait" version = "0.1.77" @@ -194,6 +205,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" name = "forcebot_rs" version = "0.1.0" dependencies = [ + "async-recursion", "async-trait", "casual_logger", "chrono", diff --git a/Cargo.toml b/Cargo.toml index f4c7751..f3f7724 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,11 @@ twitch-irc = "5.0.1" rand = { version = "0.8.5", features = [] } futures = "0.3" async-trait = "0.1.77" +async-recursion = "1.1.0" casual_logger = "0.6.5" chrono = "0.4.35" + [lib] name = "bot_lib" path = "src/lib.rs" diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs index 2e6b456..8941654 100644 --- a/src/core/bot_actions.rs +++ b/src/core/bot_actions.rs @@ -1,27 +1,83 @@ + +use twitch_irc::message::PrivmsgMessage; +use std::sync::Arc; +use tokio::sync::RwLock; + +use crate::core::botinstance::BotInstance; + +use super::{botmodules::{BotAction, BotModule}, identity::ChatBadge}; + + +pub type BotAR = Arc>; +pub type ActAR = Arc>; + +#[derive(Clone)] +pub struct ExecBodyParams { + pub bot : BotAR, + pub msg : PrivmsgMessage, + pub parent_act : ActAR , +} + + +impl ExecBodyParams { + + pub async fn get_parent_module(&self) -> Option { + + let parent_act = Arc::clone(&self.parent_act); + let parent_act_lock = parent_act.read().await; + let act = &(*parent_act_lock); + match act { + BotAction::C(c) => { + let temp = c.module.clone(); + Some(temp) + }, + BotAction::L(l) => { + let temp = l.module.clone(); + Some(temp) + }, + _ => None + } + } + + pub fn get_sender(&self) -> String { + self.msg.sender.name.clone() + } + + pub fn get_sender_chatbadge(&self) -> Option { + + let mut requestor_badge_mut: Option = None; + + for b in &self.msg.badges { + if b.name == "moderator" { + requestor_badge_mut = Some(ChatBadge::Mod); + } else if b.name == "broadcaster" { + requestor_badge_mut = Some(ChatBadge::Broadcaster); + } + } + requestor_badge_mut + } + + +} + + + pub mod actions_util { + use super::*; + use std::boxed::Box; use std::future::Future; use std::pin::Pin; - use std::sync::Arc; - - use tokio::sync::{Mutex, RwLock}; - - use twitch_irc::message::PrivmsgMessage; - - use crate::core::botinstance::BotInstance; - - pub type BotAM = Arc>; - pub type BotAR = Arc>; pub type ExecBody = Box< - dyn Fn(BotAR, PrivmsgMessage) -> Pin + Send>> + Send + Sync, + dyn Fn(ExecBodyParams) -> Pin + Send>> + Send + Sync, >; - pub fn asyncbox(f: fn(BotAR, PrivmsgMessage) -> T) -> ExecBody + pub fn asyncbox(f: fn(ExecBodyParams) -> T) -> ExecBody where T: Future + Send + 'static, { - Box::new(move |a, b| Box::pin(f(a, b))) + Box::new(move |a| Box::pin(f(a))) } } diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs index c5b6dca..4bcb352 100644 --- a/src/core/botinstance.rs +++ b/src/core/botinstance.rs @@ -17,9 +17,9 @@ use casual_logger::Log; use crate::core::ratelimiter::RateLimiter; -use crate::core::bot_actions::actions_util::BotAR; +use crate::core::bot_actions::BotAR; use crate::core::botmodules::ModulesManager; -use crate::core::identity::{IdentityManager, Permissible,self}; +use crate::core::identity::{IdentityManager, Permissible}; use crate::core::botlog; use crate::core::chat::Chat; @@ -33,18 +33,11 @@ pub enum ChangeResult { } - #[derive(Debug, PartialEq, Eq, Hash, Clone)] -// pub enum ChType { -// Channel(String), -// } -// -// pub use ChType::Channel; -// -//simplifying from enum to struct pub struct Channel(pub String); +use super::bot_actions::ExecBodyParams; use super::botmodules::StatusType; #[derive(Clone)] @@ -262,16 +255,6 @@ impl BotInstance { // // [ ] #todo Need to run through all Listener Bodies for Enabled Modules for the context of the message (e.g., ModStatus is Enabled in the context for the channel) - let botlock = bot.read().await; - let actsdb = Arc::clone(&botlock.botmodules.botactions); - let actsdblock = actsdb.read().await; - - botlog::debug( - format!("# of BotModules: {}", (*actsdblock).len()).as_str(), - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(msg), - ); - /* [ ] What we should do instead is : @@ -307,9 +290,26 @@ impl BotInstance { }, }; + + let botlock = bot.read().await; + let actsdb = Arc::clone(&botlock.botmodules.botactions); + let actsdblock = actsdb.read().await; + + botlog::debug( + format!("# of BotModules: {}", (*actsdblock).len()).as_str(), + Some("BotInstance > listener_main_prvmsg()".to_string()), + Some(msg), + ); + + for acts in (*actsdblock).values() { + + for a in acts { - match a { + + let act_clone = Arc::clone(a); + + match &(*act_clone.read().await) { crate::core::botmodules::BotAction::C(c) => { /* BotCommand handling - @@ -378,33 +378,51 @@ impl BotInstance { ); - const OF_CMD_CHANNEL:Channel = Channel(String::new()); + let botclone = Arc::clone(&bot); + let botlock = botclone.read().await; + let id = botlock.get_identity(); + let id = Arc::clone(&id); + let idlock = id.read().await; // <-- [ ] 03.24 - seems to work + let user_roles = idlock.getspecialuserroles( + msg.sender.name.clone(), + Some(Channel(msg.channel_login.clone())) + ).await; - let elevated_access = { - let mut idlock = id.write().await; - let (permissability, _) = idlock - .can_user_run_prvmsg(msg, - vec![ - identity::UserRole::BotAdmin, - identity::UserRole::Mod(OF_CMD_CHANNEL), - identity::UserRole::SupMod(OF_CMD_CHANNEL), - identity::UserRole::Broadcaster, - ]) - .await; - - permissability + + botlog::trace( + &format!("For Disabled Command Evaluating User Roles {:?}", user_roles), + Some("BotInstance > listener_main_prvmsg()".to_string()), + Some(msg), + ); + + // Only respond to those with th ebelow User Roles + + let outstr = + format!("sadg Module is disabled : {:?}",a); + + + let params = ExecBodyParams { + bot : Arc::clone(&bot), + msg : (*msg).clone(), + parent_act : Arc::clone(&act_clone), }; - if let Permissible::Allow = elevated_access { - let botlock = bot.read().await; - let outstr = - format!("sadg Module is disabled : {:?}",a); - botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await; - } + // When sending a BotMsgTypeNotif, send_botmsg does Roles related validation as required + + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outstr + ), + params, + ).await; return; }; + botlog::trace( + "ACQUIRING WRITE LOCK : ID", + Some("BotInstance > listener_main_prvmsg()".to_string()), + Some(msg), + ); let eval = { @@ -438,7 +456,21 @@ impl BotInstance { let botlock = bot.read().await; let outstr = "o7 a Mod. I kneel to serve! pepeKneel ".to_string(); - botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await; + + + let params = ExecBodyParams { + bot : Arc::clone(&bot), + msg : (*msg).clone(), + parent_act : Arc::clone(&act_clone), + + }; + + botlock.botmgrs.chat.say_in_reply_to( + msg, + outstr, + // c.module.clone(), + params + ).await; } } @@ -451,12 +483,15 @@ impl BotInstance { ); let a = Arc::clone(&bot); - c.execute(a, msg.clone()).await; + c.execute(ExecBodyParams { + bot : a, + msg : msg.clone() , + parent_act : Arc::clone(&act_clone), + }).await; botlog::trace( "exit out of execution", Some("BotInstance > listener_main_prvmsg()".to_string()), - // Some(&msg), Some(msg), ); } @@ -475,7 +510,6 @@ impl BotInstance { crate::core::botmodules::BotAction::L(l) => { let botlock = bot.read().await; - // let id = botlock.get_identity(); // [x] Check first if the Module for that Given Command is Enabled or Disabled on the given Channel let modmgr = Arc::clone(&botlock.botmodules); @@ -497,7 +531,11 @@ impl BotInstance { } else { let a = Arc::clone(&bot); - l.execute(a, msg.clone()).await; + l.execute(ExecBodyParams { + bot : a, + msg : msg.clone() , + parent_act : Arc::clone(&act_clone), + } ).await; } } diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs index f9d7ff0..25206df 100644 --- a/src/core/botmodules.rs +++ b/src/core/botmodules.rs @@ -24,16 +24,14 @@ use core::panic; use std::collections::HashMap; use std::sync::Arc; -use twitch_irc::message::PrivmsgMessage; - use casual_logger::Log; use tokio::sync::RwLock; use async_trait::async_trait; -use self::bot_actions::actions_util::BotAR; use crate::core::bot_actions::actions_util; +use crate::core::bot_actions::ExecBodyParams; use crate::core::botinstance::{BotInstance, Channel,ChangeResult}; use crate::core::botlog; use crate::core::identity::{self, Permissible,IdentityManager}; @@ -69,7 +67,8 @@ pub async fn init(mgr: Arc) { // 2. Add the BotAction to ModulesManager botc1.add_core_to_modmgr(Arc::clone(&mgr)).await; - async fn cmd_enable(bot: BotAR, msg: PrivmsgMessage) { + // async fn cmd_enable(bot: BotAR, msg: PrivmsgMessage) { + async fn cmd_enable(params : ExecBodyParams) { /* There should be additional validation checks - BotAdmins can only run instance level (-i) enables @@ -102,12 +101,11 @@ pub async fn init(mgr: Arc) { */ - // [x] Unwraps arguments from message let (arg1, arg2) = { - let mut argv = msg.message_text.split(' '); + let mut argv = params.msg.message_text.split(' '); argv.next(); // Skip the command name @@ -133,14 +131,14 @@ pub async fn init(mgr: Arc) { // [x] requestor: String, - let requestor = msg.clone().sender.name; + let requestor = params.msg.clone().sender.name; // [x] requestor_badge: Option, let mut requestor_badge_mut: Option = None; - for b in &msg.badges { + for b in ¶ms.msg.badges { if b.name == "moderator" { requestor_badge_mut = Some(ChatBadge::Mod); } else if b.name == "broadcaster" { @@ -160,21 +158,28 @@ pub async fn init(mgr: Arc) { // if let None = trg_module { if trg_module.is_none() { - let botlock = bot.read().await; + // let botlock = params.bot.read().await; let outmsg = "uuh You need to pass a module"; botlog::debug( outmsg, Some("botmodules.rs > cmd_enable()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + + // We should call a notification around here + + let bot = params.clone().bot; + + let botclone = Arc::clone(&bot); + let botlock = botclone.read().await; + + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outmsg.to_string() + ), + params.clone(), + ).await; return; @@ -183,22 +188,19 @@ pub async fn init(mgr: Arc) { // [x] trg_level: StatusLvl, - let currchnl = msg.channel_login.to_lowercase(); + let currchnl = params.msg.channel_login.to_lowercase(); let trg_level = if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } - // else if arg1 == Some("-f") { StatusLvl::Instance } else { StatusLvl::Ch(Channel(currchnl)) } ; - let botlock = bot.read().await; + let botlock = params.bot.read().await; let modmgr = Arc::clone(&botlock.botmodules); let id = botlock.get_identity(); - - // modmgr.exec_enable(requestor, requestor_badge, trg_module, trg_level, id) let rslt = modmgr.exec_enable( requestor, requestor_badge, @@ -206,6 +208,9 @@ pub async fn init(mgr: Arc) { trg_level, id).await; + + // We should call a notification around here + let outmsg = match rslt.clone() { ChangeResult::Failed(a) => format!("Stare Failed : {}",a), @@ -213,12 +218,13 @@ pub async fn init(mgr: Arc) { ChangeResult::Success(a) => format!("YAAY Success : {}",a), }; - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outmsg.to_string() + ), + params.clone(), + ).await; + } @@ -243,7 +249,8 @@ pub async fn init(mgr: Arc) { // 2. Add the BotAction to ModulesManager botc1.add_core_to_modmgr(Arc::clone(&mgr)).await; - async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) { + // async fn cmd_disable(bot: BotAR, msg: PrivmsgMessage) { + async fn cmd_disable(params : ExecBodyParams) { /* There should be additional validation checks - BotAdmins can only run instance level (-i) disables and (-f) force disable @@ -279,11 +286,11 @@ pub async fn init(mgr: Arc) { */ - // [x] Unwraps arguments from message + // [x] Unwraps arguments from message let (arg1, arg2) = { - let mut argv = msg.message_text.split(' '); + let mut argv = params.msg.message_text.split(' '); argv.next(); // Skip the command name @@ -311,14 +318,14 @@ pub async fn init(mgr: Arc) { // [x] requestor: String, - let requestor = msg.clone().sender.name; + let requestor = params.msg.clone().sender.name; // [x] requestor_badge: Option, let mut requestor_badge_mut: Option = None; - for b in &msg.badges { + for b in ¶ms.msg.badges { if b.name == "moderator" { requestor_badge_mut = Some(ChatBadge::Mod); } else if b.name == "broadcaster" { @@ -334,24 +341,25 @@ pub async fn init(mgr: Arc) { let trg_module = if (arg1 == Some("-i")) || (arg1 == Some("-f")) { arg2 } else { arg1 }; // if no trg_module was passed - // if let None = trg_module { if trg_module.is_none() { - let botlock = bot.read().await; + let botlock = params.bot.read().await; let outmsg = "uuh You need to pass a module"; botlog::debug( outmsg, Some("botmodules.rs > cmd_disable()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + + // We should call a notification around here + + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outmsg.to_string() + ), + params.clone(), + ).await; return; @@ -361,7 +369,7 @@ pub async fn init(mgr: Arc) { // [x] trg_level: StatusLvl, - let currchnl = msg.channel_login.to_lowercase(); + let currchnl = params.msg.channel_login.to_lowercase(); let trg_level = if arg1 == Some("-i") || arg1 == Some("-f") { StatusLvl::Instance } @@ -371,13 +379,12 @@ pub async fn init(mgr: Arc) { - let botlock = bot.read().await; + let botlock = params.bot.read().await; let modmgr = Arc::clone(&botlock.botmodules); let id = botlock.get_identity(); let force = arg1 == Some("-f"); - // modmgr.exec_enable(requestor, requestor_badge, trg_module, trg_level, id) let rslt = modmgr.exec_disable( requestor, requestor_badge, @@ -393,13 +400,13 @@ pub async fn init(mgr: Arc) { ChangeResult::Success(a) => format!("YAAY Success : {}",a), }; - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; - + // We should call a notification around here + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outmsg.to_string() + ), + params.clone(), + ).await; } @@ -409,13 +416,8 @@ pub async fn init(mgr: Arc) { #[derive(Debug, Clone)] -// pub enum BotModule { -// BotModule(String), -// } - pub struct BotModule(pub String); - impl PartialEq for BotModule { fn eq(&self, other: &Self) -> bool { let BotModule(name1) = self.clone(); @@ -427,8 +429,6 @@ impl Eq for BotModule {} impl Hash for BotModule{ fn hash(&self, state: &mut H) { - // self.id.hash(state); - // self.phone.hash(state); let BotModule(name) = self.clone(); name.to_lowercase().hash(state); } @@ -460,10 +460,10 @@ pub enum BotAction { } impl BotAction { - pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) { + pub async fn execute(&self, params : ExecBodyParams) { match self { - BotAction::L(a) => a.execute(m, n).await, - BotAction::C(a) => a.execute(m, n).await, + BotAction::L(a) => a.execute(params).await, + BotAction::C(a) => a.execute(params).await, _ => (), } } @@ -487,8 +487,8 @@ pub struct BotCommand { } impl BotCommand { - pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) { - (*self.exec_body)(m, n).await; + pub async fn execute(&self, params : ExecBodyParams) { + (*self.exec_body)(params).await; } } @@ -523,8 +523,8 @@ pub struct Listener { } impl Listener { - pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) { - (self.exec_body)(m, n).await; + pub async fn execute(&self, params : ExecBodyParams) { + (self.exec_body)(params).await; } } @@ -566,10 +566,11 @@ impl BotActionTrait for Listener { pub struct Routine {} type StatusdbEntry = (ModGroup, Vec); +type ModuleActions = Vec>>; pub struct ModulesManager { statusdb: Arc>>, - pub botactions: Arc>>>, + pub botactions: Arc>>, } /* @@ -647,7 +648,6 @@ impl ModulesManager { let dbt = self.statusdb.read().await; - // let a = dbt.entry(in_module.clone()).; let (mgrp,statusvector) = dbt.get(&in_module).unwrap(); match mgrp { @@ -759,6 +759,12 @@ impl ModulesManager { return ChangeResult::Failed("Module doesn't exist".to_string()); } + botlog::trace( + "ACQUIRING WRITE LOCK : ID", + Some("ModulesManager > Exec_enable".to_string()), + None, + ); + let mut idlock = id.write().await; @@ -941,6 +947,13 @@ impl ModulesManager { return ChangeResult::Failed("Module doesn't exist".to_string()); } + botlog::trace( + "ACQUIRING WRITE LOCK : ID", + Some("ModulesManager > Exec_disable".to_string()), + None, + ); + + let mut idlock = id.write().await; @@ -1113,7 +1126,6 @@ impl ModulesManager { }, } - // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string())) } pub async fn force_disable(&self, in_module: BotModule) -> (StatusType,ChangeResult) { @@ -1157,7 +1169,6 @@ impl ModulesManager { }, } - // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string())) } pub async fn set_instance_enabled(&self, in_module: BotModule) -> (StatusType,ChangeResult) { @@ -1192,7 +1203,6 @@ impl ModulesManager { }, } - // (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string())) } pub async fn set_ch_disabled(&self, in_module: BotModule , in_chnl: Channel) -> (StatusType,ChangeResult) { @@ -1230,7 +1240,6 @@ impl ModulesManager { }, } - // (StatusType::Disabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string())) } pub async fn set_ch_enabled(&self, in_module: BotModule , in_chnl: Channel) -> (StatusType,ChangeResult) { @@ -1268,7 +1277,6 @@ impl ModulesManager { } - // (StatusType::Enabled(StatusLvl::Instance),ChangeResult::NoChange("Nothing needed".to_string())) } @@ -1322,12 +1330,20 @@ impl ModulesManager { // Check All Other BotAction Command Names & Aliases to ensure they don't conflict async fn find_conflict_module(mgr: &ModulesManager, act: &BotAction) -> Option { + if let BotAction::C(incmd) = act { let actdb = mgr.botactions.read().await; for (module, moduleactions) in &(*actdb) { - for modact in moduleactions.iter() { - if let BotAction::C(dbcmd) = &modact { + + + // for modact in moduleactions.iter() { + for modact_prelock in moduleactions.iter() { + + let modact = modact_prelock.read().await; + + // if let BotAction::C(dbcmd) = &modact { + if let BotAction::C(dbcmd) = &(*modact) { // At this point, there is an command incmd and looked up dbcmd // [x] check if given botcommand c.command:String conflicts with any in botactions @@ -1383,7 +1399,7 @@ impl ModulesManager { let mut a = self.botactions.write().await; let modactions = a.entry(in_module.clone()).or_insert(Vec::new()); - modactions.push(in_action); + modactions.push(Arc::new(RwLock::new(in_action))); botlog::trace( format!( diff --git a/src/core/chat.rs b/src/core/chat.rs index 1ba85e7..27d36e3 100644 --- a/src/core/chat.rs +++ b/src/core/chat.rs @@ -21,6 +21,12 @@ use crate::core::botlog; use tokio::time::{sleep, Duration}; +use super::bot_actions::ExecBodyParams; +use super::identity; + + +use async_recursion::async_recursion; + #[derive(Clone)] pub struct Chat { pub ratelimiters: Arc>>, // used to limit messages sent per channel @@ -28,10 +34,11 @@ pub struct Chat { } -#[derive(Clone)] -enum BotMsgType<'a> { +#[derive(Clone,Debug)] +pub enum BotMsgType<'a> { SayInReplyTo(&'a PrivmsgMessage,String), Say(String,String), + Notif(String), // For Bot Sent Notifications } @@ -51,11 +58,12 @@ impl Chat { self.ratelimiters.lock().await.insert(chnl, n); } + #[async_recursion] + pub async fn send_botmsg(&self, msginput: BotMsgType<'async_recursion>, params : ExecBodyParams) { - - - async fn send_botmsg(&self, msginput: BotMsgType<'_>) { - /* + + + /* formats message before sending to TwitchIRC - [x] Custom String Formatting (e.g., adding random black spaces) @@ -64,6 +72,14 @@ impl Chat { */ + + botlog::trace( + format!("send_bot_msg params : {:?}",msginput).as_str(), + Some("chat.rs > send_botmsg ".to_string()), + Some(¶ms.msg), + ); + Log::flush(); + let (channel_login,mut outmsg) = match msginput.clone() { BotMsgType::SayInReplyTo(msg, outmsg) => { (msg.channel_login.clone(),outmsg) @@ -71,19 +87,227 @@ impl Chat { BotMsgType::Say(a,b ) => { (a.clone(),b.clone()) }, + BotMsgType::Notif(outmsg) => { + (params.msg.channel_login.clone(),outmsg) + } }; - if self.client.get_channel_status(channel_login.clone()).await == (false,false) { - // in the case where the provided channel isn't something we're known to be connected to + + + botlog::trace( + "BEFORE parent_module call", + Some("chat.rs > send_botmsg ".to_string()), + Some(¶ms.msg), + ); + + let parent_module = params.get_parent_module().await; + + let params_clone = params.clone(); + let botclone = Arc::clone(¶ms_clone.bot); + let botlock = botclone.read().await; + let modmgr = Arc::clone(&botlock.botmodules); + let modstatus = (*modmgr).modstatus( + parent_module.clone().expect("ERROR - Expected a module"), + Channel(channel_login.clone()) + ).await; + + if !params.bot.read().await.bot_channels.contains(&Channel(channel_login.clone())) { botlog::warn( &format!("A message attempted to send for a Non-Joined Channel : {}",channel_login.clone()), Some("Chat > send_botmsg".to_string()), None, ); + + if let BotMsgType::SayInReplyTo(_prvmsg,_outmsg) = msginput { + + self.send_botmsg(BotMsgType::Notif( + "uuh Bot can't send to a channel it isn't joined".to_string(), + ), + params).await; + + } + return ; } + /* + [x] !! => 03.24 - Somewhere around here, we should be validating module for target channel + */ + + + /* + - Use ModulesManager.modstatus + + modstatus(&self, in_module: BotModule, in_chnl: Channel) -> StatusType + + */ + + botlog::trace( + format!("BEFORE modstatus check : modstatus = {:?}",modstatus).as_str(), + Some("chat.rs > send_botmsg ".to_string()), + Some(¶ms.msg), + ); + + + + if let super::botmodules::StatusType::Disabled(lvl) = modstatus { + // Note : At this point, chat was called in a channel where the parent module IS enabled + // - this type of validation is done outside of Chat() + // This though takes into account scenarios where we are targetting a different channel + + + botlog::trace( + "BEFORE msginput check", + Some("chat.rs > send_botmsg ".to_string()), + Some(¶ms.msg), + ); + + Log::flush(); + + match msginput { + BotMsgType::Notif(_) => (), // Do nothing with Notif > We'll validate the user later to handle + BotMsgType::SayInReplyTo(_, _) | BotMsgType::Say(_,_) => { + + botlog::trace( + "BEFORE potential Async recursion", + Some("chat.rs > send_botmsg ".to_string()), + Some(¶ms.clone().msg), + ); + + Log::flush(); + + + self.send_botmsg(BotMsgType::Notif( + format!("uuh {:?} is disabled on {} : {:?}", + parent_module.clone().unwrap(), + channel_login.clone(), + lvl + ), + ), params.clone() + ).await; + + + botlog::trace( + "AFTER potential Async recursion", + Some("chat.rs > send_botmsg ".to_string()), + Some(¶ms.msg), + ); + + + Log::flush(); + + return + }, + + } + + } + + + /* + + [x] !! => 03.24 - Would be nice if around here , validate the user has at least some special roles in target channel + - NOTE : If these need to be refined, they can be by the custom module developer at the parent calling function of say() + - This just prevents Chat from being triggered in a channel where the sending chatter does not have any special roles + + */ + + + + /* + + Use + pub async fn getspecialuserroles( + &self, + chattername: String, + channel: Option, + ) -> Vec { + + */ + + // let params_clone = params.clone(); + + let botclone = Arc::clone(¶ms.bot); + let botlock = botclone.read().await; + let id = botlock.get_identity(); + let id = Arc::clone(&id); + let idlock = id.read().await; // <-- [x] 03.24 - seems to work + let user_roles = idlock.getspecialuserroles( + params.get_sender(), + Some(Channel(channel_login.clone())) + ).await; + + botlog::trace( + format!("BEFORE user roles check check : userroles = {:?}",user_roles).as_str(), + Some("chat.rs > send_botmsg ".to_string()), + Some(¶ms.msg), + ); + + Log::flush(); + + // [x] If user has any of the following target roles, they will be allowed - otherwise, they will not be allowed to send + // - Otherwise if not (checked here) , this will not run + // - NOTE : For now, I've removed BotAdmin just for curiosity - BotAdmins can always elevate themselves if they want + + if !(user_roles.contains(&identity::UserRole::Mod(Channel(channel_login.clone()))) + || user_roles.contains(&identity::UserRole::SupMod(Channel(channel_login.clone()))) + || user_roles.contains(&identity::UserRole::Broadcaster) + ) + { + + + match msginput { + BotMsgType::Notif(_) => { + // If Sender is Not a BotAdmin, don't do anything about the notification and return + if !user_roles.contains(&identity::UserRole::BotAdmin) { + return; + } + }, + BotMsgType::SayInReplyTo(_,_ ) | BotMsgType::Say(_,_) => { + // If the BotMsg a Say/SayInReplyTo (from Developer or Chatter) , and the Sender does not have Specific Roles in the Source Channel Sent + + self.send_botmsg(BotMsgType::Notif( + format!("uuh You do not have the right roles to send to {}", + channel_login.clone(), + ), + ), params.clone() + ).await; + + return; + + }, + }; + + + + } + + + /* + At this stage from the above Validations : + msginput would be : + a. BotMsgType::SayInReplyTo | BotMsgType::Say that is + - Towards a Destination Channel that the Sender has Elevated User Roles to Send to + b. BotMsgType::Notif that is + - Going to be sent to the Source Channel (rather than the original say/sayinreplyto was towards) + - A Sender that has Elevated User Roles in Source Channel will see a message ; otherwise, they will not + */ + + /* + + Use the following + + pub async fn can_user_run( + &mut self, + usr: String, + channelname: Channel, + chat_badge: Option, + cmdreqroles: Vec, // ) -> Result> { + ) -> (Permissible, ChangeResult) { + + */ + let rl = Arc::clone(&self.ratelimiters); let mut rllock = rl.lock().await; @@ -119,6 +343,9 @@ impl Chat { BotMsgType::Say(a, _) => { self.client.say(a, outmsg).await.unwrap(); } + BotMsgType::Notif(outmsg) => { + self.client.say_in_reply_to(¶ms.msg, outmsg).await.unwrap(); + } } contextratelimiter.increment_counter(); @@ -159,16 +386,70 @@ impl Chat { - pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) { + // pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String) { + // #[async_recursion] + pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, outmsg: String , params : ExecBodyParams) { - self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg)).await; + // let params_clone = params.clone(); + + // let botclone = Arc::clone(¶ms_clone.bot); + // let botlock = botclone.read().await; + // let id = botlock.get_identity(); + // let id = Arc::clone(&id); + + // // botlog::trace( + // // "ACQUIRING WRITE LOCK : ID", + // // Some("Chat > send_botmsg".to_string()), + // // Some(¶ms.msg), + // // ); + // // Log::flush(); + + // botlog::trace( + // "ACQUIRING READ LOCK : ID", + // Some("Chat > send_botmsg".to_string()), + // Some(¶ms.msg), + // ); + // Log::flush(); + + + // // let idlock = id.write().await; // <-- [ ] 03.24 - This is definitely locking it + // let idlock = id.read().await; // <-- [ ] 03.24 - seems to work + // let a = idlock.getspecialuserroles(params.get_sender(), Some(Channel(msg.channel_login.clone()))).await; + // botlog::trace( + // format!("GETSPECIALUSERROLES RESULT : {:?}",a).as_str(), + // Some("Chat > send_botmsg".to_string()), + // Some(¶ms.msg), + // ); + // Log::flush(); + + + + // // botlog::trace( + // // "ACQUIRED WRITE LOCK : ID", + // // Some("Chat > send_botmsg".to_string()), + // // Some(¶ms.msg), + // // ); + // // Log::flush(); + + + + // botlog::trace( + // "ACQUIRED READ LOCK : ID", + // Some("Chat > send_botmsg".to_string()), + // Some(¶ms.msg), + // ); + // Log::flush(); + + + self.send_botmsg(BotMsgType::SayInReplyTo(msg, outmsg) , params).await; } - pub async fn say(&self, channel_login: String, message: String) { + // pub async fn say(&self, channel_login: String, message: String) { + pub async fn say(&self, channel_login: String, message: String , params : ExecBodyParams) { // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say - self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message)).await; + self.send_botmsg(BotMsgType::Say(channel_login.to_lowercase(), message), params).await; } async fn _me(&self, _: String, _: String) { diff --git a/src/core/identity.rs b/src/core/identity.rs index e816e9f..2fbf56e 100644 --- a/src/core/identity.rs +++ b/src/core/identity.rs @@ -7,7 +7,8 @@ use twitch_irc::message::PrivmsgMessage; use casual_logger::Log; -use crate::core::bot_actions::actions_util::{self, BotAR}; +use crate::core::bot_actions::actions_util; +use crate::core::bot_actions::ExecBodyParams; use crate::core::botinstance::{Channel,ChangeResult}; use crate::core::botlog; use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager}; @@ -67,14 +68,13 @@ pub async fn init(mgr: Arc) { ], }; - // tempb.add_to_modmgr(Arc::clone(&mgr)).await; tempb.add_core_to_modmgr(Arc::clone(&mgr)).await; - async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) { + async fn cmd_promote(params : ExecBodyParams) { botlog::trace( "Called cmd promote", Some("identity.rs > cmd_prommote()".to_string()), - Some(&msg), + Some(¶ms.msg), ); // -- If the BotCommand.command was called (e.g., promote) & required roles were validated OUTSIDE of this call @@ -103,16 +103,16 @@ pub async fn init(mgr: Arc) { */ - // println!("{}",msg.message_text); + // println!("{}",params.msg.message_text); botlog::trace( - format!("Twich Message > {}", msg.message_text).as_str(), + format!("Twich Message > {}", params.msg.message_text).as_str(), Some("identity.rs > cmd_promote()".to_string()), None, ); - let sendername = msg.clone().sender.name; + let sendername = params.msg.clone().sender.name; - let mut argv = msg.message_text.split(' '); + let mut argv = params.msg.message_text.split(' '); argv.next(); // Skip the command name @@ -122,7 +122,7 @@ pub async fn init(mgr: Arc) { let mut sender_badge: Option = None; - for b in &msg.badges { + for b in ¶ms.msg.badges { if b.name == "moderator" { sender_badge = Some(ChatBadge::Mod); } else if b.name == "broadcaster" { @@ -130,7 +130,7 @@ pub async fn init(mgr: Arc) { } } - let targetchnl = msg.channel_login.to_lowercase(); + let targetchnl = params.msg.channel_login.to_lowercase(); /* @@ -148,7 +148,7 @@ pub async fn init(mgr: Arc) { // [x] Get a required lock first - let botlock = bot.read().await; + let botlock = params.bot.read().await; let id = botlock.get_identity(); let idlock = id.read().await; @@ -180,7 +180,6 @@ pub async fn init(mgr: Arc) { None => { botlog::debug( - // &format!("No Targer User argument"), "No Targer User argument", Some("identity.rs > cmd_demote()".to_string()), None, @@ -208,17 +207,19 @@ pub async fn init(mgr: Arc) { botlog::debug( outmsg.as_str(), Some("identity.rs > cmd_prommote()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + // We should call a notification around here + + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outmsg.to_string() + ), + params.clone(), + ).await; + botlog::trace( - // &format!("End of cmd_promote()"), "End of cmd_promote()", Some("identity.rs > cmd_prommote()".to_string()), None, @@ -239,15 +240,13 @@ pub async fn init(mgr: Arc) { ], }; - // tempb.add_to_modmgr(Arc::clone(&mgr)).await; - // add_core_to_modmgr tempb.add_core_to_modmgr(Arc::clone(&mgr)).await; - async fn cmd_demote(bot: BotAR, msg: PrivmsgMessage) { + async fn cmd_demote(params : ExecBodyParams) { botlog::debug( "Called cmd demote", Some("identity.rs > cmd_demote()".to_string()), - Some(&msg), + Some(¶ms.msg), ); Log::flush(); @@ -280,7 +279,7 @@ pub async fn init(mgr: Arc) { // [x] Unwraps arguments from message let (arg1, _arg2) = { - let mut argv = msg.message_text.split(' '); + let mut argv = params.msg.message_text.split(' '); argv.next(); // Skip the command name @@ -319,11 +318,11 @@ pub async fn init(mgr: Arc) { */ - let sendername = msg.clone().sender.name; + let sendername = params.msg.clone().sender.name; let mut sender_badge_mut: Option = None; - for b in &msg.badges { + for b in ¶ms.msg.badges { if b.name == "moderator" { sender_badge_mut = Some(ChatBadge::Mod); } else if b.name == "broadcaster" { @@ -335,7 +334,7 @@ pub async fn init(mgr: Arc) { let targetusr = arg1; - let targetchnl = msg.channel_login.to_lowercase(); + let targetchnl = params.msg.channel_login.to_lowercase(); /* @@ -349,14 +348,13 @@ pub async fn init(mgr: Arc) { // [x] Get a required lock first - let botlock = bot.read().await; + let botlock = params.bot.read().await; let id = botlock.get_identity(); let idlock = id.read().await; let rslt = match targetusr { Some(targetusr) => { botlog::debug( - // &format!("running demote()"), "running demote()", Some("identity.rs > cmd_demote()".to_string()), None, @@ -375,7 +373,6 @@ pub async fn init(mgr: Arc) { None => { botlog::debug( - // &format!("No Targer User argument"), "No Targer User argument", Some("identity.rs > cmd_demote()".to_string()), None, @@ -407,14 +404,16 @@ pub async fn init(mgr: Arc) { botlog::debug( outmsg.as_str(), Some("identity.rs > cmd_demote()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outmsg.to_string() + ), + params.clone(), + ).await; + + } let tempcomm = BotCommand { @@ -431,15 +430,13 @@ pub async fn init(mgr: Arc) { ], }; - // tempcomm.add_to_modmgr(Arc::clone(&mgr)).await; - // add_core_to_modmgr tempcomm.add_core_to_modmgr(Arc::clone(&mgr)).await; - async fn getroles(bot: BotAR, msg: PrivmsgMessage) { + async fn getroles(params : ExecBodyParams) { botlog::debug( "Called cmd getroles", Some("identity.rs > cmd_getroles()".to_string()), - Some(&msg), + Some(¶ms.msg), ); /* @@ -450,7 +447,8 @@ pub async fn init(mgr: Arc) { */ - let mut argv = msg.message_text.split(' '); + + let mut argv = params.msg.message_text.split(' '); argv.next(); // Skip the command name @@ -465,7 +463,7 @@ pub async fn init(mgr: Arc) { let targetchnl = arg2; - let botlock = bot.read().await; + let botlock = params.bot.read().await; let id = botlock.get_identity(); @@ -477,7 +475,7 @@ pub async fn init(mgr: Arc) { idlock .getspecialuserroles( String::from(targetuser), - Some(Channel(msg.channel_login.to_lowercase())), + Some(Channel(params.msg.channel_login.to_lowercase())), ) .await } @@ -485,7 +483,7 @@ pub async fn init(mgr: Arc) { // [x] gets special roles for caller let callersproles = idlock .getspecialuserroles( - msg.sender.name.to_lowercase(), + params.msg.sender.name.to_lowercase(), Some(Channel(targetchnl.to_lowercase().to_string())), ) .await; @@ -507,7 +505,7 @@ pub async fn init(mgr: Arc) { idlock .getspecialuserroles( String::from(targetuser), - Some(Channel(msg.channel_login.to_lowercase())), + Some(Channel(params.msg.channel_login.to_lowercase())), ) .await } @@ -517,17 +515,16 @@ pub async fn init(mgr: Arc) { botlog::debug( &format!("User roles of Target Chatter >> {:?}", sproles), Some("identity.rs > init > getroles()".to_string()), - Some(&msg), + Some(¶ms.msg), ); botlog::trace( - // &format!("Evaluating special roles"), "Evaluating special roles", Some("identity.rs > init > getroles()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - let outmsg = if ((targetuser.to_lowercase() == msg.channel_login.to_lowercase()) + let outmsg = if ((targetuser.to_lowercase() == params.msg.channel_login.to_lowercase()) && arg2.is_none()) || (arg2.is_some() && arg2.unwrap() == targetuser.to_lowercase()) { @@ -536,18 +533,18 @@ pub async fn init(mgr: Arc) { let mut outmsg = "FeelsWowMan they're the broadcaster. ".to_string(); if sproles.contains(&UserRole::Mod(Channel( - msg.channel_login.to_lowercase(), + params.msg.channel_login.to_lowercase(), ))) || sproles.contains(&UserRole::SupMod(Channel( - msg.channel_login.to_lowercase(), + params.msg.channel_login.to_lowercase(), ))) || sproles.contains(&UserRole::BotAdmin) { outmsg += format!("Target chatter's user roles are : {:?}", sproles).as_str(); } outmsg } else if sproles.contains(&UserRole::Mod(Channel( - msg.channel_login.to_lowercase(), + params.msg.channel_login.to_lowercase(), ))) || sproles.contains(&UserRole::SupMod(Channel( - msg.channel_login.to_lowercase(), + params.msg.channel_login.to_lowercase(), ))) || sproles.contains(&UserRole::BotAdmin) { format!("Target chatter's user roles are : {:?}", sproles) @@ -558,10 +555,15 @@ pub async fn init(mgr: Arc) { botlog::debug( format!("Chat Say Reply message : {}", outmsg).as_str(), Some("identity.rs > init > getroles()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).await; + botlock.botmgrs.chat.send_botmsg(super::chat::BotMsgType::Notif( + outmsg.to_string() + ), + params.clone(), + ).await; + // [ ] NOTE : After the above, I should receive only the roles in the context of the current channel I received this ideally and maybe BotAdmin ; not outside } @@ -608,13 +610,6 @@ pub enum ChatBadge { Mod, } -// #[derive(Debug, PartialEq, Eq)] -// pub enum ChangeResult { -// Success(String), -// Failed(String), -// NoChange(String), -// } - impl IdentityManager { pub fn init() -> IdentityManager { let mut a = HashMap::new(); @@ -682,7 +677,6 @@ impl IdentityManager { botlog::trace( "Checking within PRVMSG", Some("identity.rs > can_user_run_PRVMSG()".to_string()), - // Some(&msg), Some(msg), ); @@ -698,7 +692,6 @@ impl IdentityManager { self.can_user_run( msg.sender.name.to_owned(), - // Channel::construct(msg.channel_login.to_owned()), Channel(msg.channel_login.to_owned()), sender_badge, cmdreqroles, @@ -714,7 +707,6 @@ impl IdentityManager { chat_badge: Option, cmdreqroles: Vec, // ) -> Result> { ) -> (Permissible, ChangeResult) { - // println!{"Checking within can_user_run()"}; botlog::debug( &format!( "Checking within can_user_run() : @@ -761,8 +753,6 @@ impl IdentityManager { // [x] If cmdreqroles is empty vector , automatically assume Ok(Permissible::Allow) - // let idar = Arc::new(RwLock::new(self)); - let usr = usr.to_lowercase(); @@ -783,9 +773,7 @@ impl IdentityManager { ); } - // if cmdreqroles.len() == 0 { if cmdreqroles.is_empty() { - // return Ok(Permissible::Allow) return ( Permissible::Allow, ChangeResult::NoChange("Command has no required cmdreqroles".to_string()), @@ -799,10 +787,6 @@ impl IdentityManager { // [x] and cmdreqroles includes UserRole::Broadcaster , Ok(Permissible::Allow) // [x] and cmdreqroles includes UserRole::Mod("") OR UserRole::SupMod("") , Ok(Permissible::Allow) Some(ChatBadge::Broadcaster) => { - // if cmdreqroles.contains(&UserRole::Broadcaster) - // || cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new()))) - // || cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new()))) - // { if cmdreqroles.contains(&UserRole::Broadcaster) || cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) || cmdreqroles.contains(&UserRole::SupMod(Channel(String::new()))) @@ -874,7 +858,6 @@ impl IdentityManager { None, ); - // if cmdreqroles.contains(&UserRole::Mod(Channel::construct(String::new()))) { if cmdreqroles.contains(&UserRole::Mod(Channel(String::new()))) { botlog::trace( "Command requires Mod Role", @@ -911,7 +894,6 @@ impl IdentityManager { // [x] If cmdreqroles includes UserRole::SupMod("") , checks if chatter has UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) - // if cmdreqroles.contains(&UserRole::SupMod(Channel::construct(String::new()))) { if cmdreqroles.contains(&UserRole::SupMod(Channel(String::new()))) { if let Some(a) = self .special_roles_users @@ -1456,7 +1438,6 @@ mod core_identity { let test_id_mgr = IdentityManager::init(); // [x] Broadcaster Promotes Chatter to SupMod - // let channel = Some(Channel::construct("broadcasterer".to_string())); let channel = Some(Channel("broadcasterer".to_string())); let trgchatter = "regularChatter".to_string(); let authorizer_badge = &Some(ChatBadge::Broadcaster); @@ -1536,7 +1517,6 @@ mod core_identity { let broadcaster = "broadcasterer".to_string(); let broadcaster_badge = &Some(ChatBadge::Broadcaster); - // let channel = Some(ChType::Channel(broadcaster.clone())); let channel = Channel(broadcaster.clone()); let supchatter = "superModerator".to_string(); let trg_role = None; @@ -1579,7 +1559,6 @@ mod core_identity { // [x] SupMod Attempts to Promote Chatter to SupMod - // let broadcaster = "broadcasterer".to_string(); let authorizer = supchatter; let authorizer_badge = &Some(ChatBadge::Broadcaster); let channel = Some(Channel(broadcaster.clone())); @@ -1650,7 +1629,6 @@ mod core_identity { // [x] SupMod Attempts to Promote Chatter to SupMod - // let broadcaster = "broadcasterer".to_string(); let authorizer = botadmin; let authorizer_badge = botadmin_badge; let channel = Some(Channel("somechannel".to_string())); diff --git a/src/custom/experimental/experiment001.rs b/src/custom/experimental/experiment001.rs index f83693a..58d0c59 100644 --- a/src/custom/experimental/experiment001.rs +++ b/src/custom/experimental/experiment001.rs @@ -13,13 +13,11 @@ use rand::Rng; use std::sync::Arc; -use twitch_irc::message::PrivmsgMessage; - -// use crate::core::botinstance::ChType::Channel; +use crate::core::bot_actions::ExecBodyParams; use crate::core::botinstance::Channel; use crate::core::botlog; -use crate::core::bot_actions::actions_util::{self, BotAR}; +use crate::core::bot_actions::actions_util; use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager}; use crate::core::identity::UserRole::*; @@ -59,18 +57,6 @@ pub async fn init(mgr: Arc) { // 2. Add the BotAction to ModulesManager list1.add_to_modmgr(Arc::clone(&mgr)).await; - - // // 1. Define the BotAction - // let list1 = Listener { - // module: BotModule(String::from("experiments001")), - // name: String::from("babygirl Listener"), - // exec_body: actions_util::asyncbox(babygirl), - // help: String::from(""), - // }; - - // // 2. Add the BotAction to ModulesManager - // list1.add_to_modmgr(Arc::clone(&mgr)).await; - // 1. Define the BotAction let botc1 = BotCommand { module: BotModule(String::from("experiments001")), @@ -109,73 +95,84 @@ pub async fn init(mgr: Arc) { } -async fn good_girl(bot: BotAR, msg: PrivmsgMessage) { +async fn good_girl(params : ExecBodyParams) { + // [ ] Uses gen_ratio() to output bool based on a ratio probability . // - For example gen_ratio(2,3) is 2 out of 3 or 0.67% (numerator,denomitator) // - More Info : https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_ratio - if msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase() - || msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase() - // if msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase() + if params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase() + || params.msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase() { botlog::debug( "Good Girl Detected > Pausechamp", Some("experiments > goodgirl()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - let rollwin = rand::thread_rng().gen_ratio(1, 1); + let rollwin = rand::thread_rng().gen_ratio(1, 10); if rollwin { botlog::debug( "Oh that's a good girl!", Some("experiments > goodgirl()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - let bot = Arc::clone(&bot); + let bot = Arc::clone(¶ms.bot); + let botlock = bot.read().await; // uses chat.say_in_reply_to() for the bot controls for messages botlock - .botmgrs - .chat - .say_in_reply_to(&msg, String::from("GoodGirl xdd ")) - .await; + .botmgrs + .chat + .say_in_reply_to( + ¶ms.msg, + String::from("GoodGirl xdd "), + params.clone() + ).await; + + } } } -async fn testy(mut _chat: BotAR, msg: PrivmsgMessage) { +async fn testy(params : ExecBodyParams) { println!("testy triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call botlog::debug( "testy triggered!", Some("experiments > testy()".to_string()), - Some(&msg), + Some(¶ms.msg), ); } -async fn babygirl(bot: BotAR, msg: PrivmsgMessage) { +async fn babygirl(params : ExecBodyParams) { + + println!("babygirl triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call botlog::debug( "babygirl triggered!", Some("experiments > babygirl()".to_string()), - Some(&msg), + Some(¶ms.msg), ); - let bot = Arc::clone(&bot); + let bot = Arc::clone(¶ms.bot); let botlock = bot.read().await; - // uses chat.say_in_reply_to() for the bot controls for messages + botlock .botmgrs .chat - .say_in_reply_to(&msg, String::from("16:13 notohh: cafdk")) - .await; + .say_in_reply_to( + ¶ms.msg, + String::from("16:13 notohh: cafdk"), + params.clone() + ).await; sleep(Duration::from_secs_f64(0.5)).await; @@ -183,8 +180,11 @@ async fn babygirl(bot: BotAR, msg: PrivmsgMessage) { botlock .botmgrs .chat - .say_in_reply_to(&msg, String::from("16:13 notohh: have fun eating princess")) - .await; + .say_in_reply_to( + ¶ms.msg, + String::from("16:13 notohh: have fun eating princess"), + params.clone() + ).await; sleep(Duration::from_secs_f64(2.0)).await; @@ -192,21 +192,23 @@ async fn babygirl(bot: BotAR, msg: PrivmsgMessage) { botlock .botmgrs .chat - .say_in_reply_to(&msg, String::from("16:13 notohh: baby girl")) - .await; + .say_in_reply_to( + ¶ms.msg, + String::from("16:13 notohh: baby girl"), + params.clone() + ).await; + } - - -async fn routinelike(_bot: BotAR, msg: PrivmsgMessage) { +async fn routinelike(params : ExecBodyParams) { println!("routinelike triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call botlog::debug( "routinelike triggered!", Some("experiments > routinelike()".to_string()), - Some(&msg), + Some(¶ms.msg), ); // spawn an async block that runs independently from others diff --git a/src/custom/experimental/experiment002.rs b/src/custom/experimental/experiment002.rs index 2a97b30..3be88ac 100644 --- a/src/custom/experimental/experiment002.rs +++ b/src/custom/experimental/experiment002.rs @@ -10,27 +10,22 @@ */ -// use rand::Rng; use std::sync::Arc; use chrono::{TimeZone,Local}; -use twitch_irc::message::PrivmsgMessage; -// use crate::core::botinstance::ChType::Channel; +use crate::core::bot_actions::ExecBodyParams; use crate::core::botinstance::Channel; -// use ChType::Channel; use crate::core::botlog; use casual_logger::Log; -use crate::core::bot_actions::actions_util::{self, BotAR}; +use crate::core::bot_actions::actions_util; use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager}; use crate::core::identity::UserRole::*; -// use tokio::time::{sleep, Duration}; - pub async fn init(mgr: Arc) { const OF_CMD_CHANNEL:Channel = Channel(String::new()); @@ -54,36 +49,33 @@ pub async fn init(mgr: Arc) { // 2. Add the BotAction to ModulesManager botc1.add_to_modmgr(Arc::clone(&mgr)).await; - mgr.set_instance_enabled(BotModule(String::from("experiments002"))).await; + // If enabling by defauling at instance level , uncomment the following + // mgr.set_instance_enabled(BotModule(String::from("experiments002"))).await; } -async fn sayout(bot: BotAR, msg: PrivmsgMessage) { +async fn sayout(params : ExecBodyParams) { + /* usage : */ - let reply_parent = if let Some(Some(reply)) = msg.source.tags.0.get("reply-parent-msg-body") { + + + let reply_parent = if let Some(Some(reply)) = params.msg.source.tags.0.get("reply-parent-msg-body") { Some(reply) } else { None } ; - // let reply_parent_usr = if let Some(Some(reply)) = msg.source.tags.0.get("reply-thread-parent-user-login") { - // Some(reply) - // } else { None } - // ; - - let reply_parent_ts = if let Some(Some(replyts)) = msg.source.tags.0.get("tmi-sent-ts") { + let reply_parent_ts = if let Some(Some(replyts)) = params.msg.source.tags.0.get("tmi-sent-ts") { let a: i64 = replyts.parse().unwrap(); let b = Local.timestamp_millis_opt(a).unwrap(); - // println!("Output : {}",b.to_string()); - // println!("Formatted : {}",b.format("%m-%d %H:%M") ); Some(b.format("%m-%d %H:%M")) } else { None } ; @@ -92,7 +84,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) { let argrslt = - if let Some((_,str1)) = msg.message_text.split_once(' ') { + if let Some((_,str1)) = params.msg.message_text.split_once(' ') { if reply_parent.is_none() { if let Some((channelstr,msgstr)) = str1.split_once(' ') { Some((channelstr,msgstr)) @@ -113,7 +105,7 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) { match argrslt { Some((trgchnl,outmsg)) => { - let bot = Arc::clone(&bot); + let bot = Arc::clone(¶ms.bot); let botlock = bot.read().await; @@ -126,26 +118,6 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) { None, ); - // if botlock.botmgrs.chat.client.get_channel_status(trgchnl.to_string().clone()).await == (false,false) { - if !botlock.bot_channels.contains(&Channel(trgchnl.to_lowercase().to_string().clone())) { - - // in the case where the provided channel isn't something we're known to be connected to - botlog::warn( - &format!("A message attempted to send for a Non-Joined Channel : {}",trgchnl.to_string().clone()), - Some("Chat > send_botmsg".to_string()), - None, - ); - // return ; - - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, format!("Not a Joined Channel : {}",trgchnl)) - .await; - - - } - /* 1. If a Reply , [ ] Get Parent Content message - reply_parent @@ -166,38 +138,26 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) { let newoutmsg = if let Some(srcmsg) = reply_parent { - // format!("{} from #{} says {} . Replying to: {} : {}", - // msg.sender.name,msg.channel_login,outmsg, reply_parent_usr.unwrap(),srcmsg) - // format!("{} from #{} says {} @ {} {} : {}", - // msg.sender.name, - // msg.channel_login, - // outmsg, - // reply_parent_ts.unwrap(), - // reply_parent_usr.unwrap(), - // srcmsg) format!("{} {} @ {} : {}", reply_parent_ts.unwrap(), - msg.sender.name, - msg.channel_login, + params.msg.sender.name, + params.msg.channel_login, srcmsg) } else { - // format!("{} from #{} says : {}", - // msg.sender.name, - // msg.channel_login, - // outmsg) format!("in {} - {} : {}", - msg.channel_login, - msg.sender.name, + params.msg.channel_login, + params.msg.sender.name, outmsg) }; - // uses chat.say_in_reply_to() for the bot controls for messages botlock .botmgrs .chat - .say(trgchnl.to_string(), newoutmsg.to_string()) - .await; - + .say( + trgchnl.to_string(), + newoutmsg.to_string(), + params.clone(), + ).await; }, @@ -205,24 +165,27 @@ async fn sayout(bot: BotAR, msg: PrivmsgMessage) { botlog::debug( "sayout had issues trying to parse arguments", Some("experiment002 > sayout".to_string()), - Some(&msg), + Some(¶ms.msg), ); - let bot = Arc::clone(&bot); + let bot = Arc::clone(¶ms.bot); let botlock = bot.read().await; // uses chat.say_in_reply_to() for the bot controls for messages botlock - .botmgrs - .chat - .say_in_reply_to(&msg, String::from("Invalid arguments")) - .await; + .botmgrs + .chat + .say_in_reply_to( + ¶ms.msg, + String::from("Invalid arguments"), + params.clone() + ).await; + }, } - Log::flush(); } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 40b5598..6bc6c0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,11 @@ pub async fn main() { for acts in (*actsdb_lock).values() { for act in acts { - let outstr = match act { + + let act_prelock = act; + let act = act_prelock.read().await; + + let outstr = match &(*act) { botmodules::BotAction::C(b) => { format!("bot actions > Command : {}", b.command) }