diff --git a/src/core/bot_actions.rs b/src/core/bot_actions.rs index 8941654..a88e5de 100644 --- a/src/core/bot_actions.rs +++ b/src/core/bot_actions.rs @@ -5,7 +5,7 @@ use tokio::sync::RwLock; use crate::core::botinstance::BotInstance; -use super::{botmodules::{BotAction, BotModule}, identity::ChatBadge}; +use super::{botinstance::Channel, botmodules::{BotAction, BotModule}, identity::ChatBadge}; pub type BotAR = Arc>; @@ -15,30 +15,72 @@ pub type ActAR = Arc>; pub struct ExecBodyParams { pub bot : BotAR, pub msg : PrivmsgMessage, - pub parent_act : ActAR , + // pub parent_act : ActAR , + pub curr_act : ActAR , } impl ExecBodyParams { - pub async fn get_parent_module(&self) -> Option { + // pub async fn get_parent_module(&self) -> Option { + // pub async fn get_parent_module(&self) -> BotModule { + pub async fn get_module(&self) -> BotModule { - let parent_act = Arc::clone(&self.parent_act); - let parent_act_lock = parent_act.read().await; + let curr_act = Arc::clone(&self.curr_act); + let parent_act_lock = curr_act.read().await; let act = &(*parent_act_lock); match act { BotAction::C(c) => { - let temp = c.module.clone(); - Some(temp) + // let temp = c.module.clone(); + // Some(temp) + c.module.clone() }, BotAction::L(l) => { - let temp = l.module.clone(); - Some(temp) + // let temp = l.module.clone(); + // Some(temp) + l.module.clone() }, - _ => None + BotAction::R(r) => { + // let temp = r.module.clone(); + // Some(temp) + r.read().await.module.clone() + } + // _ => None } } + pub async fn get_channel(&self) -> Option { + + // THIS IS INCORRECT - BELOW MAY BE PULLING THE PARENT BOTACTION + // NOT THE CURRENT BOT ACTION + + + let curr_act = Arc::clone(&self.curr_act); + let parent_act_lock = curr_act.read().await; + let act = &(*parent_act_lock); + match act { + BotAction::C(_) => { + // let temp = c.module.clone(); + // Some(temp) + Some(Channel(self.msg.channel_login.clone())) + }, + BotAction::L(_) => { + // let temp = l.module.clone(); + // Some(temp) + // l.module.clone() + Some(Channel(self.msg.channel_login.clone())) + }, + BotAction::R(r) => { + // let temp = r.module.clone(); + // Some(temp) + Some(r.read().await.channel.clone()) + } + // _ => None + } + } + + + pub fn get_sender(&self) -> String { self.msg.sender.name.clone() } diff --git a/src/core/botinstance.rs b/src/core/botinstance.rs index 07b481d..563856f 100644 --- a/src/core/botinstance.rs +++ b/src/core/botinstance.rs @@ -404,7 +404,7 @@ impl BotInstance { let params = ExecBodyParams { bot : Arc::clone(&bot), msg : (*msg).clone(), - parent_act : Arc::clone(&act_clone), + curr_act : Arc::clone(&act_clone), }; // When sending a BotMsgTypeNotif, send_botmsg does Roles related validation as required @@ -461,7 +461,7 @@ impl BotInstance { let params = ExecBodyParams { bot : Arc::clone(&bot), msg : (*msg).clone(), - parent_act : Arc::clone(&act_clone), + curr_act : Arc::clone(&act_clone), }; @@ -491,7 +491,7 @@ impl BotInstance { let params = ExecBodyParams { bot : Arc::clone(&bot), msg : (*msg).clone(), - parent_act : Arc::clone(&act_clone), + curr_act : Arc::clone(&act_clone), }; @@ -516,7 +516,7 @@ impl BotInstance { c.execute(ExecBodyParams { bot : a, msg : msg.clone() , - parent_act : Arc::clone(&act_clone), + curr_act : Arc::clone(&act_clone), }).await; botlog::trace( @@ -564,7 +564,7 @@ impl BotInstance { l.execute(ExecBodyParams { bot : a, msg : msg.clone() , - parent_act : Arc::clone(&act_clone), + curr_act : Arc::clone(&act_clone), } ).await; } diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs index c104fdd..49fca78 100644 --- a/src/core/botmodules.rs +++ b/src/core/botmodules.rs @@ -30,9 +30,16 @@ use std::sync::Arc; use casual_logger::Log; +use chrono::DateTime; +// use chrono::Duration; +use chrono::Local; use tokio::sync::RwLock; use async_trait::async_trait; +use tokio::task::JoinHandle; + +use tokio::time::Instant; +use tokio::time::{sleep, Duration}; use crate::core::bot_actions::actions_util; use crate::core::bot_actions::ExecBodyParams; @@ -462,7 +469,8 @@ pub enum StatusType { pub enum BotAction { C(BotCommand), L(Listener), - R(Routine), + // R(Routine), + R(Arc>), } impl BotAction { @@ -568,8 +576,554 @@ impl BotActionTrait for Listener { } } -#[derive(Debug)] -pub struct Routine {} +// #[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[derive(PartialEq, Eq, Hash)] +pub enum RoutineAttr { + DelayedStart, + ScheduledStart(DateTime), // Scheduled Date (if any) after which, if not started, may trigger + LoopDuration(Duration), // How long to wait between iterations + LoopInfinitely, + RunOnce, + MaxTimeThreshold(DateTime), // DateTime after which, it will abort/cancel or stop + MaxIterations(i64), +} +/* + a Routine can be given different combinations of the above, but business logic may validate + these at Routine construction + + For example, a Routine could have the following characteristics + - DelayedStart (so it skips the first iteration) + - ScheduledStart(DateTime) - With a Start Date-Time for the first iteration to trigger + - LoopDuration(Duration) - How long to wait between iterations + + The above without any other thresholds would loop infinitely with the above characteristics + + Another example, + - LoopDuration(Duration) - How long to wait between iterations + - MaxTimeThreshold(DateTime) + - MaxIterations(i64) + + The above has thresholds , so if either are reached, it would abort/cancel or stop . Since there is no + ScheduledStart, the routine would have to be started manually elsewhere + + Another example , + - (no RoutineAttr) + + The above would only run once, and only when the Start() is called + +*/ + +// #[derive(Debug)] +pub struct Routine { + pub name : String , + pub module : BotModule , // from() can determine this if passed parents_params + // pub channel : Option , // Routines generally run by Channel ; but can be left None + pub channel : Channel , // Requiring some channel context + exec_body: bot_actions::actions_util::ExecBody, + // parent_params : Option , + parent_params : ExecBodyParams , + // pub join_handle : Option> , + // pub join_handle : Option> , + // pub join_handle : Option>>> , + pub join_handle : Option>>> , + start_time : Option> , + complete_iterations : i64 , + remaining_iterations : Option , + routine_attr : Vec , +} + + +impl Routine { + + // Constructor + pub fn from( + name : String , + module : BotModule , + channel : Channel, + routine_attr : Vec , + exec_body : bot_actions::actions_util::ExecBody , + // parent_params : Option + parent_params : ExecBodyParams + // ) -> Result { + // ) -> Result { + ) -> Result< + Arc>, + String + > { + + // [ ] Validation is made against parent_params + // to ensure those params don't conflict + // conlicts would throw an error + + // parent_params.unwrap(). + + if routine_attr.contains(&RoutineAttr::RunOnce) { + return Ok(Arc::new(RwLock::new(Routine { + name , + module , + channel , + exec_body , + parent_params , + join_handle : None , + start_time : None , + complete_iterations : 0 , + remaining_iterations : None , + routine_attr : routine_attr + }))) ; + } + + + Err("NOT IMPLEMENTED".to_string()) + } + + pub fn change_channel( + &self, + _channel : Channel + ) -> Result { + // [ ] Think Ideally it should try to + // change the target channel of the + // internal process too if possible? + + Err("NOT IMPLEMENTED".to_string()) + } + + // pub async fn start(self) -> Result + // pub async fn start(self : &mut Self) -> Result + pub async fn start( + trg_routine_ar : Arc> + // ) -> Result +) -> Result>,String> + { + + // [ ] Asyncio Spawn likely around here + // [ ] & Assigns self.join_handle + + + // let self_rw = Arc::new(RwLock::new(self)); + // let mut self_wr_lock = self_rw.write().await; + // let self_ar = Arc::new(RwLock::new(trg_routine_ar)); + + + if trg_routine_ar.read().await.routine_attr.contains(&RoutineAttr::RunOnce) { + // if self_wr_lock.routine_attr.contains(&RoutineAttr::RunOnce) { + // let = self_wr_lock.remaining_iterations + + // let mut self_wr_lock = self_rw.write().await; + + + // let self_rw_copy = Arc::new(self); + // let self_rw_copy = Arc::clone(&self_rw); + // let mut a = *(*self_wr_lock); + // a.remaining_iterations = Some(1); + // (*self_wr_lock).remaining_iterations = Some(1); + // let routine = *self_rw_copy.read().await; + + // fn innerhelper(self_rw : Arc>) -> Option> { + // fn innerhelper(self_rw : Arc>) -> Option> { + // fn innerhelper(inroutine : &Routine) -> Option> { + // fn innerhelper(inroutine : Routine) -> Option> { + // async fn innerhelper(inroutine : Arc>) -> Option> { + async fn runonce_innerhelper(inroutine : Arc>) -> JoinHandle<()> { + + botlog::trace( + "innerhelper() started", + Some(format!( + "Routine > start() > (In Tokio Spawn)", + )), + Some(&inroutine.read().await.parent_params.msg), + ); + + Log::flush(); + + // Some( + // tokio::spawn(async move { + + // botlog::trace( + // ">> Within Spawn", + // Some(format!( + // "Routine > start() > (In Tokio Spawn)", + // )), + // Some(&inroutine.read().await.parent_params.msg), + // ); + + // Log::flush(); + + + + // // let mut self_wr_lock = self_rw.write().await; + // // let mut remainingiter = self_wr_lock.remaining_iterations.unwrap(); + // let mut remainingiter = inroutine.write().await.remaining_iterations.unwrap_or(0); + + + + // botlog::trace( + // format!( + // "[TRACE][Routine Started] {} in {}", + // inroutine.read().await.name, + // inroutine.read().await.channel.0 + // ) + // .as_str(), + // Some(format!( + // "Routine > start() > (In Tokio Spawn) > {:?}", + // inroutine.read().await.module + // )), + // Some(&inroutine.read().await.parent_params.msg), + // ); + + // Log::flush(); + + // inroutine.write().await.start_time = Some(chrono::offset::Local::now()); + + + // // Loop iteration + // while remainingiter > 1 { + + // // execution body + // inroutine.read().await.loopbody().await; + + // // end of loop iteration + // remainingiter -= 1; + // { + // inroutine.write().await.remaining_iterations = Some(remainingiter); + // inroutine.write().await.complete_iterations += 1; + // } + + // } + + // botlog::trace( + // format!( + // "[TRACE][Routine Completed] {} in {}", + // inroutine.read().await.name, + // inroutine.read().await.channel.0 + // ) + // .as_str(), + // Some(format!( + // "Routine > start() > (In Tokio Spawn) > {:?}", + // inroutine.read().await.module + // )), + // Some(&inroutine.read().await.parent_params.msg), + // ); + + + // Log::flush(); + // })) + + return tokio::spawn(async move { + + botlog::trace( + ">> Within Spawn", + Some(format!( + "Routine > start() > (In Tokio Spawn)", + )), + Some(&inroutine.read().await.parent_params.msg), + ); + + Log::flush(); + + + // botlog::trace( + // &format!( + // ">> Within Spawn - Reamining Iter Eval : {:?}" + // ,inroutine.read().await.remaining_iterations), + // Some(format!( + // "Routine > start() > (In Tokio Spawn)", + // )), + // Some(&inroutine.read().await.parent_params.msg), + // ); + + // Log::flush(); + + botlog::trace( + ">> Within Spawn >> After remaining iter eval", + Some(format!( + "Routine > start() > (In Tokio Spawn)", + )), + Some(&inroutine.read().await.parent_params.msg), + ); + + Log::flush(); + + + botlog::trace( + ">> Within Spawn >> After remaining iter eval 2 ", + Some(format!( + "Routine > start() > (In Tokio Spawn)", + )), + Some(&inroutine.read().await.parent_params.msg), + ); + + Log::flush(); + + + botlog::trace( + ">> Within Spawn >> After remaining iter eval 3 ", + Some(format!( + "Routine > start() > (In Tokio Spawn)", + )), + Some(&inroutine.read().await.parent_params.msg), + ); + + Log::flush(); + + + // let mut self_wr_lock = self_rw.write().await; + // let mut remainingiter = self_wr_lock.remaining_iterations.unwrap(); + // let mut remainingiter = inroutine.write().await.remaining_iterations.unwrap_or(0); + // let mut remainingiter = inroutine.read().await.remaining_iterations.unwrap_or(0); + // let mut remainingiter = inroutine.read().await.remaining_iterations.unwrap_or(0); + + // async fn setremain(inroutine : Arc> , number : Option) { + // inroutine.write().await.remaining_iterations = number; + // } + + // if inroutine.read().await.remaining_iterations.is_none() { + // // inroutine.write().await.remaining_iterations = Some(0); + // // setremain(inroutine.clone(),Some(0)).await; + // } + + // botlog::trace( + // format!( + // "[TRACE][Routine Started] {} in {}", + // inroutine.read().await.name, + // inroutine.read().await.channel.0 + // ) + // .as_str(), + // Some(format!( + // "Routine > start() > (In Tokio Spawn) > {:?}", + // inroutine.read().await.module + // )), + // Some(&inroutine.read().await.parent_params.msg), + // ); + + // botlog::trace( + // format!( + // "[TRACE][Routine Started] {} in {}", + // inroutine.read().await.name, + // inroutine.read().await.channel.0 + // ) + // .as_str(), + // Some(format!( + // "Routine > start() > (In Tokio Spawn) > {:?}", + // inroutine.read().await.module + // )), + // Some(&inroutine.read().await.parent_params.msg), + // ); + + // Log::flush(); + + // inroutine.write().await.start_time = Some(chrono::offset::Local::now()); + // { + // inroutine.write().await.start_time = Some(chrono::offset::Local::now()); + // } + + + // Loop iteration + // while remainingiter > 1 { + // while inroutine.read().await.remaining_iterations.unwrap_or(0) > 1 { + + // execution body + inroutine.read().await.loopbody().await; + + // end of loop iteration + + // let remain_iter = inroutine.read().await.remaining_iterations.unwrap_or(0); + + // { + // // inroutine.write().await.remaining_iterations = Some(remain_iter - 1); + // setremain(inroutine.clone(),Some(remain_iter - 1)).await; + // } + // { + // inroutine.write().await.complete_iterations += 1; + // } + + // remainingiter -= 1; + // { + // inroutine.write().await.remaining_iterations = Some(remainingiter); + // inroutine.write().await.complete_iterations += 1; + // } + + // } + + botlog::trace( + format!( + "[TRACE][Routine Completed] {} in {}", + inroutine.read().await.name, + inroutine.read().await.channel.0 + ) + .as_str(), + Some(format!( + "Routine > start() > (In Tokio Spawn) > {:?}", + inroutine.read().await.module + )), + Some(&inroutine.read().await.parent_params.msg), + ); + + + Log::flush(); + }) + + + + } + + + // let self_rw = Arc::new(RwLock::new(self)); + // let mut self_wr_lock = self_rw.write().await; + + // self_wr_lock.join_handle = innerhelper(&routine) ; + + // let mut routine = self_rw_copy.write().await; + // (**routine).join_handle = innerhelper(*routine); + // routine.join_handle = innerhelper(*routine); + // let routine = *self_rw_copy.read().await; + // self_rw_copy.write().await.join_handle = innerhelper(&routine); + // let self_ref = Arc::clone(&trg_routine_ar); + // trg_routine_ar.write().await.join_handle = innerhelper(trg_routine_ar.clone()).await; + { + trg_routine_ar.write().await.join_handle = Some(Arc::new(RwLock::new(runonce_innerhelper(trg_routine_ar.clone()).await))); + } + + // if let Some(a) = &trg_routine_ar.read().await.join_handle { + // (*a).await.unwrap(); + // }; + + // return Ok("Successfully Started Routine".to_string()); + return Ok(trg_routine_ar); + + } + + + + botlog::trace( + format!( + "[ERROR][Routine NOT IMPLEMENTED] {} in {}", + // self_wr_lock.name,self_wr_lock.channel.0 + trg_routine_ar.read().await.name, + trg_routine_ar.read().await.channel.0 + ) + .as_str(), + Some(format!( + "Routine > start() > (In Tokio Spawn) > {:?}", + // self_wr_lock.module + trg_routine_ar.read().await.module + )), + Some(&trg_routine_ar.read().await.parent_params.msg), + ); + + Log::flush(); + + Err("NOT IMPLEMENTED".to_string()) + } + + + async fn loopbody(&self) + { + botlog::trace( + "loopbody() started", + Some(format!( + "Routine > start() > (During Tokio Spawn) > Execution body", + )), + None, + ); + + Log::flush(); + + (self.exec_body)( + self.parent_params.clone() + ).await; + } + + pub async fn stop(&self) -> Result + { + + + let self_rw = Arc::new(RwLock::new(self)); + let self_lock = self_rw.read().await; + + + botlog::trace( + format!( + "[ERROR][Routine NOT IMPLEMENTED] {} in {}", + self_lock.name,self_lock.channel.0 + ) + .as_str(), + Some(format!( + "Routine > start() > (In Tokio Spawn) > {:?}", + self_lock.module + )), + Some(&self_lock.parent_params.msg), + ); + + Log::flush(); + + Err("NOT IMPLEMENTED".to_string()) + } + + pub async fn restart( + &self, + _force : bool + ) -> Result + { + // force flag aborts the routine immediately (like cancel()) + + + let self_rw = Arc::new(RwLock::new(self)); + let self_lock = self_rw.read().await; + + + botlog::trace( + format!( + "[ERROR][Routine NOT IMPLEMENTED] {} in {}", + self_lock.name,self_lock.channel.0 + ) + .as_str(), + Some(format!( + "Routine > start() > (In Tokio Spawn) > {:?}", + self_lock.module + )), + Some(&self_lock.parent_params.msg), + ); + + Log::flush(); + Err("NOT IMPLEMENTED".to_string()) + } + + pub async fn cancel(&self) -> Result + { + + // [ ] Likely calls abort() + // Related : + // https://docs.rs/tokio/latest/tokio/task/struct.JoinHandle.html#method.abort + + + + let self_rw = Arc::new(RwLock::new(self)); + let self_lock = self_rw.read().await; + + + botlog::trace( + format!( + "[ERROR][Routine NOT IMPLEMENTED] {} in {}", + self_lock.name,self_lock.channel.0 + ) + .as_str(), + Some(format!( + "Routine > start() > (In Tokio Spawn) > {:?}", + self_lock.module + )), + Some(&self_lock.parent_params.msg), + ); + + Log::flush(); + Err("NOT IMPLEMENTED".to_string()) + } + + + +} + + + type StatusdbEntry = (ModGroup, Vec); type ModuleActions = Vec>>; diff --git a/src/core/chat.rs b/src/core/chat.rs index bb938cc..a83bd8c 100644 --- a/src/core/chat.rs +++ b/src/core/chat.rs @@ -101,14 +101,15 @@ impl Chat { Some(¶ms.msg), ); - let parent_module = params.get_parent_module().await; + let parent_module = params.get_module().await; let params_clone = params.clone(); let botclone = Arc::clone(¶ms_clone.bot); let botlock = botclone.read().await; let modmgr = Arc::clone(&botlock.botmodules); let modstatus = (*modmgr).modstatus( - parent_module.clone().expect("ERROR - Expected a module"), + // parent_module.clone().expect("ERROR - Expected a module"), + parent_module.clone(), Channel(channel_login.clone()) ).await; @@ -180,7 +181,8 @@ impl Chat { self.send_botmsg(BotMsgType::Notif( format!("uuh {:?} is disabled on {} : {:?}", - parent_module.clone().unwrap(), + // parent_module.clone().unwrap(), + parent_module.clone(), channel_login.clone(), lvl ), diff --git a/src/core/identity.rs b/src/core/identity.rs index dc2da72..e1500eb 100644 --- a/src/core/identity.rs +++ b/src/core/identity.rs @@ -553,7 +553,16 @@ async fn getroles(params : ExecBodyParams) { let arg1 = argv.next(); let targetuser = match arg1 { - None => return, // exit if no arguments + None => { + + botlog::debug( + "Exittingcmd getroles - Invalid arguments ", + Some("identity.rs > init > getroles()".to_string()), + Some(¶ms.msg), + ); + return + + }, // exit if no arguments Some(arg) => arg, }; diff --git a/src/custom/experimental.rs b/src/custom/experimental.rs index 409abd1..7da2ecb 100644 --- a/src/custom/experimental.rs +++ b/src/custom/experimental.rs @@ -12,6 +12,7 @@ pub use crate::core::botmodules::ModulesManager; mod experiment001; mod experiment002; +mod experiment003; // [ ] init() function that accepts bot instance - this is passed to init() on submodules @@ -21,4 +22,5 @@ pub async fn init(mgr: Arc) { experiment001::init(Arc::clone(&mgr)).await; experiment002::init(Arc::clone(&mgr)).await; + experiment003::init(Arc::clone(&mgr)).await; } diff --git a/src/custom/experimental/experiment003.rs b/src/custom/experimental/experiment003.rs new file mode 100644 index 0000000..1d76930 --- /dev/null +++ b/src/custom/experimental/experiment003.rs @@ -0,0 +1,357 @@ +/* + Custom Modules - + + 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 + +*/ + + +const OF_CMD_CHANNEL:Channel = Channel(String::new()); + + +use casual_logger::Log; +use rand::Rng; +use tokio::sync::RwLock; +use std::borrow::Borrow; +use std::sync::Arc; + +use crate::core::bot_actions::ExecBodyParams; +use crate::core::botinstance::Channel; +use crate::core::botlog; + +use crate::core::bot_actions::actions_util; +use crate::core::botmodules::{BotAction, BotActionTrait, BotCommand, BotModule, Listener, ModulesManager, Routine, RoutineAttr}; + +use crate::core::identity::UserRole::*; + +use tokio::time::{sleep, Duration}; + +pub async fn init(mgr: Arc) { + + // 1. Define the BotAction + let botc1 = BotCommand { + module: BotModule(String::from("experiments003")), + command: String::from("test3"), // command call name + alias: vec![], // String of alternative names + exec_body: actions_util::asyncbox(test3_body), + help: String::from("Test Command tester"), + required_roles: vec![ + BotAdmin, + Mod(OF_CMD_CHANNEL), + ], + }; + + // 2. Add the BotAction to ModulesManager + botc1.add_to_modmgr(Arc::clone(&mgr)).await; + + +} + + +async fn test3_body(params : ExecBodyParams) { + // println!("testy triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call + botlog::debug( + "testy triggered!", + Some("Experiments003 > test3 command body".to_string()), + Some(¶ms.msg), + ); + + /* + Test Routine Start() by : + 1. In this single exec body , create a Routine + 2. Create a Routine Execution Body + 3. Pass the Execution Body & Routine Attributes to create the Routine + 4. Start the Routine + 5. For RunOnce , we should see it only trigger once, and then complete in the logs + + */ + + // [x] Get the module from params + + // let parentmodule = params.get_parent_module().await; + let module = params.get_module().await; + let channel = params.get_channel().await; + let routine_attr = vec![ + RoutineAttr::RunOnce + ]; + // let exec_body = actions_util::asyncbox(rtestbody); + let exec_body = actions_util::asyncbox(rtestbody); // <-- 03.27 - when below is uncommented, this is throwing an issue + + + // let parent_params = params.clone(); + // let params_clone = params.clone(); + + + async fn rtestbody(params : ExecBodyParams) { + + // let bot = Arc::clone(¶ms.bot); + + // let botlock = bot.read().await; + + // // uses chat.say_in_reply_to() for the bot controls for messages + // botlock + // .botmgrs + // .chat + // .say_in_reply_to( + // ¶ms.msg.clone(), + // String::from("Inner Routine Loop Message"), + // params.clone() + // ).await; + + let logmsg_botact = match *params.curr_act.read().await { + BotAction::C(_) => "command", + BotAction::R(_) => "routine", + BotAction::L(_) => "listener", + } ; + + botlog::trace( + // format!("Params > Curr_act : {:?}", params.curr_act).as_str(), // BotAction doesn't imblement debug + format!("Params > Curr_act type : {:?}", logmsg_botact).as_str(), + Some("Experiments003 > test3 command body".to_string()), + Some(¶ms.msg), + ); + Log::flush(); + + for _ in 0..5 { + println!("tester"); + sleep(Duration::from_secs_f64(0.5)).await; + } + } + + + botlog::debug( + format!("RTESTBODY : module - {:?} ; channel - {:?}", + module,channel + ).as_str(), + Some("experiment003 > test3_body".to_string()), + Some(¶ms.msg), + ); + + + + let a = Routine::from( + "Routine Test".to_string(), + module, + channel.unwrap(), + routine_attr, + exec_body, + params.clone() + ); + + + + if let Ok(newr) = a { + + // [ ] before execute , be sure to adjust curr_act + + let mut params_mut = params.clone(); + // let newr_ar = Arc::new(RwLock::new(newr)); + let newr_ar = newr.clone(); + + params_mut.curr_act = Arc::new(RwLock::new( + BotAction::R(newr_ar.clone()) + )); + + // let a = newr_ar.read().await; + // let rslt = (&*a).start().await; + + // let mut newr_lock = newr_ar.write().await; + + // let rslt = newr_ar.write().await.start().await; + let rslt = Routine::start(newr_ar.clone()).await; + + // let rslt = newr_ar.read().await.start().await; + + let rsltstr = match rslt { + Ok(_) => "successful".to_string(), + Err(a) => a, + }; + + + botlog::debug( + format!("TEST3_BODY RESULT : {:?}", + rsltstr + ).as_str(), + Some("experiment003 > test3_body".to_string()), + Some(¶ms.msg), + ); + + Log::flush(); + + let bot = Arc::clone(¶ms.bot); + + let botlock = bot.read().await; + + // uses chat.say_in_reply_to() for the bot controls for messages + botlock + .botmgrs + .chat + .say_in_reply_to( + ¶ms.msg, + format!("Routine Result : {:?}",rsltstr), + params.clone() + ).await; + + // [x] Will not be handling JoinHandles here . If immediate abort() handling is required, below is an example that works + /* + + + let a = newr.clone().read().await.join_handle.clone(); + match a { + Some(b) => { + b.read().await.borrow().abort(); // [x] <-- This aborts if wanting to abort immediately + //() + }, + None => (), + } + + */ + + + } + + + Log::flush(); + + +} + + + + + +async fn good_girl(params : ExecBodyParams) { + + // [ ] Uses gen_ratio() to output bool based on a ratio probability . + // - For example gen_ratio(2,3) is 2 out of 3 or 0.67% (numerator,denomitator) + // - More Info : https://rust-random.github.io/rand/rand/trait.Rng.html#method.gen_ratio + + if params.msg.sender.name.to_lowercase() == "ModulatingForce".to_lowercase() + || params.msg.sender.name.to_lowercase() == "mzNToRi".to_lowercase() + { + botlog::debug( + "Good Girl Detected > Pausechamp", + Some("experiments > goodgirl()".to_string()), + Some(¶ms.msg), + ); + + let rollwin = rand::thread_rng().gen_ratio(1, 10); + + if rollwin { + botlog::debug( + "Oh that's a good girl!", + Some("experiments > goodgirl()".to_string()), + Some(¶ms.msg), + ); + + let bot = Arc::clone(¶ms.bot); + + + let botlock = bot.read().await; + + // uses chat.say_in_reply_to() for the bot controls for messages + botlock + .botmgrs + .chat + .say_in_reply_to( + ¶ms.msg, + String::from("GoodGirl xdd "), + params.clone() + ).await; + + + } + } +} + +async fn testy(params : ExecBodyParams) { + println!("testy triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call + botlog::debug( + "testy triggered!", + Some("experiments > testy()".to_string()), + Some(¶ms.msg), + ); +} + + +async fn babygirl(params : ExecBodyParams) { + + + println!("babygirl triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call + botlog::debug( + "babygirl triggered!", + Some("experiments > babygirl()".to_string()), + Some(¶ms.msg), + ); + + + let bot = Arc::clone(¶ms.bot); + + let botlock = bot.read().await; + + + botlock + .botmgrs + .chat + .say_in_reply_to( + ¶ms.msg, + String::from("16:13 notohh: cafdk"), + params.clone() + ).await; + + + sleep(Duration::from_secs_f64(0.5)).await; + + botlock + .botmgrs + .chat + .say_in_reply_to( + ¶ms.msg, + String::from("16:13 notohh: have fun eating princess"), + params.clone() + ).await; + + + sleep(Duration::from_secs_f64(2.0)).await; + + botlock + .botmgrs + .chat + .say_in_reply_to( + ¶ms.msg, + String::from("16:13 notohh: baby girl"), + params.clone() + ).await; + + + +} + + +async fn routinelike(params : ExecBodyParams) { + println!("routinelike triggered!"); // NOTE : This test function intends to print (e.g., to stdout) at fn call + botlog::debug( + "routinelike triggered!", + Some("experiments > routinelike()".to_string()), + Some(¶ms.msg), + ); + + // spawn an async block that runs independently from others + + tokio::spawn( async { + for _ in 0..5 { + println!(">> Innterroutine triggered!"); + sleep(Duration::from_secs_f64(5.0)).await; + } + } + ); + + // lines are executed after in conjunction to the spawn + +} +