WIP: Basic Routine Functionality #40

Draft
modulatingforce wants to merge 23 commits from routines-functionality into master
2 changed files with 121 additions and 11 deletions
Showing only changes of commit e963ae250d - Show all commits

View file

@ -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<RoutineAttr> = vec![
RoutineAttr::RunOnce,
RoutineAttr::ScheduledStart(chrono::offset::Local::now()),
RoutineAttr::DelayedStart,
];
let implemented_attr:Vec<&RoutineAttr> = vec![
let implemented_attr:Vec<RoutineAttr> = 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<Local>) -> Result<Duration,OutOfRangeError>
{
(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<Duration> {
// 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; }

View file

@ -135,7 +135,7 @@ async fn test3_body(params : ExecBodyParams) {
routine_attr,
exec_body,
params.clone()
);
).await;