diff --git a/src/core/botmodules.rs b/src/core/botmodules.rs index b5544cf..08225a9 100644 --- a/src/core/botmodules.rs +++ b/src/core/botmodules.rs @@ -615,6 +615,14 @@ pub enum RoutineAttr { */ +// For some key statuses and in particular Stopping to Gracefully stop +pub enum RoutineSignal { + Stopping, // Gracefully Stopping + Stopped, // When cancelling or aborting, this also is represented by Stopped + Started, // After Routine Started + NotStarted, +} + // #[derive(Debug)] pub struct Routine { pub name : String , @@ -627,6 +635,7 @@ pub struct Routine { pub complete_iterations : i64 , remaining_iterations : Option , routine_attr : Vec , + pub internal_signal : RoutineSignal , } @@ -807,25 +816,13 @@ impl Routine { start_time : None , complete_iterations : 0 , remaining_iterations : None , - routine_attr : routine_attr + routine_attr : routine_attr , + internal_signal : RoutineSignal::NotStarted , }))) ; } - pub fn change_channel( - &self, - _channel : Channel - ) -> Result - // [ ] => 03.27 - WIP - NOT IMPLEMENTED - { - // [ ] 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( trg_routine_ar : Arc> // ) -> Result @@ -1012,11 +1009,20 @@ impl Routine { { // [x] End of Loop iteration let mut a = trg_routine_ar.write().await; + + // [x] Check if Gracefully Stopping Signal was sent + if matches!(a.internal_signal,RoutineSignal::Stopping) { + a.internal_signal = RoutineSignal::Stopped; + break ; + } + + // [x] Check and adjust iterations 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 @@ -1078,16 +1084,21 @@ impl Routine { trg_routine_ar }); - trg_routine_arout.write().await.join_handle = Some(Arc::new(RwLock::new(join_handle))); - // } + { // Recommendation to ensure a clean update is to use one write() lock that was awaited + // - We can isolate the write lock by ensuring it's in it's own block + let mut lock = trg_routine_arout.write().await; + lock.join_handle = Some(Arc::new(RwLock::new(join_handle))); + lock.internal_signal = RoutineSignal::Started; + + } + trg_routine_arout.write().await.internal_signal = RoutineSignal::Started; return Ok(trg_routine_arout); } - async fn loopbody(&self) // [x] => 03.27 - COMPLETED { @@ -1106,18 +1117,24 @@ impl Routine { ).await; } - pub async fn stop(&self) -> Result - // [ ] => 03.27 - WIP - NOT IMPLEMENTED + pub async fn stop(&mut self) -> Result + // [ ] => 03.27 - REVIEW FOR COMPLETION { let self_rw = Arc::new(RwLock::new(self)); + + { + let mut self_lock = self_rw.write().await; + self_lock.internal_signal = RoutineSignal::Stopping; + } + + let self_lock = self_rw.read().await; - botlog::trace( format!( - "[ERROR][Routine NOT IMPLEMENTED] {} in {}", + "[ROUTINE][Sent Gracefully Stopp Signal] {} in {}", self_lock.name,self_lock.channel.0 ) .as_str(), @@ -1130,37 +1147,24 @@ impl Routine { Log::flush(); - Err("NOT IMPLEMENTED".to_string()) - } + Ok("Sent Gracefully Stop Signal".to_string()) - pub async fn restart( - &self, - _force : bool - ) -> Result - // [ ] => 03.27 - WIP - NOT IMPLEMENTED - { - // force flag aborts the routine immediately (like cancel()) + // 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), + // ); - - let self_rw = Arc::new(RwLock::new(self)); - let self_lock = self_rw.read().await; - + // Log::flush(); - 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()) + // Err("NOT IMPLEMENTED".to_string()) } pub async fn cancel(&self) -> Result @@ -1194,6 +1198,48 @@ impl Routine { Err("NOT IMPLEMENTED".to_string()) } + pub async fn restart( + &self, + _force : bool + ) -> Result + // [ ] => 03.27 - WIP - NOT IMPLEMENTED + { + // 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 fn change_channel( + &self, + _channel : Channel + ) -> Result + // [ ] => 03.27 - WIP - NOT IMPLEMENTED + { + // [ ] Think Ideally it should try to + // change the target channel of the + // internal process too if possible? + + Err("NOT IMPLEMENTED".to_string()) + } }