diff --git a/Cargo.toml b/Cargo.toml index 70c9e9c..5b20c49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,5 +16,5 @@ casual_logger = "0.6.5" [lib] -name = "botLib" +name = "bot_lib" path = "src/lib.rs" \ No newline at end of file diff --git a/src/core.rs b/src/core.rs index 7027176..8917c5d 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,9 +1,7 @@ +pub mod bot_actions; pub mod botinstance; +pub mod botlog; pub mod botmodules; +pub mod chat; pub mod identity; pub mod ratelimiter; - -// pub fn init() -> () -// { -// println!("I was here"); -// } diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs new file mode 100644 index 0000000..2e6b456 --- /dev/null +++ b/src/core/bot_actions.rs @@ -0,0 +1,27 @@ +pub mod actions_util { + + 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, + >; + + pub fn asyncbox(f: fn(BotAR, PrivmsgMessage) -> T) -> ExecBody + where + T: Future + Send + 'static, + { + Box::new(move |a, b| Box::pin(f(a, b))) + } +} diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs index 758ffdf..e31077f 100644 --- a/src/core/botinstance.rs +++ b/src/core/botinstance.rs @@ -1,246 +1,27 @@ -// use futures::lock::Mutex; -use tokio::sync::mpsc::UnboundedReceiver; -use tokio::sync::RwLock; -use twitch_irc::login::StaticLoginCredentials; -use twitch_irc::message::PrivmsgMessage; -use twitch_irc::message::ServerMessage; -use twitch_irc::transport::tcp::TCPTransport; -use twitch_irc::transport::tcp::TLS; -use twitch_irc::ClientConfig; -use twitch_irc::SecureTCPTransport; -use twitch_irc::TwitchIRCClient; -// use std::borrow::Borrow; -use dotenv::dotenv; -use std::borrow::BorrowMut; -use std::boxed; -use std::cell::Ref; -use std::env; - use std::collections::HashMap; +use std::env; +use std::sync::Arc; -use rand::Rng; +use tokio::sync::mpsc::UnboundedReceiver; +use tokio::sync::{Mutex, RwLock}; -// Important to use tokios Mutex here since std Mutex doesn't work with async functions -use tokio::sync::Mutex; +use twitch_irc::login::StaticLoginCredentials; +use twitch_irc::message::{PrivmsgMessage, ServerMessage}; +use twitch_irc::transport::tcp::{TCPTransport, TLS}; +use twitch_irc::{ClientConfig, SecureTCPTransport, TwitchIRCClient}; +use dotenv::dotenv; +use casual_logger::Log; -use crate::core::botmodules::BotAction; -use crate::core::ratelimiter; use crate::core::ratelimiter::RateLimiter; -use crate::core::botmodules; +use crate::core::bot_actions::actions_util::BotAR; use crate::core::botmodules::ModulesManager; use crate::core::identity::{ChangeResult, IdentityManager, Permissible}; -use std::cell::RefCell; -use std::rc::Rc; -use std::sync::Arc; -// use futures::lock::Mutex; - -use std::pin::Pin; - -//use std::borrow::Borrow; -use core::borrow::Borrow; - -// pub type BotAR = Arc>; -use super::botmodules::bot_actions::actions_util::BotAR; - -use casual_logger::{Level, Log}; - -pub mod botlog { - - /* - Module intends to add some layers to logging with the module user only requiring to pass : - - String Log message - - Option - Code_Module - - Option - this is used to parse out Chatter & Channel into the logs - */ - - use casual_logger::{Level, Log}; - use twitch_irc::message::PrivmsgMessage; - - // trace, debug, info, notice, warn, error, fatal - - /* - - in main : Log::debug("Checking bot actions", Some("main()".to_string()), None); - - in log : - [blalba@timestmp] - debug = "Checking bot actions", - - */ - - pub fn trace( - in_msg: &str, - in_module: Option, - in_prvmsg: Option<&PrivmsgMessage>, - ) -> () { - let (chnl, chatter) = match in_prvmsg { - Some(prvmsg) => { - //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); - ( - Some(prvmsg.channel_login.clone()), - Some(prvmsg.sender.name.clone()), - ) // <-- Clone fine atm while we're just working with Strings - } - None => (None, None), - }; - - Log::trace_t( - in_msg, - casual_logger::Table::default() // - .str("Channel", &format!("{:?}", chnl)) - .str("Chatter", &format!("{:?}", chatter)) - .str("Code_Module", &format!("{:?}", in_module)), - ); - } - - pub fn debug( - in_msg: &str, - in_module: Option, - in_prvmsg: Option<&PrivmsgMessage>, - ) -> () { - let (chnl, chatter) = match in_prvmsg { - Some(prvmsg) => { - //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); - ( - Some(prvmsg.channel_login.clone()), - Some(prvmsg.sender.name.clone()), - ) // <-- Clone fine atm while we're just working with Strings - } - None => (None, None), - }; - - Log::debug_t( - in_msg, - casual_logger::Table::default() // - .str("Channel", &format!("{:?}", chnl)) - .str("Chatter", &format!("{:?}", chatter)) - .str("Code_Module", &format!("{:?}", in_module)), - ); - } - - pub fn info(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) -> () { - let (chnl, chatter) = match in_prvmsg { - Some(prvmsg) => { - //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); - ( - Some(prvmsg.channel_login.clone()), - Some(prvmsg.sender.name.clone()), - ) // <-- Clone fine atm while we're just working with Strings - } - None => (None, None), - }; - - Log::info_t( - in_msg, - casual_logger::Table::default() // - .str("Channel", &format!("{:?}", chnl)) - .str("Chatter", &format!("{:?}", chatter)) - .str("Code_Module", &format!("{:?}", in_module)), - ); - } - - pub fn notice( - in_msg: &str, - in_module: Option, - in_prvmsg: Option<&PrivmsgMessage>, - ) -> () { - let (chnl, chatter) = match in_prvmsg { - Some(prvmsg) => { - //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); - ( - Some(prvmsg.channel_login.clone()), - Some(prvmsg.sender.name.clone()), - ) // <-- Clone fine atm while we're just working with Strings - } - None => (None, None), - }; - - Log::notice_t( - in_msg, - casual_logger::Table::default() // - .str("Channel", &format!("{:?}", chnl)) - .str("Chatter", &format!("{:?}", chatter)) - .str("Code_Module", &format!("{:?}", in_module)), - ); - } - - pub fn warn(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) -> () { - let (chnl, chatter) = match in_prvmsg { - Some(prvmsg) => { - //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); - ( - Some(prvmsg.channel_login.clone()), - Some(prvmsg.sender.name.clone()), - ) // <-- Clone fine atm while we're just working with Strings - } - None => (None, None), - }; - - Log::warn_t( - in_msg, - casual_logger::Table::default() // - .str("Channel", &format!("{:?}", chnl)) - .str("Chatter", &format!("{:?}", chatter)) - .str("Code_Module", &format!("{:?}", in_module)), - ); - } - - pub fn error( - in_msg: &str, - in_module: Option, - in_prvmsg: Option<&PrivmsgMessage>, - ) -> () { - let (chnl, chatter) = match in_prvmsg { - Some(prvmsg) => { - //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); - ( - Some(prvmsg.channel_login.clone()), - Some(prvmsg.sender.name.clone()), - ) // <-- Clone fine atm while we're just working with Strings - } - None => (None, None), - }; - - Log::error_t( - in_msg, - casual_logger::Table::default() // - .str("Channel", &format!("{:?}", chnl)) - .str("Chatter", &format!("{:?}", chatter)) - .str("Code_Module", &format!("{:?}", in_module)), - ); - } - - pub fn fatal<'a>( - in_msg: &'a str, - in_module: Option, - in_prvmsg: Option<&PrivmsgMessage>, - ) -> &'a str { - let (chnl, chatter) = match in_prvmsg { - Some(prvmsg) => { - //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); - ( - Some(prvmsg.channel_login.clone()), - Some(prvmsg.sender.name.clone()), - ) // <-- Clone fine atm while we're just working with Strings - } - None => (None, None), - }; - - Log::fatal_t( - in_msg, - casual_logger::Table::default() // - .str("Channel", &format!("{:?}", chnl)) - .str("Chatter", &format!("{:?}", chatter)) - .str("Code_Module", &format!("{:?}", in_module)), - ); - - in_msg - } -} +use crate::core::botlog; +use crate::core::chat::Chat; #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub enum ChType { @@ -249,105 +30,8 @@ pub enum ChType { pub use ChType::Channel; -#[derive(Clone)] -pub struct Chat { - pub ratelimiters: Arc>>, // used to limit messages sent per channel - pub client: TwitchIRCClient, StaticLoginCredentials>, -} - -impl Chat { - pub fn init( - ratelimiters: HashMap, - client: TwitchIRCClient, StaticLoginCredentials>, - ) -> Chat { - Chat { - ratelimiters: Arc::new(Mutex::new(ratelimiters)), - client: client, - } - } - - pub async fn init_channel(&mut self, chnl: ChType) -> () { - let n = RateLimiter::new(); - self.ratelimiters.lock().await.insert(chnl, n); - } - - // pub async fn say_in_reply_to(&mut self, msg:& PrivmsgMessage , mut outmsg:String) -> () { - pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, mut outmsg: String) -> () { - /* - formats message before sending to TwitchIRC - - - [x] Custom String Formatting (e.g., adding random black spaces) - - [x] Ratelimiter Handling - - [ ] Checkf if BotActions is Enabled & Caller is Allowed to Run - - */ - - let a = Arc::clone(&self.ratelimiters); - let mut a = a.lock().await; - - let contextratelimiter = a - // .get_mut() - .get_mut(&Channel(String::from(&msg.channel_login))) - .expect("ERROR: Issue with Rate limiters"); - - match contextratelimiter.check_limiter() { - ratelimiter::LimiterResp::Allow => { - let maxblanks = rand::thread_rng().gen_range(1..=20); - - for _i in 1..maxblanks { - let blankspace: &str = "󠀀"; - outmsg.push_str(blankspace); - } - - self.client.say_in_reply_to(msg, outmsg).await.unwrap(); - // println!("(#{}) > {}", msg.channel_login, "rate limit counter increase"); - // Log::trace(&format!("(#{}) > {}", msg.channel_login, "rate limit counter increase")); - botlog::trace( - &format!( - "(#{}) > {}", - msg.channel_login, "rate limit counter increase" - ), - Some("Chat > say_in_reply_to".to_string()), - Some(&msg), - ); - contextratelimiter.increment_counter(); - // println!("{:?}",self.ratelimiters); - // Log::trace(&format!("{:?}",self.ratelimiters)); - botlog::trace( - &format!("{:?}", self.ratelimiters), - Some("Chat > say_in_reply_to".to_string()), - Some(&msg), - ); - } - ratelimiter::LimiterResp::Skip => { - (); // do nothing otherwise - } - } - Log::flush(); - } - - async fn say(&self, _: String, _: String) -> () { - // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say - - // self.client.say(msg,outmsg).await.unwrap(); - } - - async fn me(&self, _: String, _: String) -> () { - // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say - - // self.client.me(msg,outmsg).await.unwrap(); - } - - async fn me_in_reply_to(&self, _: String, _: String) -> () { - // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say - - // self.client.me(msg,outmsg).await.unwrap(); - } -} - #[derive(Clone)] pub struct BotManagers { - // pub botmodules : ModulesManager, pub identity: Arc>, pub chat: Chat, } @@ -363,7 +47,7 @@ impl BotManagers { } } - pub fn rIdentity(self) -> Arc> { + pub fn r_identity(self) -> Arc> { self.identity } } @@ -376,8 +60,6 @@ impl ArcBox { } } -//#[derive(Clone)] -// #[derive(Copy)] // <-- Cannot be derived pub struct BotInstance { pub prefix: char, pub bot_channel: ChType, @@ -386,7 +68,7 @@ pub struct BotInstance { pub twitch_oauth: String, pub bot_channels: Vec, pub botmgrs: BotManagers, - //modesmgr : ModesManager, // Silent/Quiet , uwu , frisky/horny + //modesmgr : ModesManager, // [FUTURE] Silent/Quiet , uwu , frisky/horny } impl BotInstance { @@ -402,14 +84,9 @@ impl BotInstance { .next() .expect("ERROR : when defining prefix"); - /* - Vector of channels to join - */ - let mut botchannels = Vec::new(); for chnl in env::var("bot_channels").unwrap().split(',') { - // println!("(Env Var # {})",chnl); botchannels.push(Channel(String::from(chnl))); } @@ -421,32 +98,19 @@ impl BotInstance { let (incoming_messages, client) = TwitchIRCClient::::new(config); - // hashmap for channels and their associated ratelimiters let mut ratelimiters = HashMap::new(); for Channel(chnl) in &botchannels { - // For each channel in botchannels + // For each channel in botchannels , join & create ratelimiters client.join(chnl.to_owned()).unwrap(); - // ratelimiters are a hashmap of channel and a corresponding rate limiter let n = RateLimiter::new(); ratelimiters.insert(Channel(String::from(chnl)), n); - //self.chat.ratelimiters.insert(Channel(String::from(chnl)),n); } - // let b = BotInstance { - // prefix : prefix, - // bot_channel : Channel(login_name) , - // incoming_messages : Arc::new(RwLock::new(incoming_messages)), - // botmodules : ModulesManager::init().await, - // twitch_oauth : oauth_token, - // bot_channels : botchannels, - // botmgrs : BotManagers::init(ratelimiters,client), - // }; - BotInstance { - prefix: prefix, + prefix, bot_channel: Channel(login_name), incoming_messages: Arc::new(RwLock::new(incoming_messages)), botmodules: ModulesManager::init().await, @@ -454,56 +118,34 @@ impl BotInstance { bot_channels: botchannels, botmgrs: BotManagers::init(ratelimiters, client), } - - // b } - pub async fn runner(self) -> () { + pub async fn runner(self) { + // Main Game Loop + let bot = Arc::new(RwLock::new(self)); let join_handle = tokio::spawn(async move { - let a = bot.read().await; - let mut a = a.incoming_messages.write().await; - while let Some(message) = a.recv().await { + let botlock = bot.read().await; + let mut msglock = botlock.incoming_messages.write().await; + + while let Some(message) = msglock.recv().await { match message { ServerMessage::Notice(msg) => { - match &msg.channel_login { - Some(chnl) => { - // println!("NOTICE : (#{}) {}", chnl, msg.message_text) - // Log::notice(&format!("NOTICE : (#{}) {}", chnl, msg.message_text)); - botlog::notice( - &format!("NOTICE : (#{}) {}", chnl, msg.message_text), - Some("BotInstance > runner()".to_string()), - None, - ); - } - None => { - // println!("NOTICE : {}", msg.message_text); - // Log::notice(&format!("NOTICE : {}", msg.message_text)); - botlog::notice( - &format!("NOTICE : {}", msg.message_text), - Some("BotInstance > runner()".to_string()), - None, - ); - } - } + botlog::notice( + format!("NOTICE : (#{:?}) {}", msg.channel_login, msg.message_text) + .as_str(), + Some("BotInstance > runner()".to_string()), + None, + ); } ServerMessage::Privmsg(msg) => { - // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); - // Log::trace(&format!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text)); botlog::debug( - &format!( - "Twitch Chat > {} @ #{}: {}", + format!( + "[Twitch Chat > {}] > {}: {}", msg.channel_login, msg.sender.name, msg.message_text - ), - Some("BotInstance > runner()".to_string()), - Some(&msg), - ); - - // println!("Privmsg section"); - // Log::debug(&format!("Privmsg section")); - botlog::trace( - &format!("Privmsg section"), + ) + .as_str(), Some("BotInstance > runner()".to_string()), Some(&msg), ); @@ -511,28 +153,22 @@ impl BotInstance { BotInstance::listener_main_prvmsg(Arc::clone(&bot), &msg).await; } ServerMessage::Whisper(msg) => { - // println!("(w) {}: {}", msg.sender.name, msg.message_text); - // Log::trace(&format!("(w) {}: {}", msg.sender.name, msg.message_text)); - botlog::trace( - &format!("(w) {}: {}", msg.sender.name, msg.message_text), + botlog::debug( + format!("[Whisper] {}: {}", msg.sender.name, msg.message_text).as_str(), Some("BotInstance > runner()".to_string()), None, ); } ServerMessage::Join(msg) => { - // println!("JOINED: {}", msg.channel_login); - // Log::notice(&format!("JOINED: {}", msg.channel_login)); botlog::notice( - &format!("JOINED: {}", msg.channel_login), + format!("JOINED: {}", msg.channel_login).as_str(), Some("BotInstance > runner()".to_string()), None, ); } ServerMessage::Part(msg) => { - // println!("PARTED: {}", msg.channel_login); - // Log::notice(&format!("PARTED: {}", msg.channel_login)); botlog::notice( - &format!("PARTED: {}", msg.channel_login), + format!("PARTED: {}", msg.channel_login).as_str(), Some("BotInstance > runner()".to_string()), None, ); @@ -546,81 +182,39 @@ impl BotInstance { join_handle.await.unwrap(); } - pub fn get_botmodules(self) -> Arc { - self.botmodules - } - - pub async fn get_botmgrs(self) -> BotManagers { - let a = self.botmgrs; - a - } - pub fn get_identity(&self) -> Arc> { Arc::clone(&self.botmgrs.identity) } pub fn get_prefix(&self) -> char { - (*self).prefix + self.prefix } // ----------------- // PRIVATE FUNCTIONS - pub async fn listener_main_prvmsg(bot: BotAR, msg: &PrivmsgMessage) -> () { - // println!(">> Inner listenermain_prvmsg()"); - // Log::trace(">> Inner listenermain_prvmsg()"); + async fn listener_main_prvmsg(bot: BotAR, msg: &PrivmsgMessage) { botlog::trace( ">> Inner listenermain_prvmsg()", Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + Some(msg), ); - // let a = a; - // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); - - // // [ ] 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) + // // [ ] #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 hacts = Arc::clone(&botlock.botmodules.botactions); - // let hacts = hacts.read().await; - let a = hacts.read().await; - // println!("hacts size : {}",(*a).len()); - // Log::debug(&format!("hacts size : {}",(*a).len())); - botlog::trace( - &format!("hacts size : {}", (*a).len()), + 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), + Some(msg), ); - // println!(">> Inner listenermain_prvmsg() >> before for loop of bot actions"); - // Log::trace(">> Inner listenermain_prvmsg() >> before for loop of bot actions"); - botlog::trace( - ">> Inner listenermain_prvmsg() >> before for loop of bot actions", - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), - ); - - for (_m, acts) in &*hacts.read().await { - // println!(">> Inner listenermain_prvmsg() >> checking bot actions"); - // Log::trace(">> Inner listenermain_prvmsg() >> checking bot actions"); - botlog::trace( - ">> Inner listenermain_prvmsg() >> checking bot actions", - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), - ); - - // let bot = bot; - + for acts in (*actsdblock).values() { for a in acts { - // println!(">> Inner listenermain_prvmsg() >> checking bot actions >> 2"); - // Log::trace(">> Inner listenermain_prvmsg() >> checking bot actions >> 2"); - botlog::trace( - ">> Inner listenermain_prvmsg() >> checking bot actions >> 2", - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), - ); - - let _act = match a { + match a { crate::core::botmodules::BotAction::C(c) => { /* BotCommand handling - @@ -632,22 +226,15 @@ impl BotInstance { _cmdreqroles:Vec) */ - // for v in msg.message_text.split(" ") { - // println!("args : {v}"); - // } - - // println!("Reviewing internal commands"); - // Log::trace("Reviewing internal commands"); botlog::trace( "Reviewing internal commands", Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + Some(msg), ); - // let inpt = msg.message_text.split("\n").next().expect("ERROR during BotCommand"); let inpt = msg .message_text - .split(" ") + .split(' ') .next() .expect("ERROR during BotCommand"); @@ -670,118 +257,78 @@ impl BotInstance { } if confirmed_bot_command { - // println!("Confirmed bot command"); - // Log::debug("Confirmed bot command"); botlog::debug( - "Confirmed bot command", + format!("Confirmed bot command ; Msg : {}", msg.message_text) + .as_str(), Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), - ); - - // println!("Going for botlock"); - // Log::trace("Going for botlock"); - botlog::trace( - "Going for botlock", - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + // Some(&msg), + Some(msg), ); let botlock = bot.read().await; - // println!("Going for identity"); - // Log::trace("Going for identity"); - botlog::trace( - "Going for identity", - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), - ); - let id = botlock.get_identity(); let eval = { - let mut id = id.write().await; - // println!("Unlocking identity"); - // Log::trace("Unlocking identity"); - botlog::trace( - "Unpacking identity", - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), - ); + let mut idlock = id.write().await; + let (permissability, chngrslt) = idlock + .can_user_run_prvmsg(msg, c.required_roles.clone()) + .await; - let (a, b) = - id.can_user_run_PRVMSG(&msg, c.required_roles.clone()).await; - // // [-] #todo : need ot add functionality around here to do an o7 when a mod has been promoted => Preferring to do this outside the mutex - // if let ChangeResult::Success(b) = b { - // // let b = b.to_lowercase(); - // // let b = b.contains(&"Auto Promoted Mod".to_lowercase()); - // if b.to_lowercase().contains(&"Auto Promoted Mod".to_lowercase()) { - // let chat = - // } - // } - (a, b) + (permissability, chngrslt) }; - // println!("Checking if permissible"); - Log::trace("Checking if permissible"); + botlog::trace( "Checking if permissible", Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + Some(msg), ); let (eval, rolechange) = eval; - if let ChangeResult::Success(b) = rolechange { - if b.to_lowercase() + if let ChangeResult::Success(innerstr) = rolechange { + if innerstr + .to_lowercase() .contains(&"Auto Promoted Mod".to_lowercase()) { botlog::notice( "Assigning Mod UserRole to Mod", Some("botinstance > listener_main_prvmsg()".to_string()), - Some(&msg), - ); - - // println!("Read() lock Bot"); - // Log::trace("Read() lock Bot"); - botlog::trace( - "Read() lock Bot", - Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + Some(msg), ); 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; + botlock.botmgrs.chat.say_in_reply_to(msg, outstr).await; } } match eval { Permissible::Allow => { - // println!("Executed as permissible"); - // Log::debug("Executed as permissible"); botlog::debug( "Executed as permissible", Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + Some(msg), ); + let a = Arc::clone(&bot); c.execute(a, msg.clone()).await; - // println!("exit out of execution"); - // Log::trace("exit out of execution"); + botlog::trace( "exit out of execution", Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + // Some(&msg), + Some(msg), ); } + Permissible::Block => { - // println!("User Not allowed to run command"); - // Log::info("User Not allowed to run command"); botlog::info( "User Not allowed to run command", Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + Some(msg), ); - } // _ => (), + } }; } } @@ -796,19 +343,12 @@ impl BotInstance { } } - // // [ ] There should be a BotCommand Listener to check for prefixes ran - - // println!("End of Separate Listener Main prvmsg"); - // Log::trace("End of Separate Listener Main prvmsg"); botlog::trace( "End of Separate Listener Main prvmsg", Some("BotInstance > listener_main_prvmsg()".to_string()), - Some(&msg), + Some(msg), ); - // self - // bot - Log::flush(); } } diff --git a/src/core/botlog.rs b/src/core/botlog.rs new file mode 100644 index 0000000..27272d2 --- /dev/null +++ b/src/core/botlog.rs @@ -0,0 +1,175 @@ +/* + Module intends to add some layers to logging with the module user only requiring to pass : + - String Log message + - Option - Code_Module + - Option - this is used to parse out Chatter & Channel into the logs +*/ + +// use casual_logger::{Level, Log}; +use casual_logger::Log; +use twitch_irc::message::PrivmsgMessage; + +// trace, debug, info, notice, warn, error, fatal + +/* + +in main : Log::debug("Checking bot actions", Some("main()".to_string()), None); + +in log : +[blalba@timestmp] +debug = "Checking bot actions", + +*/ + +pub fn trace(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) { + let (chnl, chatter) = match in_prvmsg { + Some(prvmsg) => { + //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); + ( + Some(prvmsg.channel_login.clone()), + Some(prvmsg.sender.name.clone()), + ) // <-- Clone fine atm while we're just working with Strings + } + None => (None, None), + }; + + Log::trace_t( + in_msg, + casual_logger::Table::default() // + .str("Channel", &format!("{:?}", chnl)) + .str("Chatter", &format!("{:?}", chatter)) + .str("Code_Module", &format!("{:?}", in_module)), + ); +} + +pub fn debug(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) { + let (chnl, chatter) = match in_prvmsg { + Some(prvmsg) => { + //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); + ( + Some(prvmsg.channel_login.clone()), + Some(prvmsg.sender.name.clone()), + ) // <-- Clone fine atm while we're just working with Strings + } + None => (None, None), + }; + + Log::debug_t( + in_msg, + casual_logger::Table::default() // + .str("Channel", &format!("{:?}", chnl)) + .str("Chatter", &format!("{:?}", chatter)) + .str("Code_Module", &format!("{:?}", in_module)), + ); +} + +pub fn info(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) { + let (chnl, chatter) = match in_prvmsg { + Some(prvmsg) => { + //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); + ( + Some(prvmsg.channel_login.clone()), + Some(prvmsg.sender.name.clone()), + ) // <-- Clone fine atm while we're just working with Strings + } + None => (None, None), + }; + + Log::info_t( + in_msg, + casual_logger::Table::default() // + .str("Channel", &format!("{:?}", chnl)) + .str("Chatter", &format!("{:?}", chatter)) + .str("Code_Module", &format!("{:?}", in_module)), + ); +} + +pub fn notice(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) { + let (chnl, chatter) = match in_prvmsg { + Some(prvmsg) => { + //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); + ( + Some(prvmsg.channel_login.clone()), + Some(prvmsg.sender.name.clone()), + ) // <-- Clone fine atm while we're just working with Strings + } + None => (None, None), + }; + + Log::notice_t( + in_msg, + casual_logger::Table::default() // + .str("Channel", &format!("{:?}", chnl)) + .str("Chatter", &format!("{:?}", chatter)) + .str("Code_Module", &format!("{:?}", in_module)), + ); +} + +pub fn warn(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) { + let (chnl, chatter) = match in_prvmsg { + Some(prvmsg) => { + //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); + ( + Some(prvmsg.channel_login.clone()), + Some(prvmsg.sender.name.clone()), + ) // <-- Clone fine atm while we're just working with Strings + } + None => (None, None), + }; + + Log::warn_t( + in_msg, + casual_logger::Table::default() // + .str("Channel", &format!("{:?}", chnl)) + .str("Chatter", &format!("{:?}", chatter)) + .str("Code_Module", &format!("{:?}", in_module)), + ); +} + +pub fn error(in_msg: &str, in_module: Option, in_prvmsg: Option<&PrivmsgMessage>) { + let (chnl, chatter) = match in_prvmsg { + Some(prvmsg) => { + //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); + ( + Some(prvmsg.channel_login.clone()), + Some(prvmsg.sender.name.clone()), + ) // <-- Clone fine atm while we're just working with Strings + } + None => (None, None), + }; + + Log::error_t( + in_msg, + casual_logger::Table::default() // + .str("Channel", &format!("{:?}", chnl)) + .str("Chatter", &format!("{:?}", chatter)) + .str("Code_Module", &format!("{:?}", in_module)), + ); +} + +pub fn fatal<'a>( + in_msg: &'a str, + in_module: Option, + in_prvmsg: Option<&PrivmsgMessage>, +) -> &'a str { + let (chnl, chatter) = match in_prvmsg { + Some(prvmsg) => { + //Log::trace(&format!("(#{}) {}: {}", prvmsg.channel_login, prvmsg.sender.name, prvmsg.message_text)); + ( + Some(prvmsg.channel_login.clone()), + Some(prvmsg.sender.name.clone()), + ) // <-- Clone fine atm while we're just working with Strings + } + None => (None, None), + }; + + Log::fatal_t( + in_msg, + casual_logger::Table::default() // + .str("Channel", &format!("{:?}", chnl)) + .str("Chatter", &format!("{:?}", chatter)) + .str("Code_Module", &format!("{:?}", in_module)), + ); + + in_msg +} diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs index 2a38523..0bfe4fa 100644 --- a/src/core/botmodules.rs +++ b/src/core/botmodules.rs @@ -1,28 +1,3 @@ -use core::panic; -use std::error::Error; - -use std::collections::HashMap; - -use crate::core::identity; - -use std::cell::RefCell; -use std::sync::Arc; -use tokio::sync::RwLock; - -use std::future::Future; -// use futures::lock::Mutex; - -// Important to use tokios Mutex here since std Mutex doesn't work with async functions -use tokio::sync::Mutex; - -use crate::core::botinstance::{self, botlog, BotInstance}; -use std::rc::Rc; - -// use tokio::sync::RwLock; - -use async_trait::async_trait; -use casual_logger::{Level, Log}; - /* ModulesManager is used to manage Modules and BotActions associated with those modules @@ -44,30 +19,36 @@ Example */ +use core::panic; + +use std::collections::HashMap; +use std::error::Error; +use std::sync::Arc; + +use twitch_irc::message::PrivmsgMessage; + +use tokio::sync::RwLock; + +use async_trait::async_trait; + +use self::bot_actions::actions_util::BotAR; +use crate::core::botinstance::{BotInstance, ChType}; +use crate::core::botlog; +use crate::core::identity; + +use crate::core::bot_actions; +pub use ChType::Channel; +pub use ModType::BotModule; + #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub enum ModType { BotModule(String), } -pub use ModType::BotModule; - -// #[derive(Debug, PartialEq, Eq, Hash, Clone)] -// pub enum ChType { -// Channel(String), -// } - -use botinstance::ChType; - -use twitch_irc::message::PrivmsgMessage; -pub use ChType::Channel; - -use self::bot_actions::actions_util; -use self::bot_actions::actions_util::BotAR; - #[derive(Debug)] -enum StatusLvl { +pub enum StatusLvl { Instance, - Ch(ChType), + _Ch(ChType), } #[derive(Debug)] @@ -76,7 +57,6 @@ pub enum ModStatusType { Disabled(StatusLvl), } -// #[derive(Clone)] pub enum BotAction { C(BotCommand), L(Listener), @@ -84,7 +64,7 @@ pub enum BotAction { } impl BotAction { - pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) -> () { + pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) { match self { BotAction::L(a) => a.execute(m, n).await, BotAction::C(a) => a.execute(m, n).await, @@ -99,20 +79,18 @@ pub trait BotActionTrait { async fn add_to_modmgr(self, modmgr: Arc); } -// #[derive(Clone)] pub struct BotCommand { pub module: ModType, pub command: String, // command call name pub alias: Vec, // String of alternative names - // bot_prefix : char, // although should be global? pub exec_body: bot_actions::actions_util::ExecBody, pub help: String, pub required_roles: Vec, } impl BotCommand { - pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) -> () { - ((*self).exec_body)(m, n).await; + pub async fn execute(&self, m: BotAR, n: PrivmsgMessage) { + (*self.exec_body)(m, n).await; } } @@ -122,7 +100,6 @@ impl BotActionTrait for BotCommand { self.add_to_modmgr(bot.botmodules).await; } - // async fn add_to_modmgr(self, modmgr:Arc>) { async fn add_to_modmgr(self, modmgr: Arc) { modmgr .add_botaction(self.module.clone(), BotAction::C(self)) @@ -130,40 +107,6 @@ impl BotActionTrait for BotCommand { } } -pub mod bot_actions { - - pub mod actions_util { - - use std::boxed::Box; - use std::future::Future; - use std::pin::Pin; - - use std::rc::Rc; - - use crate::core::botinstance::{BotInstance, BotManagers, Chat}; - use std::cell::RefCell; - use std::sync::Arc; - use twitch_irc::message::PrivmsgMessage; - // use futures::lock::Mutex; - // Important to use tokios Mutex here since std Mutex doesn't work with async functions - use tokio::sync::{Mutex, RwLock}; - - pub type BotAM = Arc>; - pub type BotAR = Arc>; - - pub type ExecBody = Box< - dyn Fn(BotAR, PrivmsgMessage) -> Pin + Send>> + Send + Sync, - >; - - pub fn asyncbox(f: fn(BotAR, PrivmsgMessage) -> T) -> ExecBody - where - T: Future + Send + 'static, - { - Box::new(move |a, b| Box::pin(f(a, b))) - } - } -} - pub struct Listener { pub module: ModType, pub name: String, @@ -172,17 +115,15 @@ 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, m: BotAR, n: PrivmsgMessage) { + (self.exec_body)(m, n).await; } } #[async_trait] impl BotActionTrait for Listener { async fn add_to_bot(self, bot: BotInstance) { - // println!("Adding action to bot"); - // Log::trace("Adding action to bot"); - botinstance::botlog::trace( + botlog::trace( "Adding action to bot", Some("BotModules > BotActionTrait > add_to_bot()".to_string()), None, @@ -191,10 +132,7 @@ impl BotActionTrait for Listener { } async fn add_to_modmgr(self, modmgr: Arc) { - // let modmgr = *modmgr.lock().await; - // println!("Adding action to module manager"); - // Log::trace("Adding action to module manager"); - botinstance::botlog::trace( + botlog::trace( "Adding action to module manager", Some("BotModules > BotActionTrait > add_to_bot()".to_string()), None, @@ -207,9 +145,7 @@ impl BotActionTrait for Listener { } #[derive(Debug)] -struct Routine {} - -// #[derive(Clone)] +pub struct Routine {} pub struct ModulesManager { statusdb: Arc>>>, @@ -232,35 +168,33 @@ botactions impl ModulesManager { pub async fn init() -> Arc { - let m = HashMap::new(); - let act = HashMap::new(); - - let mut mgr = ModulesManager { - statusdb: Arc::new(RwLock::new(m)), - botactions: Arc::new(RwLock::new(act)), + let mgr = ModulesManager { + statusdb: Arc::new(RwLock::new(HashMap::new())), + botactions: Arc::new(RwLock::new(HashMap::new())), }; // :: [x] initialize core modules - - // println!("ModulesManager > init() > Adding modules"); - botlog::debug( + botlog::trace( "ModulesManager > init() > Adding modules", Some("ModulesManager > init()".to_string()), None, ); - let mgra = Arc::new(mgr); - crate::core::identity::init(Arc::clone(&mgra)).await; - crate::modules::init(Arc::clone(&mgra)).await; + let mgrarc = Arc::new(mgr); + + // 1. load core modules + crate::core::identity::init(Arc::clone(&mgrarc)).await; + + // 2. load custom modules + crate::custom::init(Arc::clone(&mgrarc)).await; - // println!(">> Modules Manager : End of Init"); botlog::trace( ">> Modules Manager : End of Init", Some("ModulesManager > init()".to_string()), None, ); - mgra + mgrarc } pub fn modstatus(&self, _: ModType, _: ChType) -> ModStatusType { @@ -286,8 +220,6 @@ impl ModulesManager { } pub async fn add_botaction(&self, in_module: ModType, in_action: BotAction) { - // println!("Add botaction called"); - botlog::trace( "Add botaction called", Some("ModulesManager > init()".to_string()), @@ -306,37 +238,15 @@ impl ModulesManager { both would be called separately, even if they both have the same or different logic */ - // let newlistener = Listener { - // // module : BotModule(String::from("experiments").to_owned()), - // module : in_module.clone(), - // name : String::from("socklistener"), - // help : String::from("This will listen and react to sock randomly"), - // }; - - // As a Demonstration, the listener's Module is added and Enabled at Instance level - // [x] Before Adding, validate the following : // - If BotAction to Add is a BotCommand , In Module Manager DB (botactions), // Check All Other BotAction Command Names & Aliases to ensure they don't conflict async fn find_conflict_module(mgr: &ModulesManager, act: &BotAction) -> Option { - // Some(BotModule(String::from("GambaCore"))) - - // match act { - // BotAction::C(c) => { - // Some(BotModule(String::from("GambaCore"))) - // }, - // BotAction::L(l) => None, - // BotAction::R(r) => None, - // } - if let BotAction::C(incmd) = act { - // let n = & mgr.botactions; + let actdb = mgr.botactions.read().await; - let d = mgr.botactions.read().await; - let d = &(*d); - - for (module, moduleactions) in d { + for (module, moduleactions) in &(*actdb) { for modact in moduleactions.iter() { if let BotAction::C(dbcmd) = &modact { // At this point, there is an command incmd and looked up dbcmd @@ -345,17 +255,13 @@ impl ModulesManager { if incmd.command.to_lowercase() == dbcmd.command.to_lowercase() { // Returning State - with the identified module - // return Some((module.clone(),BotAction::C(*dbcmd.clone()))); - // return Some(incmd); // for some reason I keep getting issues - //return Some(BotModule(String::from("GambaCore"))); // works return Some(module.clone()); // works - // return Some(dbcmd.clone()); } for a in &dbcmd.alias { if incmd.command.to_lowercase() == a.to_lowercase() { // Returning State - with the identified module - // return Some((module.clone(),BotAction::C(dbcmd))); + return Some(module.clone()); // works } } @@ -365,14 +271,14 @@ impl ModulesManager { for inalias in &incmd.alias { if inalias.to_lowercase() == dbcmd.command.to_lowercase() { // Returning State - with the identified module - // return Some((module.clone(),BotAction::C(dbcmd))); + return Some(module.clone()); // works } for a in &dbcmd.alias { if inalias.to_lowercase() == a.to_lowercase() { // Returning State - with the identified module - // return Some((module.clone(),BotAction::C(dbcmd))); + return Some(module.clone()); // works } } @@ -380,65 +286,46 @@ impl ModulesManager { } } } - - // return Some(BotModule(String::from("GambaCore"))) } // for all other scenarios (e.g., Listener, Routine), find no conflicts None } - // if let probmod = find_conflict_module(&self, &in_action) { - // // () // return because there was a conflict? - // panic!("ERROR: Could not add {:?} ; there was a conflict with existing module {:?}", in_action , probmod ); - // } - match find_conflict_module(&self, &in_action).await { - // Some(c) => panic!("ERROR: Could not add {:?} ; there was a conflict with existing module {:?}", in_action , c ), - Some(c) => panic!( + if let Some(c) = find_conflict_module(self, &in_action).await { + panic!( "ERROR: Could not add module; there was a conflict with existing module {:?}", c - ), - None => (), + ) } let mut dbt = self.statusdb.write().await; - let statusvector = dbt - // .entry(BotModule(String::from("experiments"))) - .entry(in_module.clone()) - .or_insert(Vec::new()); + let statusvector = dbt.entry(in_module.clone()).or_insert(Vec::new()); statusvector.push(ModStatusType::Enabled(StatusLvl::Instance)); // Pushes the Module as Enabled at Instance Level let mut a = self.botactions.write().await; - let modactions = a - //.entry( BotModule(String::from("experiments"))) - .entry(in_module.clone()) - .or_insert(Vec::new()); + let modactions = a.entry(in_module.clone()).or_insert(Vec::new()); - // modactions.push(BotAction::L(newlistener)); modactions.push(in_action); - // println!(">> Modules Manager : Called Add bot Action"); botlog::trace( - ">> Modules Manager : Called Add bot Action", - Some("ModulesManager > init()".to_string()), - None, - ); - // println!("add_botaction - botactions size : {}",modactions.len()); - botlog::trace( - &format!("add_botaction - botactions size : {}", modactions.len()), + format!( + "Modules Manager> add_botaction called - botactions size : {}", + modactions.len() + ) + .as_str(), Some("ModulesManager > init()".to_string()), None, ); } - fn statuscleanup(&self, _: Option) -> () { + fn _statuscleanup(&self, _: Option) { // internal cleans up statusdb . For example : // - remove redudancies . If we see several Enabled("m"), only keep 1x // - Clarify Conflict. If we see Enabled("m") and Disabled("m") , we remove Enabled("m") and keep Disabled("m") // the IDEAL is that this is ran before every read/update operation to ensure quality // Option can pass Some(Channel("m")) (as an example) so statuscleanup only works on the given channel // Passing None to chnl may be a heavy operation, as this will review and look at the whole table - () } } diff --git a/src/core/chat.rs b/src/core/chat.rs new file mode 100644 index 0000000..4720af7 --- /dev/null +++ b/src/core/chat.rs @@ -0,0 +1,110 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use tokio::sync::Mutex; + +use twitch_irc::login::StaticLoginCredentials; +use twitch_irc::message::PrivmsgMessage; +use twitch_irc::transport::tcp::{TCPTransport, TLS}; +use twitch_irc::TwitchIRCClient; + +use casual_logger::Log; + +use rand::Rng; + +use crate::core::ratelimiter; +use crate::core::ratelimiter::RateLimiter; + +use crate::core::botinstance::ChType; +use crate::core::botlog; +pub use ChType::Channel; + +#[derive(Clone)] +pub struct Chat { + pub ratelimiters: Arc>>, // used to limit messages sent per channel + pub client: TwitchIRCClient, StaticLoginCredentials>, +} + +impl Chat { + pub fn init( + ratelimiters: HashMap, + client: TwitchIRCClient, StaticLoginCredentials>, + ) -> Chat { + Chat { + ratelimiters: Arc::new(Mutex::new(ratelimiters)), + client, + } + } + + pub async fn init_channel(&mut self, chnl: ChType) { + let n = RateLimiter::new(); + self.ratelimiters.lock().await.insert(chnl, n); + } + + pub async fn say_in_reply_to(&self, msg: &PrivmsgMessage, mut outmsg: String) { + /* + formats message before sending to TwitchIRC + + - [x] Custom String Formatting (e.g., adding random black spaces) + - [x] Ratelimiter Handling + - [ ] Checkf if BotActions is Enabled & Caller is Allowed to Run + + */ + + let rl = Arc::clone(&self.ratelimiters); + let mut rllock = rl.lock().await; + + let contextratelimiter = rllock + // .get_mut() + .get_mut(&Channel(String::from(&msg.channel_login))) + .expect("ERROR: Issue with Rate limiters"); + + match contextratelimiter.check_limiter() { + ratelimiter::LimiterResp::Allow => { + let maxblanks = rand::thread_rng().gen_range(1..=20); + + for _i in 1..maxblanks { + let blankspace: &str = "󠀀"; + outmsg.push_str(blankspace); + } + + self.client.say_in_reply_to(msg, outmsg).await.unwrap(); + + contextratelimiter.increment_counter(); + + let logstr = format!( + "(#{}) > {} ; Ratelimiers : {:?}", + msg.channel_login, "rate limit counter increase", self.ratelimiters + ); + + botlog::trace( + logstr.as_str(), + Some("Chat > say_in_reply_to".to_string()), + Some(msg), + ); + } + ratelimiter::LimiterResp::Skip => { + // (); // do nothing otherwise + } + } + Log::flush(); + } + + async fn _say(&self, _: String, _: String) { + // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say + + // self.client.say(msg,outmsg).await.unwrap(); + } + + async fn _me(&self, _: String, _: String) { + // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say + + // self.client.me(msg,outmsg).await.unwrap(); + } + + async fn _me_in_reply_to(&self, _: String, _: String) { + // more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say + + // self.client.me(msg,outmsg).await.unwrap(); + } +} diff --git a/src/core/identity.rs b/src/core/identity.rs index b21ccb3..877fb6c 100644 --- a/src/core/identity.rs +++ b/src/core/identity.rs @@ -1,44 +1,29 @@ -use std::borrow::Borrow; use std::collections::HashMap; -use std::error::Error; - -use crate::core::botmodules::bot_actions::actions_util; -use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager}; - -use crate::core::botinstance::{self, botlog, BotInstance, ChType}; -use futures::lock::Mutex; -use twitch_irc::message::{Badge, PrivmsgMessage}; - -// use crate::core::botmodules::ChType; - -use crate::core::botinstance::ArcBox; - -use std::cell::RefCell; -use std::rc::Rc; - use std::sync::Arc; + use tokio::sync::RwLock; -use casual_logger::{Level, Log}; +use twitch_irc::message::PrivmsgMessage; -use super::botmodules::bot_actions::actions_util::BotAR; +use casual_logger::Log; + +use crate::core::bot_actions::actions_util::{self, BotAR}; +use crate::core::botinstance::ChType; +use crate::core::botlog; +use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, ModulesManager}; fn adminvector() -> Vec { vec![String::from("ModulatingForce")] //vec![] } -// pub fn init(mgr:&mut ModulesManager) pub async fn init(mgr: Arc) { - // println!("Went into Identiy Module init"); - botinstance::botlog::trace( - "Went into Identiy Module init", + botlog::trace( + "Went into Identity Module init", Some("identity.rs > init()".to_string()), None, ); - // let a = actions_util::asyncbox(cmd_promote) ; - let tempb = BotCommand { module: BotModule(String::from("identity")), command: String::from("promote"), // command call name @@ -55,10 +40,8 @@ pub async fn init(mgr: Arc) { tempb.add_to_modmgr(Arc::clone(&mgr)).await; - async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) -> () { - //println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); - // println!("Called cmd promote"); - botinstance::botlog::trace( + async fn cmd_promote(bot: BotAR, msg: PrivmsgMessage) { + botlog::trace( "Called cmd promote", Some("identity.rs > cmd_prommote()".to_string()), Some(&msg), @@ -91,15 +74,15 @@ pub async fn init(mgr: Arc) { */ // println!("{}",msg.message_text); - botinstance::botlog::trace( - &format!("Twich Message > {}", msg.message_text), + botlog::trace( + format!("Twich Message > {}", msg.message_text).as_str(), Some("identity.rs > cmd_promote()".to_string()), None, ); let sendername = msg.clone().sender.name; - let mut argv = msg.message_text.split(" "); + let mut argv = msg.message_text.split(' '); argv.next(); // Skip the command name @@ -141,8 +124,8 @@ pub async fn init(mgr: Arc) { let rslt = match targetusr { Some(targetusr) => { - botinstance::botlog::debug( - &format!("running promote()"), + botlog::debug( + "running promote()", Some("identity.rs > cmd_promote()".to_string()), None, ); @@ -166,8 +149,9 @@ pub async fn init(mgr: Arc) { } None => { - botinstance::botlog::debug( - &format!("No Targer User argument"), + botlog::debug( + // &format!("No Targer User argument"), + "No Targer User argument", Some("identity.rs > cmd_demote()".to_string()), None, ); @@ -179,329 +163,38 @@ pub async fn init(mgr: Arc) { // [x] 3. Output resulting change - match rslt { + let outmsg = match rslt { ChangeResult::Success(a) => { - // println!("Succesfully promoted : {a} ;"); - let outmsg = &format!("o7 Successfully promoted : {a}"); - botinstance::botlog::debug( - outmsg, - Some("identity.rs > cmd_prommote()".to_string()), - Some(&msg), - ); - // let outmsg = "o7 Successfully promoted : ".to_string(); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + format!("o7 Successfully promoted : {a}") } ChangeResult::Failed(a) => { - // println!("Failed to promote : {a} ; "); - let outmsg = &format!("PoroSad failed to promote : {a}"); - botinstance::botlog::debug( - outmsg, - Some("identity.rs > cmd_prommote()".to_string()), - Some(&msg), - ); - // let outmsg = "PoroSad failed to promote : ".to_string(); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + format!("PoroSad failed to promote : {a}") } ChangeResult::NoChange(a) => { - // println!("No Changes Made : {a} ; "); - let outmsg = &format!("uuh No Promotion Change : {a}"); - botinstance::botlog::debug( - outmsg, - Some("identity.rs > cmd_prommote()".to_string()), - Some(&msg), - ); - // let outmsg = "uuh No Promotion Change : ".to_string(); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + format!("uuh No Promotion Change : {a}") } - } + }; - /* - match arg1 { - Some(a1) if a1 == String::from("-admin") => { - // - [x] BotAdmins can promote admin to give BotAdmin UserRole + botlog::debug( + outmsg.as_str(), + Some("identity.rs > cmd_prommote()".to_string()), + Some(&msg), + ); - let botlock = bot.read().await; - let idlock = botlock.get_identity(); - let id = idlock.read().await; - // let ta = ta.getspecialuserroles(String::from("Hello"), Some(ChType::Channel(msg.channel_login.to_lowercase()))); - // let ta = ta.getspecialuserroles(arg2.unwrap().to_string(), Some(ChType::Channel(msg.channel_login.to_lowercase()))); - let rolesfut = id.getspecialuserroles( - msg.sender.name.to_lowercase(), - Some(ChType::Channel(msg.channel_login.to_lowercase()))); - let usrroles = rolesfut.await; - // let ta = ta.unwrap(); - // let a = ta.read().await; - // let ta = *ta; - // let ta = *ta; - // if let Some(a) = *ta { + botlock + .botmgrs + .chat + .say_in_reply_to(&msg, outmsg.to_string()) + .await; - if usrroles.contains(&UserRole::BotAdmin) { - // println!("BotAdmin allowed to promote admin"); - botinstance::botlog::debug("BotAdmin allowed to promote admin", - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - - { - - let idlock = Arc::clone(&bot.read().await.get_identity()); - // let idlock = idlock.write().await; - let idlock = idlock.read().await; - // let mut idlock = *idlock; - // let ta = idlock.promote(msg.sender.name.to_lowercase(), None, Some(UserRole::BotAdmin)).await; - let ta = idlock.promote(arg2.unwrap().to_string().to_lowercase(), None, Some(UserRole::BotAdmin)).await; - - match ta { - ChangeResult::Success(a) => { - // println!("Succesfully promoted : {a} ;"); - let outmsg = &format!("o7 Successfully promoted : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - // let outmsg = "o7 Successfully promoted : ".to_string(); - botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::Failed(a) => { - // println!("Failed to promote : {a} ; "); - let outmsg = &format!("PoroSad failed to promote : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - // let outmsg = "PoroSad failed to promote : ".to_string(); - botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::NoChange(a) => { - // println!("No Changes Made : {a} ; "); - let outmsg = &format!("uuh No Promotion Change : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - // let outmsg = "uuh No Promotion Change : ".to_string(); - botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - - } - } - } // if usrroles.contains(&UserRole::BotAdmin) - } - - // }, - Some(arg1) => { - // In the case of promoting another chatter - // Check caller's roles - // Check targer chatter's roles - // - Also check if target chatter alread has target roles - // if caller's role is Broadcaster, SupMod, BotAdmin , they can Promote target Chatters to become Mod (i.e., the target user is not a Mod,SupMod,BotAdmin) - // if caller is BotAdmin, they can promote BotAdmins to Mod - // if caller's role is Broadcaster, BotAdmin, they can Promote target Mod to SupMod - botinstance::botlog::debug(&format!("Evaluating arg1: {arg1}"), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - - let idlock = Arc::clone(&bot.read().await.get_identity()); - let idlock = idlock.read().await; - // let ta = idlock.promote(msg.sender.name.to_lowercase(), None, Some(UserRole::BotAdmin)).await; - - let senderroles = idlock.getspecialuserroles( - msg.sender.name.to_lowercase(), - Some(ChType::Channel(msg.channel_login.to_lowercase()))).await; - - let trgusrroles = idlock.getspecialuserroles( - arg1.to_lowercase(), - Some(ChType::Channel(msg.channel_login.to_lowercase()))).await; - - botinstance::botlog::debug(&format!("Ready to evaluate sender and targer user roles"), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - - botinstance::botlog::trace(&format!("Related Vars : sender roles : {:?} ; targer usr roles : {:?}" , - senderroles,trgusrroles), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - - if ( senderroles.contains(&UserRole::Broadcaster) || - senderroles.contains(&UserRole::SupMod(ChType::Channel(msg.channel_login.to_lowercase()))) || - senderroles.contains(&UserRole::BotAdmin) ) && - ( !trgusrroles.contains(&UserRole::Broadcaster) && - // !trgusrroles.contains(&UserRole::BotAdmin) && // target users that are BotAdmins can promote themselves to Mod or SupMod - !trgusrroles.contains(&UserRole::SupMod(ChType::Channel(msg.channel_login.to_lowercase()))) && - !trgusrroles.contains(&UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase()))) - ) - { - // if caller's role is Broadcaster, SupMod, BotAdmin , they can Promote target Chatters to become Mod (i.e., the target user is not a Mod,SupMod,BotAdmin) - botinstance::botlog::trace(&format!("Attempting promote..."), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - let ta = idlock.promote(arg1.to_string().to_lowercase(), - Some(ChType::Channel(msg.channel_login.to_lowercase())), - Some(UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase())))).await; - - match ta { - ChangeResult::Success(a) => { - // println!("Succesfully promoted : {a} ;"); - let outmsg = &format!("Successful Promotion : {a}"); - botinstance::botlog::debug(&format!("Successful Promotion : {a}"), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - // let outmsg = "o7 Successfully promoted : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::Failed(a) => { - // println!("Failed to promote : {a} ; "); - let outmsg = &format!("PoroSad failed to promote : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - // Log::flush(); - // let outmsg = "PoroSad failed to promote : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::NoChange(a) => { - // println!("No Changes Made : {a} ; "); - let outmsg = &format!("uuh Not making any changes : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - // let outmsg = "uuh No Promotion Change : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - - } - - } else if trgusrroles.contains(&UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase()))) && - ( senderroles.contains(&UserRole::Broadcaster) || - senderroles.contains(&UserRole::BotAdmin) ) - { - botinstance::botlog::trace(&format!("Attempting promote..."), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - - // broadcaster & botadmins can make mods into SupMod - let ta = idlock.promote(arg1.to_string().to_lowercase(), - Some(ChType::Channel(msg.channel_login.to_lowercase())), - Some(UserRole::SupMod(ChType::Channel(msg.channel_login.to_lowercase())))).await; - - match ta { - ChangeResult::Success(a) => { - // println!("Succesfully promoted : {a} ;"); - let outmsg = &format!("Successful Promotion : {a}"); - botinstance::botlog::debug(&format!("Successful Promotion : {a}"), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - // let outmsg = "o7 Successfully promoted : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::Failed(a) => { - // println!("Failed to promote : {a} ; "); - let outmsg = &format!("PoroSad failed to promote : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - // Log::flush(); - // let outmsg = "PoroSad failed to promote : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::NoChange(a) => { - // println!("No Changes Made : {a} ; "); - let outmsg = &format!("uuh No Change in Promotion : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - // let outmsg = "uuh No Promotion Change : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - - } - - } else if trgusrroles.contains(&UserRole::Broadcaster) // This should always be NoChange - { - botinstance::botlog::trace(&format!("Attempting promote..."), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - - // broadcaster & botadmins can make mods into superadmins - let ta = idlock.promote(arg1.to_string().to_lowercase(), - Some(ChType::Channel(msg.channel_login.to_lowercase())), - Some(UserRole::Mod(ChType::Channel(msg.channel_login.to_lowercase())))).await; - - match ta { - ChangeResult::Success(a) => { - // println!("Succesfully promoted : {a} ;"); - let outmsg = &format!("Successful Promotion : {a}"); - botinstance::botlog::debug(&format!("Successful Promotion : {a}"), - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - // let outmsg = "o7 Successfully promoted : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::Failed(a) => { - // println!("Failed to promote : {a} ; "); - let outmsg = &format!("PoroSad failed to promote : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - // Log::flush(); - // let outmsg = "PoroSad failed to promote : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - ChangeResult::NoChange(a) => { - // println!("No Changes Made : {a} ; "); - let outmsg = &format!("uuh No Change in Promotion : {a}"); - botinstance::botlog::debug(outmsg, - Some("identity.rs > cmd_prommote()".to_string()), Some(&msg)); - Log::flush(); - // let outmsg = "uuh No Promotion Change : ".to_string(); - bot.read().await.botmgrs.chat.say_in_reply_to(&msg, outmsg.to_string()).await; - }, - - } - } - - else { - let s = botlog::fatal("Reached unreachable else", - Some("identity > cmd_promote()".to_string()), Some(&msg)); - panic!("{}",s); - }; - - Log::flush(); - - } - _ => (), - } - - - - let arg2 = argv.next(); - - let targetchnl = arg2; - - */ - - botinstance::botlog::trace( - &format!("End of cmd_promote()"), + botlog::trace( + // &format!("End of cmd_promote()"), + "End of cmd_promote()", Some("identity.rs > cmd_prommote()".to_string()), None, ); } - // BotCommand { - // module : BotModule(String::from("identity")), - // command : String::from("demote"), // command call name - // alias : vec![], // String of alternative names - // exec_body : actions_util::asyncbox(cmd_demote) , - // help : String::from("demote"), - // required_roles : vec![ - // UserRole::Mod(ChType::Channel(String::new())), - // UserRole::SupMod(ChType::Channel(String::new())), - // UserRole::Broadcaster, - // UserRole::BotAdmin, - // ], - // }.add_to_modmgr(Arc::clone(&mgr)); - let tempb = BotCommand { module: BotModule(String::from("identity")), command: String::from("demote"), // command call name @@ -518,10 +211,8 @@ pub async fn init(mgr: Arc) { tempb.add_to_modmgr(Arc::clone(&mgr)).await; - // async fn cmd_demote(mut _chat:Arc>,_msg:PrivmsgMessage) { - async fn cmd_demote(mut bot: BotAR, msg: PrivmsgMessage) { - // println!("Called cmd demote"); - botinstance::botlog::debug( + async fn cmd_demote(bot: BotAR, msg: PrivmsgMessage) { + botlog::debug( "Called cmd demote", Some("identity.rs > cmd_demote()".to_string()), Some(&msg), @@ -554,20 +245,10 @@ pub async fn init(mgr: Arc) { */ - // [ ] #TODO : Need to define the body that calls demote() - // [x] Unwraps arguments from message - // let mut argv = msg.message_text.split(" "); - - // argv.next(); // Skip the command name - - // let arg1 = argv.next(); - - // let arg2 = argv.next(); - - let (arg1, arg2) = { - let mut argv = msg.message_text.split(" "); + let (arg1, _arg2) = { + let mut argv = msg.message_text.split(' '); argv.next(); // Skip the command name @@ -578,47 +259,26 @@ pub async fn init(mgr: Arc) { (arg1, arg2) }; - /* - let mut sender_badge:Option = None; - - for b in &msg.badges { - if b.name == "moderator" { - sender_badge = Some(ChatBadge::Mod); - } else if b.name == "broadcaster" { - sender_badge = Some(ChatBadge::Broadcaster); - } - } - */ - // --- /* - => 2024.02.15 - The business logic seems embeded straight into demote() with the following in mind : - - demote() atm doesn't take sender ChatBadge <-- the assumption is canuserrun() was done - for this user, and automatically assigned any roles that should get auto assigned - - demote() returns a ChangeResult + - [x] 1. Parse out the following + - Sender (e.g., Name & Badge) + - Target User (arg1) + - Target Channel (current channel) + - Msg or Msg.Message_Text (for later) - - [ ] So I think all I need to do here is parse out and pass input args to demote(), and output quirky messages based on ChangeResult - - - [x] 1. Parse out the following - - Sender (e.g., Name & Badge) - - Target User (arg1) - - Target Channel (current channel) - - Msg or Msg.Message_Text (for later) - - - [x] 2. Run Demote() - - within demote(), getspecialuserroles() is called on both the sender and the target - - getspecialuserroles() only sends current db , while canuserrun() may change db depending on the most current state of the sender - - getspecialuserroles also borrows the sender's badge to evaluate - - - [ ] 3. Take ChangeResult and output response + - [x] 2. Run Demote() + - within demote(), getspecialuserroles() is called on both the sender and the target + - getspecialuserroles() only sends current db , while canuserrun() may change db depending on the most current state of the sender + - getspecialuserroles also borrows the sender's badge to evaluate + - [x] 3. Take ChangeResult and output response */ /* - - [x] 1. Parse out the following - Sender (e.g., Name & Badge) - Target User (arg1) @@ -663,8 +323,9 @@ pub async fn init(mgr: Arc) { let rslt = match targetusr { Some(targetusr) => { - botinstance::botlog::debug( - &format!("running demote()"), + botlog::debug( + // &format!("running demote()"), + "running demote()", Some("identity.rs > cmd_demote()".to_string()), None, ); @@ -681,8 +342,9 @@ pub async fn init(mgr: Arc) { } None => { - botinstance::botlog::debug( - &format!("No Targer User argument"), + botlog::debug( + // &format!("No Targer User argument"), + "No Targer User argument", Some("identity.rs > cmd_demote()".to_string()), None, ); @@ -698,92 +360,29 @@ pub async fn init(mgr: Arc) { */ - // let senderUserRole = { - - // // note : getspecialuserroles will cover : - // // - Internal roles stored at db for Mod & SupMod & BotAdmin - // // - Broadcaster (based on target hchatter & channel) - // // It MAY NOT COVER sutations where Sender has a Mod Badge, but not in DB yet as Mod - // // - So ideally this covers that (at least returns that they're a mod and go ahead and run for now) - // // - [ ] #TODO : This should also go ahead and add that mod to DB if possible as channel mod - - // // let evalroles = vec![]; - - // let evalroles = match sender_badge { - - // Some(ChatBadge::Mod) => { - - // let mut rslroles = idlock.getspecialuserroles( - // sendername.clone(), - // Some(ChType::Channel(targetchnl.clone()))).await; - - // rslroles.push(UserRole::Mod(ChType::Channel(targetchnl))); - - // rslroles - // }, - // _ => { - // idlock.getspecialuserroles( - // sendername, - // Some(ChType::Channel(targetchnl.clone()))).await - // } - // }; - - // // => 02.16 - I think better would just migrate over the logic within demote - // // - If there's business reqs to evaluate , better to keep the ChangeResult - // // consistent and also pass ChatBadge - - // }; // senderUserRole - - match rslt { + let outmsg = match rslt { ChangeResult::Success(a) => { - // println!("Succesfully promoted : {a} ;"); - let outmsg = &format!("o7 Successfully demoted : {a}"); - botinstance::botlog::debug( - outmsg, - Some("identity.rs > cmd_demote()".to_string()), - Some(&msg), - ); - // let outmsg = "o7 Successfully promoted : ".to_string(); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + format!("o7 Successfully demoted : {a}") } ChangeResult::Failed(a) => { - // println!("Failed to promote : {a} ; "); - let outmsg = &format!("PoroSad failed to demote : {a}"); - botinstance::botlog::debug( - outmsg, - Some("identity.rs > cmd_demote()".to_string()), - Some(&msg), - ); - // let outmsg = "PoroSad failed to promote : ".to_string(); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + format!("PoroSad failed to demote : {a}") } ChangeResult::NoChange(a) => { - // println!("No Changes Made : {a} ; "); - let outmsg = &format!("uuh No Demotion Change : {a}"); - botinstance::botlog::debug( - outmsg, - Some("identity.rs > cmd_demote()".to_string()), - Some(&msg), - ); - // let outmsg = "uuh No Promotion Change : ".to_string(); - botlock - .botmgrs - .chat - .say_in_reply_to(&msg, outmsg.to_string()) - .await; + format!("uuh No Demotion Change : {a}") } - } + }; - // println!("tester"); - // println!("tester2"); + botlog::debug( + outmsg.as_str(), + Some("identity.rs > cmd_demote()".to_string()), + Some(&msg), + ); + + botlock + .botmgrs + .chat + .say_in_reply_to(&msg, outmsg.to_string()) + .await; } let tempcomm = BotCommand { @@ -802,10 +401,8 @@ pub async fn init(mgr: Arc) { tempcomm.add_to_modmgr(Arc::clone(&mgr)).await; - // async fn getroles(bot:Arc>,msg:PrivmsgMessage) { async fn getroles(bot: BotAR, msg: PrivmsgMessage) { - // println!("Called cmd getroles"); - botinstance::botlog::debug( + botlog::debug( "Called cmd getroles", Some("identity.rs > cmd_getroles()".to_string()), Some(&msg), @@ -819,100 +416,29 @@ pub async fn init(mgr: Arc) { */ - // IN other code areas , I see this - // ServerMessage::Privmsg(msg) => { - // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); - - // println!("{}",msg.message_text); - let mut argv = msg.message_text.split(" "); - - // for v in argv { - // println!("args : {v}"); - // } + let mut argv = msg.message_text.split(' '); argv.next(); // Skip the command name let arg1 = argv.next(); - // if arg == None { - // return ; // Do nothing if no arguments - // } - let targetuser = match arg1 { None => return, // exit if no arguments Some(arg) => arg, }; - // match String::from(arg1) { - // a if a == String::from("admin") => (), - // _ => (), - // } - - // match argv[1] { - // String::from("admin") => (), - - // } - let arg2 = argv.next(); let targetchnl = arg2; - // // let a = bot.read().ok().unwrap().get_identity(); - // let a = bot.lock().await; - // // let a = a.lock().await; - // // let a = a.get_identity().await; - // let a = a.botmgrs; - // // let a = *(*a).lock().await; - // let a = *a.lock().await; - // let a = a.identity; - // let a = *a.lock().await; - - // let a = bot.clone(); - // let a = a.into_inner(); - // let a = a.botmgrs; - // let a = a.into_inner(); - // let a = a.identity; - // let a = a.into_inner(); - // let a = bot.clone(); - // let a = a.lock().await; - // let a = a.get_identity(); - // let a = a.lock().await; - // let a = bot.get_identity(); let botlock = bot.read().await; - // println!("botlock read"); - botinstance::botlog::trace( - "botlock read", - Some("identity.rs > init > getroles()".to_string()), - Some(&msg), - ); - let idlock = botlock.get_identity(); - // println!("got identity"); - botinstance::botlog::trace( - "got identity", - Some("identity.rs > init > getroles()".to_string()), - Some(&msg), - ); - let idlock = idlock.read().await; // <-- 02.12 - Latest where it gest stuck - before or at this point - // println!("id lock"); - botinstance::botlog::trace( - "id lock", - Some("identity.rs > init > getroles()".to_string()), - Some(&msg), - ); + + let id = botlock.get_identity(); + + let idlock = id.read().await; + let sproles = match targetchnl { None => { - // let bot = Rc::clone(&bot); - //let bot = Arc::clone(&bot); - // let a = bot.botmgrs.identity.getspecialuserroles(String::from(targetuser),None); - // let a = Arc::try_unwrap(bot).ok().unwrap().into_inner().ok().unwrap(); - // let a = Arc::try_unwrap(bot.clone()).ok().unwrap().into_inner(); - // let a = a.botmgrs.identity.getspecialuserroles(String::from(targetuser),None); - // let a = a.ok().getspecialuserroles(String::from(targetuser),None); - // let a = bot.read().ok().unwrap().rIdentity().getspecialuserroles(String::from(targetuser),None); - // println!("Retrieved User Roles >> {:?}",a); - // let a = idlock.read().await; - // idlock.getspecialuserroles(String::from(targetuser),None).await - // [ ] If targetchnl is not provided, default to pulling the current channel idlock .getspecialuserroles( @@ -922,56 +448,19 @@ pub async fn init(mgr: Arc) { .await } Some(targetchnl) => { - // let bot = Rc::clone(&bot); - // let bot = Arc::clone(&bot); - // let a = bot.botmgrs.identity.getspecialuserroles(String::from(targetuser), Some(ChType::Channel(String::from(targetchnl)))); - // Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner() - // let a = Arc::try_unwrap(bot).ok().unwrap().into_inner().ok().unwrap(); - // let a = Arc::try_unwrap(bot.clone()).ok().unwrap().into_inner(); - // let a = a.botmgrs.identity.getspecialuserroles(String::from(targetuser), Some(ChType::Channel(String::from(targetchnl)))); - // let a = bot.read().ok().unwrap().rIdentity().getspecialuserroles(String::from(targetuser),None); - // println!("Retrieved User Roles >> {:?}",a); - // bot.read().ok().unwrap().rIdentity().getspecialuserroles(String::from(targetuser),None) - // let a = a.read().await; - - // [ ] If caller is not a BotAdmin, they can only pull those related to the current channel for the target user - // [ ] If caller is a BotAdmin, allow & return for target channel - // let mut sender_badge:Option = None; - - // for b in &msg.badges { - // if b.name == "moderator" { - // sender_badge = Some(ChatBadge::Mod); - // } else if b.name == "broadcaster" { - // sender_badge = Some(ChatBadge::Broadcaster); - // } - // } - - // match sender_badge { - // Some(ChatBadge::Mod) => { - - // } , - // Some(ChatBadge::Broadcaster) => { - - // } - // _ => { - - // } - // } - - // [x]gets special roles for caller + // [x] gets special roles for caller let callersproles = idlock .getspecialuserroles( msg.sender.name.to_lowercase(), Some(ChType::Channel(targetchnl.to_lowercase().to_string())), ) .await; - // idlock.getspecialuserroles(String::from(targetuser),Some(ChType::Channel(targetchnl.to_lowercase().to_string()))).await - // let a = callersproles.contains(&UserRole::Mod(ChType::Channel(targetchnl.to_lowercase().to_string()))); + if callersproles.contains(&UserRole::Mod(ChType::Channel( targetchnl.to_lowercase().to_string(), ))) || callersproles.contains(&UserRole::SupMod(ChType::Channel( targetchnl.to_lowercase().to_string(), - ))) || callersproles.contains(&&UserRole::Broadcaster) + ))) || callersproles.contains(&UserRole::Broadcaster) { idlock .getspecialuserroles( @@ -979,7 +468,6 @@ pub async fn init(mgr: Arc) { Some(ChType::Channel(targetchnl.to_lowercase())), ) .await - // callersproles } else { // Otherwise, don't get the target channel, return the current channel instead idlock @@ -992,41 +480,34 @@ pub async fn init(mgr: Arc) { } }; - // let sproles = idlock.getspecialuserroles(String::from(targetuser),).await; - - // println!("Retrieved User Roles >> {:?}",sproles); - botinstance::botlog::debug( + botlog::debug( &format!("User roles of Target Chatter >> {:?}", sproles), Some("identity.rs > init > getroles()".to_string()), Some(&msg), ); - // # I believe at this stage I still have botlock active - - botinstance::botlog::debug( - &format!("Evaluating special roles"), + botlog::trace( + // &format!("Evaluating special roles"), + "Evaluating special roles", Some("identity.rs > init > getroles()".to_string()), Some(&msg), ); - // let mut outmsg = String::new(); - - //let sproles = sproles; - // let arg2 = arg2.unwrap(); - let outmsg = if ((targetuser.to_lowercase() == msg.channel_login.to_lowercase()) && arg2.is_none()) || (arg2.is_some() && arg2.unwrap() == targetuser.to_lowercase()) { // First evaluates if they're broadcaster - let mut outmsg = format!("FeelsWowMan they're the broadcaster. "); + + let mut outmsg = "FeelsWowMan they're the broadcaster. ".to_string(); + if sproles.contains(&UserRole::Mod(ChType::Channel( msg.channel_login.to_lowercase(), ))) || sproles.contains(&UserRole::SupMod(ChType::Channel( msg.channel_login.to_lowercase(), ))) || sproles.contains(&UserRole::BotAdmin) { - outmsg = outmsg + &format!("Target chatter's user roles are : {:?}", sproles); + outmsg += format!("Target chatter's user roles are : {:?}", sproles).as_str(); } outmsg } else if sproles.contains(&UserRole::Mod(ChType::Channel( @@ -1037,61 +518,21 @@ pub async fn init(mgr: Arc) { { format!("Target chatter's user roles are : {:?}", sproles) } else { - format!("Target chatter has no special roles LULE ") + "Target chatter has no special roles LULE ".to_string() }; - // if sproles.contains(&UserRole::Mod(msg.channel_login.to_lowercase())) { - - // } else if sproles.contains(&UserRole::Mod(msg.channel_login.to_lowercase())) { - - // } - - // let outmsg = match sproles - // { - - // // let mut outmsg = String::new(); - // Some(sproles) => { - - // let sproles = sproles.read().await; - - // format!("Target chatter's user roles are : {:?}",sproles) - - // } - // None => { - // // # NOTE : Broadcaster could be included in this - - // // # below is checking if the provided text includes the username - // // let msg = msg.message_text.to_lowercase().contains(&msg.channel_login.to_lowercase()); - // botinstance::botlog::debug(&format!("Evaluating special roles > channel login : {} ; message text : {} ; ",&msg.channel_login,&msg.message_text), - // Some("identity.rs > init > getroles()".to_string()), Some(&msg)); - // botinstance::botlog::debug(&format!("Evaluating special roles > bool evaluation : {} ", - // msg.message_text.to_lowercase().contains(&msg.channel_login.to_lowercase())), - // Some("identity.rs > init > getroles()".to_string()), Some(&msg)); - - // if msg.message_text.to_lowercase().contains(&msg.channel_login.to_lowercase()) { - // format!("FeelsWowMan they're the broadcaster ") - // } else { - // format!("Target chatter has no special roles LULE ") - // } - - // } - - // }; - // let a = bot.identity.getuserroles(String::from("ModulatingForce"), Some(ChType::Channel(String::from("ModulatingForcebot")))); - // println!("{:?}",a); - - botinstance::botlog::debug( - &format!("Chat Say Reply message : {:?}", outmsg), + botlog::debug( + format!("Chat Say Reply message : {}", outmsg).as_str(), Some("identity.rs > init > getroles()".to_string()), Some(&msg), ); + botlock.botmgrs.chat.say_in_reply_to(&msg, outmsg).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 } - // println!("End of Init MOdule add"); - botinstance::botlog::trace( + botlog::trace( "End of Init MOdule add", Some("identity.rs > init ".to_string()), None, @@ -1100,11 +541,6 @@ pub async fn init(mgr: Arc) { Log::flush(); } -// #[derive(Debug, PartialEq, Eq, Hash, Clone)] -// pub enum ChType { -// Channel(String), -// } - #[derive(Debug, PartialEq, Eq, Clone)] pub enum UserRole { Chatter, @@ -1119,29 +555,17 @@ pub enum Permissible { Block, } +type UserRolesDB = HashMap>>>; + #[derive(Clone)] pub struct IdentityManager { - // special_roles_users : HashMap>, // # <-- (!) This must be String instead of ChType because we're checking a User not a Channel - // special_roles_users : Arc>>>, // # <-- (!) This must be String instead of ChType because we're checking a User not a Channel - // special_roles_users : Arc>>>, - special_roles_users: Arc>>>>>, - // parent_mgr : Box, - //parent_mgr : Option>, + special_roles_users: Arc>, } /* HashMap< String, <-- Chatter / Username Vec -- <-- Vectors are basically arrays > - - -- [ ] - let a = vec![] - - modulatingforce : vec![UserRole::BotAdmin, - UserRole::Mod(ChType::Channel("modulatingforcebot"))] - modulatingforce : vec![UserRole::BotAdmin, - UserRole::Mod(ChType::Channel("modulatingforcebot"))] - */ #[derive(Debug)] @@ -1169,7 +593,6 @@ impl IdentityManager { IdentityManager { special_roles_users: Arc::new(RwLock::new(a)), - //parent_mgr : None, } } @@ -1192,7 +615,6 @@ impl IdentityManager { .await; if let Some(indx) = usrrolelock.iter().position(|value| *value == trg_role) { usrrolelock.swap_remove(indx); - //return ChangeResult::Success("Demoted successfully".to_string()) } } @@ -1201,7 +623,7 @@ impl IdentityManager { srulock .entry(trgchatter.clone()) .or_insert(Arc::new(RwLock::new(vec![]))); - botinstance::botlog::trace( + botlog::trace( &format!( "Ensuring User in Roles {:?}", srulock.entry(trgchatter.clone()) @@ -1214,22 +636,18 @@ impl IdentityManager { // [ ] Maybe I should create a can_user_run version that simply takes PrvMsg, but then calls can_user_run directly - // pub fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Result> - // pub fn can_user_run_PRVMSG(&self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Permissible - // pub async fn can_user_run_PRVMSG(self,msg:&PrivmsgMessage,cmdreqroles:Vec) -> Permissible - pub async fn can_user_run_PRVMSG( + pub async fn can_user_run_prvmsg( &mut self, msg: &PrivmsgMessage, cmdreqroles: Vec, ) -> (Permissible, ChangeResult) { - // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); - // [ ] Check what Badges in PrivmsgMessage - // println!{"Checking within PRVMSG"}; - botinstance::botlog::debug( + + botlog::trace( "Checking within PRVMSG", Some("identity.rs > can_user_run_PRVMSG()".to_string()), - Some(&msg), + // Some(&msg), + Some(msg), ); let mut sender_badge: Option = None; @@ -1312,7 +730,7 @@ impl IdentityManager { cmdreqroles: Vec, // ) -> Result> { ) -> (Permissible, ChangeResult) { // println!{"Checking within can_user_run()"}; - botinstance::botlog::debug( + botlog::debug( &format!( "Checking within can_user_run() : usr : {} ; channel : {:?} ; badge : {:?} ; cmdreqroles : {:?}", @@ -1362,7 +780,8 @@ impl IdentityManager { let usr = usr.to_lowercase(); - if cmdreqroles.len() == 0 { + // if cmdreqroles.len() == 0 { + if cmdreqroles.is_empty() { // return Ok(Permissible::Allow) return ( Permissible::Allow, @@ -1393,48 +812,19 @@ impl IdentityManager { // [x] Check if they have either UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) // [x] If not, assign them UserRole::Mod(channelname::ChType) Some(ChatBadge::Mod) => { - // println!("Mod Chatbadge detected"); - botinstance::botlog::info( + botlog::info( "Mod Chatbadge detected", Some("identity.rs > can_user_run()".to_string()), None, ); - // println!("debug special roles : {:?}",self.special_roles_users); - // println!("debug usr : {}",&usr.to_lowercase()); + let rolesdb = Arc::clone(&self.special_roles_users); - // let Some((k,v)) = self.special_roles_users.get_key_value(usr); - // match self.special_roles_users.get_mut(&usr.to_lowercase()) { - // match self.special_roles_users.get(&usr.to_lowercase()) { - // println!("Creating clone"); - botinstance::botlog::trace( - "Creating arc clone", - Some("identity.rs > can_user_run()".to_string()), - None, - ); - - let roleslock = Arc::clone(&(*self).special_roles_users); - - // println!("Read lock on : Special_Roles_User"); // <-- after this is slightly different between working and problem - botinstance::botlog::trace( - "Read lock on : Special_Roles_User", - Some("identity.rs > can_user_run()".to_string()), - None, - ); - - // { - - // // If target user doesn't exist in special_roles_users , add with blank vector roles - // let mut srulock = self.special_roles_users.write().await; - // srulock.entry(usr.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - // botinstance::botlog::trace(&format!("Ensuring Chatter in Roles {:?}",srulock.entry(usr.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } self.affirm_chatter_in_db(usr.clone()).await; - let mut roleslock = roleslock.write().await; - match (*roleslock).get(&usr.to_lowercase()) { + let rolesdb_lock = rolesdb.write().await; + + match (*rolesdb_lock).get(&usr.to_lowercase()) { Some(usrroles) if usrroles .read() @@ -1445,46 +835,25 @@ impl IdentityManager { .await .contains(&UserRole::SupMod(channelname.clone())) => { - // <-- working got to this point - // println!("contains mod : {}", usrroles.read().await.contains(&UserRole::Mod(channelname.clone()))); - // println!("contains supmod : {}", usrroles.read().await.contains(&UserRole::SupMod(channelname.clone()))); - // Do nothing when theh have a mod badge and have either a supmod or mod badge for the channel - // println!("Already a mod in roles"); - botinstance::botlog::trace( + botlog::trace( "Already a mod in roles", Some("identity.rs > can_user_run()".to_string()), None, ); } + _ => { // In the event they have a mod badge , are running a bot command, but don't have a channel mod role yet... - // println!("lock created > adding with a mod role o7"); - botinstance::botlog::trace( - "lock created > adding with a mod role o7", - Some("identity.rs > can_user_run()".to_string()), - None, - ); - // botinstance::botlog::notice("Assigning ModRole to Chatter", - // Some("identity.rs > can_user_run()".to_string()), None); + let mut rolesdb_lock_mut = rolesdb_lock; + let usrroles = rolesdb_lock_mut.get_mut(&usr.to_lowercase()).unwrap(); + let mut usrroles_lock = usrroles.write().await; - let mut roleslock = roleslock; - let mut a = roleslock.get_mut(&usr.to_lowercase()).unwrap(); - let mut alock = a.write().await; - - alock.push(UserRole::Mod(channelname.clone())); + usrroles_lock.push(UserRole::Mod(channelname.clone())); modrolechange = ChangeResult::Success("Auto Promoted Mod".to_string()); - - // alock.get_mut(&usr.to_lowercase()) - // .get_or_insert_with(|| UserRole::Mod(channelname.clone())) - // // .expect("ERROR") - // .unwrap() - // .write().await - // // .get_mut() - // .push(UserRole::Mod(channelname.clone())); - } // <-- I'm assuming problem got to here + } } } _ => (), // Don't handle other roles here @@ -1492,35 +861,26 @@ impl IdentityManager { // [x] If cmdreqroles includes UserRole::Mod("") , checks if chatter has UserRole::Mod(channelname::ChType) or UserRole::SupMod(channelname::ChType) to determine if Ok(Permissible::Allow) - // println!("cmd required roles : {:?}",cmdreqroles); - botinstance::botlog::trace( + botlog::trace( &format!("cmd required roles : {:?}", cmdreqroles), Some("identity.rs > can_user_run()".to_string()), None, ); if cmdreqroles.contains(&UserRole::Mod(ChType::Channel(String::new()))) { - // match self.special_roles_users.get(&channelname) { - // Some(usrroles) => {}, - // None => (), - - // } - - // println!("Command requires Mod Role"); - botinstance::botlog::trace( + botlog::trace( "Command requires Mod Role", Some("identity.rs > can_user_run()".to_string()), None, ); - if let Some(a) = (&*self) + if let Some(a) = self .special_roles_users .read() .await .get(&usr.to_lowercase()) { - // println!("Special roles found for user"); - botinstance::botlog::trace( + botlog::trace( "Special roles found for user", Some("identity.rs > can_user_run()".to_string()), None, @@ -1531,9 +891,7 @@ impl IdentityManager { .await .contains(&UserRole::SupMod(channelname.clone())) { - // return Ok(Permissible::Allow); - // println!("Special roles found for user : A mod idenfified "); - botinstance::botlog::trace( + botlog::trace( "> Special Role Identified : Mod ", Some("identity.rs > can_user_run()".to_string()), None, @@ -1546,7 +904,7 @@ 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(ChType::Channel(String::new()))) { - if let Some(a) = (&*self) + if let Some(a) = self .special_roles_users .read() .await @@ -1556,7 +914,6 @@ impl IdentityManager { .await .contains(&UserRole::SupMod(channelname.clone())) { - // return Ok(Permissible::Allow); return (Permissible::Allow, modrolechange); } } @@ -1564,8 +921,7 @@ impl IdentityManager { // [x] If cmdreqroles includes UserRole::BotAdmin and chatter has UserRole::BotAdmin , Ok(Permissible::Allow) - // println!("Eval cmdreqroles with botadmin : {}",cmdreqroles.contains(&UserRole::BotAdmin)); - botinstance::botlog::trace( + botlog::trace( &format!( "Eval cmdreqroles with botadmin : {}", cmdreqroles.contains(&UserRole::BotAdmin) @@ -1575,41 +931,36 @@ impl IdentityManager { ); if cmdreqroles.contains(&UserRole::BotAdmin) { - // println!("special roles get : {:?}",(&*self).special_roles_users.read().await.get(&usr.to_lowercase())); - botinstance::botlog::trace( - &format!( + botlog::trace( + format!( "special roles get : {:?}", - (&*self) - .special_roles_users + self.special_roles_users .read() .await .get(&usr.to_lowercase()) - ), + ) + .as_str(), Some("identity.rs > can_user_run()".to_string()), None, ); - if let Some(a) = (&*self) + if let Some(a) = (self) .special_roles_users .read() .await .get(&usr.to_lowercase()) { - println!( - "special roles contains BotAdmin: {}", - a.read().await.contains(&UserRole::BotAdmin) - ); - botinstance::botlog::trace( - &format!( + botlog::trace( + format!( "special roles contains BotAdmin: {}", a.read().await.contains(&UserRole::BotAdmin) - ), + ) + .as_str(), Some("identity.rs > can_user_run()".to_string()), None, ); if a.read().await.contains(&UserRole::BotAdmin) { - // return Ok(Permissible::Allow); return (Permissible::Allow, modrolechange); } } @@ -1621,7 +972,6 @@ impl IdentityManager { ) } - // pub async fn promote(&mut self,trgchatter:String,channel:Option,trg_role:Option) -> ChangeResult { pub async fn promote( &self, authorizer: String, @@ -1630,7 +980,7 @@ impl IdentityManager { channel: Option, trg_role: Option, ) -> ChangeResult { - botinstance::botlog::trace( + botlog::trace( &format!( "IN VARS for promote() : auth : {} ; authbadge : {:?} ; trg : {} ; Channel {:?} ; {:?}", authorizer,authorizer_badge,trgchatter,channel,trg_role), @@ -1663,27 +1013,13 @@ impl IdentityManager { .await; { - // mut block - - // let authusrroles_mut = &mut authusrroles; - // [x] Add Mod(channel) to authusrroles - // [x] #TODO also add to DB if possible? match *authorizer_badge { Some(ChatBadge::Mod) if (!authusrroles.contains(&UserRole::Mod(channel.clone())) && !authusrroles.contains(&UserRole::SupMod(channel.clone()))) => { - // (*authusrroles_mut).push(UserRole::Mod(channel.clone())); authusrroles.push(UserRole::Mod(channel.clone())); - // let mut srulock = self.special_roles_users.write().await; - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - // .write().await - // .push(UserRole::Mod(channel.clone())); - self.affirm_chatter_in_db(authorizer.clone()).await; self.add_role(authorizer.clone(), UserRole::Mod(channel.clone())) .await; @@ -1691,7 +1027,7 @@ impl IdentityManager { _ => (), } - } // mut block + } // [x] 2. Get Authorizer & Target Chatter Roles @@ -1701,12 +1037,13 @@ impl IdentityManager { (authusrroles, trgusrroles) } else { - let mut authusrroles = self + let authusrroles = self .getspecialuserroles(authorizer.to_lowercase().clone(), None) .await; let trgusrroles = self .getspecialuserroles(trgchatter.to_lowercase().clone(), None) .await; + (authusrroles, trgusrroles) }; @@ -1720,29 +1057,8 @@ impl IdentityManager { if trgusrroles.contains(&UserRole::BotAdmin) { return ChangeResult::NoChange("Already has the role".to_string()); } else { - // { - // let mut srulock = self.special_roles_users.write().await; - - // srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - // botinstance::botlog::trace(&format!("Ensuring Target Chatter in Roles > {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } self.affirm_chatter_in_db(trgchatter.clone()).await; - // { - - // let mut srulock = self.special_roles_users.write().await; - - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles for the user") - // .write().await - // .push(UserRole::BotAdmin); // <-- Adds the specific role - // botinstance::botlog::trace(&format!("Inserting Role > {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } self.add_role(trgchatter.clone(), UserRole::BotAdmin).await; return ChangeResult::Success("Promotion Successful".to_string()); @@ -1762,14 +1078,6 @@ impl IdentityManager { - NOTE : We do not validate trg_role here - app logic requires you to promote 1 to Mod and 1 more to SupMod */ - // let authhasnsreqroles = match channel.clone() { - - // Some(channel) => authusrroles.contains(&UserRole::SupMod(channel.clone())) || - // authusrroles.contains(&UserRole::BotAdmin) || - // authusrroles.contains(&UserRole::Broadcaster) , - // None => authusrroles.contains(&UserRole::BotAdmin), - // }; - if let Some(trg_chnl) = channel.clone() { if !trgusrroles.contains(&UserRole::Broadcaster) && !trgusrroles.contains(&UserRole::Mod(trg_chnl.clone())) @@ -1783,43 +1091,20 @@ impl IdentityManager { || authusrroles.contains(&UserRole::Broadcaster) || authusrroles.contains(&UserRole::BotAdmin) { - // { - - // // If target user doesn't exist in special_roles_users , add with blank vector roles - // let mut srulock = self.special_roles_users.write().await; - // srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - // botinstance::botlog::trace(&format!("Ensuring Chatter in Roles {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } self.affirm_chatter_in_db(trgchatter.clone()).await; - // { - // // promote target after - // let mut srulock = self.special_roles_users.write().await; - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // .write().await - // .push(UserRole::Mod(trg_chnl.clone())); // Role to Add - // botinstance::botlog::trace(&format!("Adding Roles to Chatter {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } self.add_role(trgchatter.clone(), UserRole::Mod(trg_chnl.clone())) .await; return ChangeResult::Success(String::from("Promotion Successful")); - } - // Other else conditions would be mostly spcecial responses like ChangeResult::NoChange or ChangeResult::Fail - // related to authusrroles - else { + } else { + // Other else conditions would be mostly spcecial responses like ChangeResult::NoChange or ChangeResult::Fail + // related to authusrroles return ChangeResult::Failed(String::from("You're not permitted to do that")); } } else if !trgusrroles.contains(&UserRole::Broadcaster) && trgusrroles.contains(&UserRole::Mod(trg_chnl.clone())) && !trgusrroles.contains(&UserRole::SupMod(trg_chnl.clone())) - // { // target user is a Mod && not broadcaster // target's Next Role would be SupMod @@ -1830,46 +1115,11 @@ impl IdentityManager { if authusrroles.contains(&UserRole::Broadcaster) || authusrroles.contains(&UserRole::BotAdmin) { - // { // Inserts user if doesn't exist - // let mut srulock = self.special_roles_users.write().await; - // srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - // botinstance::botlog::trace(&format!("Ensuring User in Roles {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } self.affirm_chatter_in_db(trgchatter.clone()).await; - // { // Adds the requested role for the user - // let mut srulock = self.special_roles_users.write().await; - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - // .write().await - // .push(UserRole::SupMod(trg_chnl.clone())); - // botinstance::botlog::trace(&format!("Adding Required Role > {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } - self.add_role(trgchatter.clone(), UserRole::SupMod(trg_chnl.clone())) .await; - // { // Removes the lower role (mod) from the user - // let mut srulock = self.special_roles_users.write().await; - // let mut uroleslock = srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // .write().await; - // if let Some(indx) = uroleslock.iter().position(|value| *value == UserRole::Mod(trg_chnl.clone())){ - // uroleslock.swap_remove(indx); - // } - - // botinstance::botlog::trace(&format!("Removing lower role > {:?}",uroleslock), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } - self.remove_role(trgchatter, UserRole::Mod(trg_chnl.clone())) .await; @@ -1885,347 +1135,21 @@ impl IdentityManager { return ChangeResult::Failed(String::from("Already highest available role")); } else { // since handling for channel is already done, will be handling other trguserroles situations here - // other situations includes : - /* - [-] targetuser is broadcaster >> no need - this was done earlier in the function - [?] ? - */ // At the moment, without any new roles, this should not be reached - botinstance::botlog::warn( - &format!("Code Warning : add handing for other trgusrroles"), + botlog::warn( + "Code Warning : add handing for other trgusrroles", Some("identity.rs > promote()".to_string()), None, ); + return ChangeResult::Failed(String::from("Code Warning")); } - - // let trghasreqroles = - - // { - - // // If target user doesn't exist in special_roles_users , add with blank vector roles - // let mut srulock = self.special_roles_users.write().await; - // srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - // botinstance::botlog::trace(&format!("Ensuring Chatter in Roles {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } - // { - // // promote target after - // let mut srulock = self.special_roles_users.write().await; - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - // .write().await - // .push(UserRole::Mod(trg_chnl.clone())); // Role to Add - // botinstance::botlog::trace(&format!("Adding Roles to Chatter {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } - - // return ChangeResult::Success(String::from("Promotion Successful")); }; - // if authhasnsreqroles { - - // { - - // // If target user doesn't exist in special_roles_users , add with blank vector roles - // let mut srulock = self.special_roles_users.write().await; - // srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - // botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } - // { - // // promote target after - // let mut srulock = self.special_roles_users.write().await; - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - // .write().await - // .push(UserRole::Mod(trg_chnl)); - // botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",srulock.entry(trgchatter.clone())), - // Some("identity.rs > promote()".to_string()), None); - // Log::flush(); - // } - - // return ChangeResult::Success(String::from("Promotion Successful")); - - // } - - // authusrroles.contains(&UserRole::Mod(())) - - /* - - - let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; - - - let rolemap = chatterroles; - - match trg_role { - Some(UserRole::Mod(_)) => { - - - if let Some(trg_chnl) = channel.clone() { - - // [ ] 1. If trg_role & trgchatter is a Mod or SupMod of the target channel, return NoChange - - let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; - let rolemap = chatterroles; - // let rolemap = rolemap.unwrap(); - if rolemap.contains(&UserRole::Mod(trg_chnl.clone())) { - return ChangeResult::NoChange(String::from("Target User already has Target Role")); - } else if rolemap.contains(&UserRole::Broadcaster) { - return ChangeResult::NoChange(String::from("No need to do that for broadcaster")); - } - - // # otherwise, trg_role for the given chnl is not assigned to the trgchatter - // chatterroles.push(UserRole::Mod(trg_chnl.clone())); - // let a = self.special_roles_users; - // let b = a.write().await; - // // let c = b.get_mut(&trgchatter); - // let c = (*b).; - - // [ ] 2. Ensure an entry in Special_Roles_user for trgchatter, and push Mod(Channel) for the Target User - - // [x] (!!) AROUND HERE - check if the user exists first, and at least add the user as we're promoting anyway - - { - - // If target user doesn't exist in special_roles_users , add with blank vector roles - let mut srulock = self.special_roles_users.write().await; - srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())), - Some("identity.rs > promote()".to_string()), None); - Log::flush(); - } - { - // promote target after - let mut srulock = self.special_roles_users.write().await; - srulock - .get_mut(&trgchatter) - .expect("Error getting roles") - // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - .write().await - .push(UserRole::Mod(trg_chnl)); - botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",srulock.entry(trgchatter.clone())), - Some("identity.rs > promote()".to_string()), None); - Log::flush(); - } - - return ChangeResult::Success(String::from("Promotion Successful")); - } - - - }, - Some(UserRole::SupMod(_)) => - { - if let Some(trg_chnl) = channel.clone() { - - // [ ] 1. If trg_role & trgchatter is a Mod or SupMod of the target channel, return NoChange - - let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; - let rolemap = chatterroles; - // let rolemap = rolemap.unwrap(); - if rolemap.contains(&UserRole::SupMod(trg_chnl.clone())) { - return ChangeResult::NoChange(String::from("Target User already has Target Role")); - } else if rolemap.contains(&UserRole::Broadcaster) { - return ChangeResult::NoChange(String::from("No need to do that for broadcaster")); - } - // # otherwise, trg_role for the given chnl is not assigned to the trgchatter - // chatterroles.push(UserRole::Mod(trg_chnl.clone())); - // let a = self.special_roles_users; - // let b = a.write().await; - // // let c = b.get_mut(&trgchatter); - // let c = (*b).; - - - // [ ] 2. Ensure an entry in Special_Roles_user for trgchatter, and push SupMod(Channel) for the Target User - - // [x] (!!) AROUND HERE - check if the user exists first, and at least add the user as we're promoting anyway - - { - let mut srulock = self.special_roles_users.write().await; - srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())), - Some("identity.rs > promote()".to_string()), None); - Log::flush(); - } - { - let mut srulock = self.special_roles_users.write().await; - srulock - .get_mut(&trgchatter) - .expect("Error getting roles") - // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - .write().await - .push(UserRole::SupMod(trg_chnl.clone())); - botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",srulock.entry(trgchatter.clone())), - Some("identity.rs > promote()".to_string()), None); - Log::flush(); - } - { - let mut srulock = self.special_roles_users.write().await; - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - // .write().await - // .(UserRole::Mod(trg_chnl)); - // let indx = srulock.iter().position() - let mut uroleslock = srulock - .get_mut(&trgchatter) - .expect("Error getting roles") - // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - .write().await; - if let Some(indx) = uroleslock.iter().position(|value| *value == UserRole::Mod(trg_chnl.clone())){ - uroleslock.swap_remove(indx); - } - - botinstance::botlog::trace(&format!("SRLOCK - 2st write > {:?}",uroleslock), - Some("identity.rs > promote()".to_string()), None); - Log::flush(); - } - - return ChangeResult::Success(String::from("Promotion Successful")); - } - } , - Some(UserRole::BotAdmin) => { - - - - let chatterroles = self.getspecialuserroles(trgchatter.clone(), channel.clone()).await; - let rolemap = chatterroles; - - botinstance::botlog::trace(&format!("Target Role : BotAdmin"), - Some("identity.rs > promote()".to_string()), None); - - // [x] 1. Check their roles first if they already have botadmin - // [x] 2. Know that prior to promote() , BotAdmins should have been validated before being able to pass the BotAdmin target - - // [x] 1. Check target chatter's roles first if they already have botadmin - botinstance::botlog::trace(&format!("Eval rolemap.contains(BotAdmin) : {}",rolemap.contains(&UserRole::BotAdmin)), - Some("identity.rs > promote()".to_string()), None); - - botinstance::botlog::trace(&format!("Eval rolemap.contains(BotAdmin) > Rolemap : {:?}",rolemap), - Some("identity.rs > promote()".to_string()), None); - - // [ ] (!) This seems to be an issue - rolemap by this point is blank - if rolemap.contains(&UserRole::BotAdmin) { - return ChangeResult::NoChange(String::from("Target User already has Target Role")); - } - // # otherwise, trg_role for the given chnl is not assigned to the trgchatter - // chatterroles.push(UserRole::Mod(trg_chnl.clone())); - - // [x] (!!) AROUND HERE - check if the user exists first, and at least add the user as we're promoting anyway - - { - let mut srulock = self.special_roles_users.write().await; - - srulock.entry(trgchatter.clone()).or_insert(Arc::new(RwLock::new(vec![]))); - botinstance::botlog::trace(&format!("SRLOCK - 1st write > {:?}",srulock.entry(trgchatter.clone())), - Some("identity.rs > promote()".to_string()), None); - Log::flush(); - } - - { - - let mut srulock = self.special_roles_users.write().await; - - srulock - .get_mut(&trgchatter) - // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - .expect("Error getting roles") - .write().await - .push(UserRole::BotAdmin); - botinstance::botlog::trace(&format!("SRLOCK - 2nd write > {:?}",srulock.entry(trgchatter.clone())), - Some("identity.rs > promote()".to_string()), None); - Log::flush(); - } - botinstance::botlog::trace(&format!("Target Role : BotAdmin >> Successful"), - Some("identity.rs > promote()".to_string()), None); - - return ChangeResult::Success(String::from("Promotion Successful")); - }, - Some(_) => { - botinstance::botlog::warn(&format!("Runtime reached undeveloped code"), - Some("identity.rs > promote()".to_string()), None); - }, - None => { - botinstance::botlog::warn(&format!("Runtime reached undeveloped code"), - Some("identity.rs > promote()".to_string()), None); - }, - } - - */ - - // match chatterroles { - // Some(chatterroles) => { - - // // [x] chatter already has the target role - // if chatterroles.contains(&trg_role) { - // return ChangeResult::NoChange(String::from("Target User already has Target Role")); - // } - - // // By this point, chatteroles does not contain target role - // // match trgRole { - // // Some(trgRole) => { - // // match trgRole { - // // UserRole::Mod(a) => { - - // // }, - // // UserRole::SupMod(a) => (), - // // UserRole::BotAdmin => (), - // // _ => (), // <-- do nothing with al other options - // // } - // // }, - // // None => { - // // /* - // // - If trgRole is None , then promote by implicit rules . For example, - // // - For UserRoles without Mod or SupMod & Caller is SupMod | Broadcaster | BotAdmin > To Mod - // // - For Mod & Caller is SupMod | Broadcaster | BotAdmin > To SupMod - // // - For UserRoles without BotAdmin & Caller is BotAdmin > To BotAdmin - // // */ - // // }, - - // // } - - // // let trgRole = match trgRole { - // // Some(UserRole::Mod(a)) => a, - // // Some(UserRole::SupMod(a)) => a, - // // Some(UserRole::BotAdmin) => UserRole::BotAdmin, - // // None => { - // // /* - // // - If trgRole is None , then promote by implicit rules . For example, - // // - For UserRoles without Mod or SupMod & Caller is SupMod | Broadcaster | BotAdmin > To Mod - // // - For Mod & Caller is SupMod | Broadcaster | BotAdmin > To SupMod - // // - For UserRoles without BotAdmin & Caller is BotAdmin > To BotAdmin - // // */ - // // }, - - // // }; - - // // if let Some(trgRole) = trgRole { - - // // // [x] chatter already has the target role - // // if chatterroles.contains(&trgRole) { - // // return ChangeResult::NoChange(String::from("Target User already has Target Role")); - // // } - - // // // [ ] trgRole should be assigned based on the input channel - // // let roletoassign = UserRole:: - // // } - - // }, - // _ => (), - // } - botinstance::botlog::warn( - &format!("Runtime reached undeveloped code"), + botlog::warn( + "Runtime reached undeveloped code", Some("identity.rs > promote()".to_string()), None, ); @@ -2238,11 +1162,8 @@ impl IdentityManager { authorizer_badge: &Option, trgchatter: String, channel: Option, - // trg_role:Option ) -> ChangeResult { - // botinstance::botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?} ; Targer Role {:?}", - // authorizer,trgchatter,channel,trg_role), - botinstance::botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?}", + botlog::trace(&format!("IN VARS for demote() : Authorizer : {:?} ; Target Chatter : {} ; Target Channel : {:?}", authorizer,trgchatter,channel), Some("identity.rs > demote()".to_string()), None); Log::flush(); @@ -2272,18 +1193,8 @@ impl IdentityManager { if (!authusrroles.contains(&UserRole::Mod(channel.clone())) && !authusrroles.contains(&UserRole::SupMod(channel.clone()))) => { - // (*authusrroles_mut).push(UserRole::Mod(channel.clone())); authusrroles.push(UserRole::Mod(channel.clone())); - // [ ] below pushes mod to authorizer - // let mut srulock = self.special_roles_users.write().await; - // srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // // !! [ ] Unsure what happens if promoting a chatter that doesn't exist at - // .write().await - // .push(UserRole::Mod(channel.clone())); - self.add_role(authorizer.clone(), UserRole::Mod(channel.clone())) .await; } @@ -2309,16 +1220,6 @@ impl IdentityManager { || authusrroles.contains(&UserRole::SupMod(channel.clone()))) && trgusrroles.contains(&UserRole::Mod(channel.clone())) { - // // [ ] Below removes Mod from trgchatter - // let mut srulock = self.special_roles_users.write().await; - // let mut usrrolelock = srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // .write().await; - // if let Some(indx) = usrrolelock.iter().position(|value| *value == UserRole::Mod(channel.clone())){ - // usrrolelock.swap_remove(indx); - // return ChangeResult::Success("Demoted successfully".to_string()) - // } self.remove_role(trgchatter.clone(), UserRole::Mod(channel.clone())) .await; return ChangeResult::Success("Demoted successfully".to_string()); @@ -2328,18 +1229,6 @@ impl IdentityManager { || authusrroles.contains(&UserRole::Broadcaster)) && trgusrroles.contains(&UserRole::SupMod(channel.clone())) { - // [ ] For Trgchatter, below pushes Mod UserRole and removes SupMod - // let mut srulock = self.special_roles_users.write().await; - // let mut usrrolelock = srulock - // .get_mut(&trgchatter) - // .expect("Error getting roles") - // .write().await; - // usrrolelock.push(UserRole::Mod(channel.clone())); // pushes Mod , and removes SupMod - // if let Some(indx) = usrrolelock.iter().position(|value| *value == UserRole::SupMod(channel.clone())){ - // usrrolelock.swap_remove(indx); - // return ChangeResult::Success("Demoted successfully".to_string()) - // } - self.add_role(trgchatter.clone(), UserRole::Mod(channel.clone())) .await; self.remove_role(trgchatter.clone(), UserRole::SupMod(channel.clone())) @@ -2360,13 +1249,12 @@ impl IdentityManager { } } - botinstance::botlog::warn(&format!("Potential Unhandled Demotion Condition : Consider explicitely adding in for better handling"), - Some("identity.rs > demote()".to_string()), None); + botlog::warn("Potential Unhandled Demotion Condition : Consider explicitely adding in for better handling", + Some("identity.rs > demote()".to_string()), None); Log::flush(); ChangeResult::Failed(String::from("Did not meet criteria to demote succesfully")) } - // pub async fn getspecialuserroles(&self,chattername:String,channel:Option) -> Option>>> { pub async fn getspecialuserroles( &self, chattername: String, @@ -2377,7 +1265,7 @@ impl IdentityManager { */ // [ ] !!! TODO: I don't think below is evaluating by given channel - botinstance::botlog::debug( + botlog::debug( &format!( "IN VARS > chattername {} ; channel {:?}", chattername, channel @@ -2409,29 +1297,24 @@ impl IdentityManager { None => None, }; - let rolesa = Arc::clone(&self.special_roles_users); + let rolesdb = Arc::clone(&self.special_roles_users); - let a = rolesa.read().await; - // let a = Arc::clone(a) - let a = a; - let vecroles = &(*a); - let vecroles = vecroles.get(&chattername); + let rolesdb_lock = rolesdb.read().await; + + let vecroles = &(*rolesdb_lock).get(&chattername); match vecroles { Some(a) => { // [ ] This needs to take the user roles for the user, then yield only the one for the channel if channel is explicitely provided // Some(Arc::clone(a)) match channel_out { Some(channel) => { - // let eval = a.read().await.contains(&UserRole::Mod(channel)); - // let eval = a.read().await.contains(&UserRole::SupMod(channel)); - botinstance::botlog::debug( + botlog::debug( &format!("INTERNAL > All Roles found {:?}", &a), Some("IdentityManager > getspecialuserroles()".to_string()), None, ); - // a.read().await.contains(&UserRole::BotAdmin) - botinstance::botlog::trace( + botlog::debug( &format!( "INTERNAL > eval special roles contains botadmin : {:?}", a.read().await.contains(&UserRole::BotAdmin) @@ -2452,11 +1335,6 @@ impl IdentityManager { // else {}; } None => { - // here , do nothing if the channel not provided - // [ ] TODO : Future is to provide all maybe ? - // ... no I think missing this is an issue for when the flag is -admin and channel is None? - // - // => 02.13 - Decided That None is provided as a Channel, we can output non-channel related roles like BotAdmin if a.read().await.contains(&UserRole::BotAdmin) { evalsproles.push(UserRole::BotAdmin); } @@ -2471,16 +1349,23 @@ impl IdentityManager { } } - botinstance::botlog::debug( + botlog::debug( &format!("OUT > evalsproles {:?}", &evalsproles), Some("IdentityManager > getspecialuserroles()".to_string()), None, ); - return evalsproles; + // return evalsproles; + evalsproles } } +// ===================== +// ===================== +// ===================== +// ===================== +// ===================== + #[cfg(test)] mod core_identity { @@ -2491,9 +1376,6 @@ mod core_identity { #[test] fn user_role_identity() { Log::set_file_ext(Extension::Log); - // Log::set_level(Level::Trace); - // let result = 2 + 2; - // assert_eq!(result, 4); assert_eq!( UserRole::SupMod(ChType::Channel("strong".to_string())), UserRole::SupMod(ChType::Channel("Strong".to_lowercase())) @@ -2617,7 +1499,8 @@ mod core_identity { let broadcaster = "broadcasterer".to_string(); let broadcaster_badge = &Some(ChatBadge::Broadcaster); - let channel = Some(ChType::Channel(broadcaster.clone())); + // let channel = Some(ChType::Channel(broadcaster.clone())); + let channel = ChType::Channel(broadcaster.clone()); let supchatter = "superModerator".to_string(); let trg_role = None; @@ -2626,7 +1509,7 @@ mod core_identity { broadcaster.clone(), broadcaster_badge, supchatter.clone(), - channel.clone(), + Some(channel.clone()), trg_role.clone(), ) .await; @@ -2641,7 +1524,7 @@ mod core_identity { broadcaster.clone(), broadcaster_badge, supchatter.clone(), - channel.clone(), + Some(channel.clone()), trg_role.clone(), ) .await; @@ -2652,10 +1535,10 @@ mod core_identity { ); let rslt = test_id_mgr - .getspecialuserroles(supchatter.clone(), channel.clone()) + .getspecialuserroles(supchatter.clone(), Some(channel.clone())) .await; - assert!(rslt.contains(&UserRole::SupMod(channel.unwrap()))); + assert!(rslt.contains(&UserRole::SupMod(channel))); // [x] SupMod Attempts to Promote Chatter to SupMod @@ -2685,7 +1568,6 @@ mod core_identity { .getspecialuserroles(trgchatter.clone(), channel.clone()) .await; - // assert!(rslt.contains(&UserRole::Mod(ChType::Channel("broadcasterer".to_string())))); assert!(rslt.contains(&UserRole::Mod(channel.clone().unwrap()))); let rslt = test_id_mgr @@ -2698,7 +1580,6 @@ mod core_identity { ) .await; - // assert_eq!(rslt, ChangeResult::Success("Promotion Successful".to_string())); assert_eq!( rslt, ChangeResult::Failed("You're not permitted to do that".to_string()) @@ -2770,7 +1651,6 @@ mod core_identity { ) .await; - // assert_eq!(rslt, ChangeResult::Success("Promotion Successful".to_string())); assert_eq!( rslt, ChangeResult::Success("Promotion Successful".to_string()) @@ -2810,7 +1690,7 @@ mod core_identity { let test_id_mgr = IdentityManager::init(); let supmod = "supmoder".to_string(); - // let supmod_badge = &None; + let channel = Some(ChType::Channel("somechannel".to_string())); test_id_mgr.affirm_chatter_in_db(supmod.clone()).await; @@ -2827,8 +1707,6 @@ mod core_identity { // [x] Create regular mod let regmod = "moder".to_string(); - // let supmod_badge = &None; - // let channel = Some(ChType::Channel("somechannel".to_string())); test_id_mgr.affirm_chatter_in_db(regmod.clone()).await; test_id_mgr diff --git a/src/core/ratelimiter.rs b/src/core/ratelimiter.rs index f87b2b9..b43abba 100644 --- a/src/core/ratelimiter.rs +++ b/src/core/ratelimiter.rs @@ -1,8 +1,8 @@ -use std::time::Instant; - const TIME_THRESHOLD_S: u64 = 30; const MSG_THRESHOLD: u32 = 20; +use std::time::Instant; + #[derive(Debug, Clone)] pub struct RateLimiter { timer: Instant, @@ -12,6 +12,13 @@ pub struct RateLimiter { pub enum LimiterResp { Allow, // when it's evaluated to be within limits Skip, // as outside of rate limits + // Enqueue, // [FUTURE] +} + +impl Default for RateLimiter { + fn default() -> Self { + Self::new() + } } impl RateLimiter { @@ -24,21 +31,18 @@ impl RateLimiter { pub fn check_limiter(&mut self) -> LimiterResp { if self.timer.elapsed().as_secs() >= TIME_THRESHOLD_S { - // # [x] elapsed >= TIME_THRESHOLD_S self.timer = Instant::now(); self.msgcounter = 0; LimiterResp::Allow } else if self.msgcounter < MSG_THRESHOLD { - // # [x] elapsed < TIME_THRESHOLD_S && msgcounter < MSG_THRESHOLD LimiterResp::Allow - // } else if self.msgcounter >= MSG_THRESHOLD { } else { - // # [x] elapsed < TIME_THRESHOLD_S && msgcounter >= MSG_THRESHOLD + // when elapsed() < TIME_THRESHOLD_S && msgcounter >= MSG_THRESHOLD LimiterResp::Skip } } - pub fn increment_counter(&mut self) -> () { + pub fn increment_counter(&mut self) { self.msgcounter += 1; } } diff --git a/src/modules.rs b/src/custom.rs similarity index 81% rename from src/modules.rs rename to src/custom.rs index 08cb49b..fc802e6 100644 --- a/src/modules.rs +++ b/src/custom.rs @@ -4,15 +4,11 @@ */ -//mod crate::core::botmodules; -// use crate::core::botmodules; -pub use crate::core::botmodules::ModulesManager; - -// use crate::core::botinstance; -pub use crate::core::botinstance::BotInstance; -use futures::lock::Mutex; use std::sync::Arc; +pub use crate::core::botinstance::BotInstance; +pub use crate::core::botmodules::ModulesManager; + // [ ] Load submodules mod experiments; @@ -24,6 +20,4 @@ pub async fn init(mgr: Arc) { // this is achieved by calling submodules that also have fn init() defined experiments::init(mgr).await - - //(); } diff --git a/src/modules/experiments.rs b/src/custom/experiments.rs similarity index 50% rename from src/modules/experiments.rs rename to src/custom/experiments.rs index e61d296..462630f 100644 --- a/src/modules/experiments.rs +++ b/src/custom/experiments.rs @@ -1,47 +1,29 @@ /* - Submodules - + Custom Modules - - - should have definitions of BotAction that will be added to a bit - - therefore, will be defined in modules.rs file - - will define one init(&BotInstance) take within the module that will contain : - - BotAction definitions that each call &BotInstance module manager to add itself + Usage : + [ ] within the file's init(), define BotActions & Load them into the ModulesManager + [ ] Define Execution Bodies for these BotActions + [ ] Afterwards, add the following to parent modules.rs file + - mod ; + - within init(), ::init(mgr).await */ -// mod crate::modules; -//use crate::modules; +use rand::Rng; +use std::sync::Arc; -use std::future::Future; - -use crate::core::botmodules::bot_actions::actions_util::{self, BotAR}; -use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager}; - -use crate::core::botinstance::{self, BotInstance, ChType}; -use futures::lock::Mutex; use twitch_irc::message::PrivmsgMessage; +use crate::core::botlog; + +use crate::core::bot_actions::actions_util::{self, BotAR}; +use crate::core::botmodules::{BotActionTrait, BotCommand, BotModule, Listener, ModulesManager}; + use crate::core::identity; -use rand::Rng; - -use std::rc::Rc; - -use std::sync::{Arc, RwLock}; - -// pub fn init(mgr:&mut ModulesManager) pub async fn init(mgr: Arc) { - // BotCommand { - // module : BotModule(String::from("experiments 004")), - // command : String::from("test1"), // command call name - // alias : vec![String::from("tester1"),String::from("testy1")], // String of alternative names - // exec_body : actions_util::asyncbox(testy) , - // help : String::from("DUPCMD4 tester"), - // required_roles : vec![ - // //identity::UserRole::Mod(ChType::Channel(String::new())), - // identity::UserRole::SupMod(ChType::Channel(String::new())) - // ], - // }.add_to_modmgr(mgr); - + // 1. Define the BotAction let botc1 = BotCommand { module: BotModule(String::from("experiments001")), command: String::from("test1"), // command call name @@ -51,8 +33,10 @@ pub async fn init(mgr: Arc) { required_roles: vec![identity::UserRole::BotAdmin], }; + // 2. Add the BotAction to ModulesManager botc1.add_to_modmgr(Arc::clone(&mgr)).await; + // 1. Define the BotAction let list1 = Listener { module: BotModule(String::from("experiments001")), name: String::from("GoodGirl Listener"), @@ -60,46 +44,38 @@ pub async fn init(mgr: Arc) { help: String::from(""), }; + // 2. Add the BotAction to ModulesManager list1.add_to_modmgr(Arc::clone(&mgr)).await; } -async fn good_girl(mut bot: BotAR, msg: PrivmsgMessage) { - // println!("In GoodGirl() Listener"); - // Change below from debug to trace if required later - botinstance::botlog::debug( - "In GoodGirl() Listener", - Some("experiments > goodgirl()".to_string()), - Some(&msg), - ); - - //println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text); - +async fn good_girl(bot: BotAR, msg: PrivmsgMessage) { // [ ] 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() - // && msg.message_text.contains("GoodGirl") { - // chat.say_in_reply_to(&msg,String::from("GoodGirl")).await; - //if rng.gen_ratio(1,5) { - // println!("In GoodGirl() > Pausechamp"); - botinstance::botlog::debug( - "In GoodGirl() > Pausechamp", + botlog::debug( + "Good Girl Detected > Pausechamp", Some("experiments > goodgirl()".to_string()), Some(&msg), ); + let rollwin = rand::thread_rng().gen_ratio(1, 8); + if rollwin { - // println!("In GoodGirl() > Win"); - botinstance::botlog::debug( - "In GoodGirl() > Win", + botlog::debug( + "Oh that's a good girl!", Some("experiments > goodgirl()".to_string()), Some(&msg), ); - let a = Arc::clone(&bot); - let botlock = a.read().await; + + let bot = Arc::clone(&bot); + + let botlock = bot.read().await; + + // uses chat.say_in_reply_to() for the bot controls for messages botlock .botmgrs .chat @@ -111,7 +87,7 @@ async fn good_girl(mut bot: BotAR, msg: PrivmsgMessage) { async fn testy(mut _chat: BotAR, msg: PrivmsgMessage) { println!("testy triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call - botinstance::botlog::debug( + botlog::debug( "testy triggered!", Some("experiments > testy()".to_string()), Some(&msg), diff --git a/src/lib.rs b/src/lib.rs index 650ed26..c5ba775 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,2 @@ pub mod core; -pub mod modules; +pub mod custom; diff --git a/src/main.rs b/src/main.rs index 68f4f4e..b45ab98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,15 @@ -// pub mod core; -// pub mod modules; -//use myLib; -//pub mod lib; -use std::process::Output; - -// use crate::core::botinstance::ArcBox; -use botLib::core::botinstance::ArcBox; - -use botLib::core::botinstance::{self, BotInstance}; -// use core::botinstance::{self,BotInstance}; - -use casual_logger::Extension; use std::sync::Arc; use tokio::sync::RwLock; + +use casual_logger::{Extension, Level, Log}; + +use bot_lib::core::botinstance::BotInstance; +use bot_lib::core::botlog; +use bot_lib::core::botmodules; + pub type BotAR = Arc>; -use casual_logger::{Level, Log}; - -// Cweamcat can cweam on me - Forcen +// God I love anime girls #[tokio::main] pub async fn main() { @@ -27,58 +19,36 @@ pub async fn main() { let bot = BotInstance::init().await; - // Log::debug("Checking bot actions"); - botinstance::botlog::debug("Checking bot actions", Some("main()".to_string()), None); - let a = Arc::clone(&bot.botmodules.botactions); - let a = a.read().await; - // let a = *a; + { + botlog::trace("Reading bot actions", Some("main()".to_string()), None); - for (_, acts) in &*a { - for act in acts { - match act { - botLib::core::botmodules::BotAction::C(b) => { - // println!("bot actiions: {}",b.command) - // Log::info(&format!("bot actions: {}",b.command)); - botinstance::botlog::info( - &format!("bot actions: {}", b.command), - Some("main()".to_string()), - None, - ); - } - botLib::core::botmodules::BotAction::L(l) => { - // println!("bot actiions: {}",l.name) - // Log::info(&format!("bot actions: {}",l.name)); - botinstance::botlog::info( - &format!("bot actions: {}", l.name), - Some("main()".to_string()), - None, - ); - } - _ => { - // println!("Not a valid match??") - // Log::info("Not a valid match??"); - botinstance::botlog::info( - "Not a valid match??", - Some("main()".to_string()), - None, - ); - } + let actsdb = Arc::clone(&bot.botmodules.botactions); + let actsdb_lock = actsdb.read().await; + + for acts in (*actsdb_lock).values() { + for act in acts { + let outstr = match act { + botmodules::BotAction::C(b) => { + format!("bot actions > Command : {}", b.command) + } + botmodules::BotAction::L(l) => { + format!("bot actions > Listener : {}", l.name) + } + _ => "Not a valid match??".to_string(), + }; + + botlog::info(outstr.as_str(), Some("main()".to_string()), None); } } } - // println!("Starting runner.."); - // Log::notice("Starting Bot Runner"); - botinstance::botlog::notice("Starting Bot Runner", Some("main()".to_string()), None); + botlog::notice("Starting Bot Runner", Some("main()".to_string()), None); println!("Starting Bot Runner"); Log::flush(); bot.runner().await; - // println!("ERROR : EXIT Game loop"); - // let msg = Log::fatal("ERROR : EXIT Game loop"); - // panic!("{}",Log::fatal("ERROR : EXIT Game loop")); - let a = botinstance::botlog::fatal("ERROR : EXIT Game loop", Some("main()".to_string()), None); - panic!("{}", a); + let pstr = botlog::fatal("ERROR : EXIT Game loop", Some("main()".to_string()), None); + panic!("{}", pstr); }