From e963ae250df15c4b2d56f80ad1c323df97bce450 Mon Sep 17 00:00:00 2001 From: ModulatingForce <116608425+modulatingforce@users.noreply.github.com> Date: Wed, 27 Mar 2024 23:00:04 -0400 Subject: [PATCH] (cont) routine methods --- src/core/botmodules.rs | 130 +++++++++++++++++++++-- src/custom/experimental/experiment003.rs | 2 +- 2 files changed, 121 insertions(+), 11 deletions(-) diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs index f1997ad..bbed7fb 100644 --- a/src/core/botmodules.rs +++ b/src/core/botmodules.rs @@ -35,6 +35,7 @@ use casual_logger::Log; use chrono::DateTime; // use chrono::Duration; use chrono::Local; +use chrono::OutOfRangeError; use tokio::sync::RwLock; use async_trait::async_trait; @@ -655,17 +656,25 @@ impl Routine { // WORK IN PROGRESS VECTOR - Vec<$RoutineAttr> - let wip_attr:Vec<&RoutineAttr> = vec![ - &RoutineAttr::RunOnce + let wip_attr:Vec = vec![ + RoutineAttr::RunOnce, + RoutineAttr::ScheduledStart(chrono::offset::Local::now()), + RoutineAttr::DelayedStart, ]; - let implemented_attr:Vec<&RoutineAttr> = vec![ + let implemented_attr:Vec = vec![ ]; // [x] 2. Built in Logic will check these vectors, and return if Not Implemented - let mut unimplemented = routine_attr.iter().filter(|x| !wip_attr.contains(x) && !implemented_attr.contains(x)); + let mut unimplemented = routine_attr.iter() + .filter(|x| { + let inx = x; + wip_attr.iter().filter(|y| matches!(y,i if i == inx)).next().is_none() + || implemented_attr.iter().filter(|y| matches!(y,i if i == inx)).next().is_none() + } + ); if unimplemented.next().is_some() { @@ -690,6 +699,23 @@ impl Routine { return Ok("Valid & Implemented Setup".to_string()) } + if routine_attr.contains(&RoutineAttr::RunOnce) & + routine_attr.contains(&RoutineAttr::LoopInfinitely) + { + return Err("Conflicting Routine Attributes".to_string()) + } + + + // [x] Err if DelayedStart but no LoopDuration + if routine_attr.contains(&RoutineAttr::DelayedStart) && + routine_attr.iter() + .filter(|x| matches!(x,&&RoutineAttr::LoopDuration(_)) ) + .next().is_none() + { + return Err("DelayedStart must include a LoopDuration".to_string()) + } + + @@ -837,19 +863,103 @@ impl Routine { ); Log::flush(); - { // Prior to Loop that calls Custom Routine Execution Body + + // [ ] If Scheduled Start or Delayed Start, Handle that first + + + fn duration_to_datetime(future_dt: DateTime) -> Result + { + (future_dt - chrono::offset::Local::now()).to_std() + } + + let delayduration = { + + let lock = trg_routine_ar.read().await; + + let mut related_attrs = lock + .routine_attr.iter() + .filter(|x| matches!(x,&&RoutineAttr::DelayedStart) || matches!(x,&&RoutineAttr::ScheduledStart(_)) ); + + // match related_attrs.next() { + + // } + + async fn duration_from_attr(attr: &RoutineAttr,trg_routine_ar : RoutineAR) -> Option { + // let duration_from_attr = async { + let lock = trg_routine_ar.read().await; + + match attr { + RoutineAttr::ScheduledStart(dt) => { + if let Ok(dur) = duration_to_datetime(*dt) { + Some(dur) + } else { None } + }, + RoutineAttr::DelayedStart => { + let mut loopdur_attr_iter = lock + .routine_attr.iter() + .filter(|x| matches!(x,&&RoutineAttr::LoopDuration(_)) ); + + if let Some(loopdur_attr) = loopdur_attr_iter.next() { + if let RoutineAttr::LoopDuration(dur) = loopdur_attr { + Some(*dur) + } else { None } + } else { None } + // None + }, + _ => { None } // Handle no other combination + } + } + + // The following is done twice just in case ScheduledStart and DelayedStart are defined + let delayduration01 = if let Some(attr) = related_attrs.next() { + duration_from_attr(attr, trg_routine_ar.clone()).await + } else { None }; + + let delayduration02 = if let Some(attr) = related_attrs.next() { + duration_from_attr(attr, trg_routine_ar.clone()).await + } else { None }; + + // if there is a 2nd related duration, pick the minimum, otherwise, pick the results of delayduration01 + if delayduration02.is_some() { + Some(Duration::min(delayduration01.unwrap(),delayduration02.unwrap())) + } else { delayduration01 } + + }; + + + botlog::trace( + format!( + "[TRACE][Routine Processing] {} in {} > Delay Duration - {:?} ", + trg_routine_ar.read().await.name, + trg_routine_ar.read().await.channel.0 , + delayduration , + ) + .as_str(), + Some(format!( + "Routine > start() > (In Tokio Spawn) > {:?}", + trg_routine_ar.read().await.module + )), + Some(&trg_routine_ar.read().await.parent_params.msg), + ); + + if let Some(dur) = delayduration { + sleep(dur).await; + } + + + { // [x] Prior to Loop that calls Custom Routine Execution Body let mut a = trg_routine_ar.write().await; a.start_time = Some(chrono::offset::Local::now()); } - loop { // Routine loop + loop { // [x] Routine loop - // execution body + // [x] execution body trg_routine_ar.read().await.loopbody().await; - { // End of Loop iteration + { // [x] End of Loop iteration let mut a = trg_routine_ar.write().await; a.complete_iterations += 1; if let Some(i) = a.remaining_iterations { @@ -857,8 +967,8 @@ impl Routine { } } - // End of Loop Validation - // These generally may include routine_attr related checks + // [x]End of Loop Validation + // These generally may include routine_attr related checks to , for example, break out of the loop if trg_routine_ar.read().await.routine_attr.contains(&RoutineAttr::RunOnce) { if trg_routine_ar.read().await.complete_iterations > 0 { break; } diff --git a/src/custom/experimental/experiment003.rs b/src/custom/experimental/experiment003.rs index 5537d33..9b8f91e 100644 --- a/src/custom/experimental/experiment003.rs +++ b/src/custom/experimental/experiment003.rs @@ -135,7 +135,7 @@ async fn test3_body(params : ExecBodyParams) { routine_attr, exec_body, params.clone() - ); + ).await;