diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs index bbed7fb..b5544cf 100644 --- a/src/core/botmodules.rs +++ b/src/core/botmodules.rs @@ -636,15 +636,15 @@ impl Routine { pub async fn validate_attr(routine_attr : &Vec) -> Result - // [ ] => 03.27 - WIP + // [ ] => 03.27 - REVIEW FOR COMPLETION { /* GENERAL LOGIC : - [ ] 1. Define RoutineAttr in a broad level that are known to be implented or are work in progress - [ ] 2. Built in Logic will check these vectors, and return if Not Implemented - [ ] 3. If Implemented , then there are additional internal validation based on combination done later + [x] 1. Define RoutineAttr in a broad level that are known to be implented or are work in progress + [x] 2. Built in Logic will check these vectors, and return if Not Implemented + [x] 3. If Implemented , then there are additional internal validation based on combination done later */ @@ -657,9 +657,14 @@ impl Routine { // WORK IN PROGRESS VECTOR - Vec<$RoutineAttr> let wip_attr:Vec = vec![ - RoutineAttr::RunOnce, - RoutineAttr::ScheduledStart(chrono::offset::Local::now()), RoutineAttr::DelayedStart, + RoutineAttr::ScheduledStart(chrono::offset::Local::now()), + RoutineAttr::LoopDuration(Duration::from_secs(1)), + RoutineAttr::LoopInfinitely, // Note : There's no added implementation for this + RoutineAttr::RunOnce, + RoutineAttr::MaxTimeThreshold(chrono::offset::Local::now()), + RoutineAttr::MaxIterations(1), + ]; let implemented_attr:Vec = vec![ @@ -693,18 +698,27 @@ impl Routine { - // [ ] 3. If Implemented , then there are additional internal validation based on combination done later + // [x] 3. If Implemented , then there are additional internal validation based on combination done later to ERR - if routine_attr.contains(&RoutineAttr::RunOnce) { - return Ok("Valid & Implemented Setup".to_string()) - } - - if routine_attr.contains(&RoutineAttr::RunOnce) & - routine_attr.contains(&RoutineAttr::LoopInfinitely) + // Below ensures a routine_attr containing LoopInfinitely does not contain conflicit attributes + if routine_attr.contains(&RoutineAttr::LoopInfinitely) && + ( routine_attr.contains(&RoutineAttr::RunOnce) + || routine_attr.iter().filter(|y| matches!(y,&&RoutineAttr::MaxIterations(_))).next().is_some() + || routine_attr.iter().filter(|y| matches!(y,&&RoutineAttr::MaxTimeThreshold(_))).next().is_some() + ) { return Err("Conflicting Routine Attributes".to_string()) } + // [x] if there is no RunOnce, there must be a LoopDuration + if !routine_attr.contains(&RoutineAttr::RunOnce) + && routine_attr.iter() + .filter(|x| matches!(x,&&RoutineAttr::LoopDuration(_)) ) + .next().is_none() + { + return Err("LoopDuration is required if not RunOnce".to_string()); + } + // [x] Err if DelayedStart but no LoopDuration if routine_attr.contains(&RoutineAttr::DelayedStart) && @@ -718,18 +732,44 @@ impl Routine { + // [x] 4. If all other failure checks above works, ensure one more time that the attribute is implemented + // - If not, routine NOT IMPLEMENTED error + if 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() + }) + .next() + .is_none() + { + + botlog::trace( + "[ERROR][Routine Feature NOT IMPLEMENTED]", + Some("Routine > Validate_attr()".to_string()), + None, + ); + Log::flush(); - botlog::trace( - "[ERROR][Routine Feature NOT IMPLEMENTED]", - Some("Routine > Validate_attr()".to_string()), - None, - ); + Ok("Implemented & Validated".to_string()) - Log::flush(); + } else { + + + botlog::trace( + "[ERROR][Routine Feature NOT IMPLEMENTED]", + Some("Routine > Validate_attr()".to_string()), + None, + ); + + Log::flush(); + + Err("NOT IMPLEMENTED".to_string()) + + } - return Err("NOT IMPLEMENTED".to_string()) } @@ -790,11 +830,11 @@ impl Routine { trg_routine_ar : Arc> // ) -> Result ) -> Result>,String> - // [ ] => 03.27 - WIP + // [ ] => 03.27 - REVIEW FOR COMPLETION { - // [ ] Asyncio Spawn likely around here - // [ ] & Assigns self.join_handle + // [x] Asyncio Spawn likely around here + // [x] & Assigns self.join_handle /* @@ -864,16 +904,19 @@ impl Routine { Log::flush(); - // [ ] If Scheduled Start or Delayed Start, Handle that first + // [x] 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 @@ -947,9 +990,17 @@ impl Routine { } - { // [x] Prior to Loop that calls Custom Routine Execution Body + { // [x] Loop Initialization - 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()); + + if let Some(&RoutineAttr::MaxIterations(iternum)) = + a.routine_attr.iter() + .filter(|x| matches!(x,RoutineAttr::MaxIterations(_))) + .next() + { + a.remaining_iterations = Some(iternum); + } } loop { // [x] Routine loop @@ -964,16 +1015,33 @@ impl Routine { a.complete_iterations += 1; if let Some(i) = a.remaining_iterations { if i > 0 { a.remaining_iterations = Some(i-1) ; } + else { break ; } // if remaining iterations is 0, exit } } - // [x]End of Loop Validation + // [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; } } + // return if max time has passed + if let Some(&RoutineAttr::MaxTimeThreshold(dt)) = trg_routine_ar.read().await.routine_attr.iter() + .filter(|x| matches!(x,&&RoutineAttr::MaxTimeThreshold(_)) ) + .next() { + if chrono::offset::Local::now() > dt { break; } + } + + // [x] Checks for Loop duration to sleep + if let Some(&RoutineAttr::LoopDuration(dur)) = trg_routine_ar.read().await.routine_attr.iter() + .filter(|x| matches!(x,&&RoutineAttr::LoopDuration(_)) ) + .next() + { + sleep(dur).await; + }; + + }