Last active
October 11, 2025 00:48
-
-
Save boj/ff0f25558a9ece405b1f6e4a5e0a9126 to your computer and use it in GitHub Desktop.
DMCA FSM Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::fmt::debug; | |
| type CustomerId = i32; | |
| type InfringementId = i32; | |
| pub enum Event { | |
| Init, | |
| Build, | |
| Execute, | |
| Done, | |
| } | |
| #[derive(Debug)] | |
| pub struct Processor { | |
| customer_id: CustomerId, | |
| infringement_id: InfringementId, | |
| state: Option<Box<dyn State>>, | |
| } | |
| impl Processor { | |
| pub fn new(customer_id: CustomerId, infringement_id: InfringementId) -> Processor { | |
| Processor { | |
| state: Some(Box::new(Init {})), | |
| customer_id, | |
| infringement_id, | |
| } | |
| } | |
| pub fn handle_event(&mut self, event: Event) { | |
| if let Some(state) = self.state.take() { | |
| self.state = Some(state.handle_event(event, self)); | |
| } | |
| } | |
| } | |
| trait State { | |
| fn handle_event(self: Box<Self>, _event: Event, _processor: Processor) -> Box<dyn State>; | |
| } | |
| // State logic | |
| struct Init {} | |
| impl State for Init { | |
| fn handle_event(self: Box<Self>, event: Event, processor: &mut Processor) -> Box<dyn State> { | |
| match event { | |
| Event::Build => self.build(), | |
| _ => self, // noop | |
| } | |
| } | |
| } | |
| // Business logic | |
| impl Init { | |
| fn build(self: Box<Self>) -> Box<dyn State> { | |
| // query self.customer_id | |
| // move into next strike state based on processing logic | |
| let n = 1; // pretend we're on strike 1 | |
| match n { | |
| 1 => Box::new(Strike1), | |
| 2 => Box::new(Strike1), | |
| 3 => Box::new(Strike1), | |
| // 2 => Box::new(Strike2), | |
| // 3 => Box::new(Strike3), | |
| // 4 => Box::new(Strike4), | |
| // 5 => Box::new(Strike5), | |
| 61 => Box::new(Strike6_Step1), | |
| 62 => Box::new(Strike6_Step2), | |
| // 7 => Box::new(Strike7), | |
| _ => self, // error out if we somehow increment over the max | |
| } | |
| } | |
| } | |
| // State logic | |
| struct Strike1 {} | |
| impl State for Strike1 { | |
| fn handle_event(self: Box<Self>, event: Event, processor: &mut Processor) -> Box<dyn State> { | |
| match event { | |
| Event::Execute => self.execute(); | |
| _ => self, // noop | |
| } | |
| } | |
| } | |
| impl Strike1 { | |
| fn execute(&self) { | |
| // query self.customer_id and their strike count | |
| // email customer the violation | |
| // record the new strike customer is on | |
| // record the strike count in commv | |
| } | |
| } | |
| // State logic | |
| struct Strike6_Step1 {} | |
| impl State for Strike6_Step1 { | |
| fn handle_event(self: Box<Self>, event: Event, processor: &mut Processor) -> Box<dyn State> { | |
| match event { | |
| Event::Execute => self.execute(); | |
| _ => self, // noop | |
| } | |
| } | |
| } | |
| impl Strike6_Step1 { | |
| fn execute(&self) { | |
| // query self.customer_id | |
| // email customer the violation | |
| // email sales if it's a business | |
| // send a docusign form | |
| // write that customer was on strike6_step1 to database | |
| } | |
| } | |
| // State logic | |
| struct Strike6_Step2 {} | |
| impl State for Strike6_Step2 { | |
| fn handle_event(self: Box<Self>, event: Event, processor: &mut Processor) -> Box<dyn State> { | |
| match event { | |
| Event::Execute => self.execute(); | |
| _ => self, // noop | |
| } | |
| } | |
| } | |
| impl Strike6_Step2 { | |
| fn execute(&self) { | |
| // check docusign api | |
| // docusign form signed, move forward | |
| // or if over the wait time of 5 or 7 days, move to strike7 | |
| } | |
| } | |
| fn main() { | |
| // process exchange emails & process any strikes in a "retry" state & stepwise states | |
| // for each customer that received a violation, send them into the FSM | |
| let customer_id = 1; // fictional customer | |
| // create new fsm | |
| let mut fsm = Processor::new(customer_id); | |
| // seed fsm and build current strike for customer | |
| fsm.handle_event(Event::Build); | |
| // process strike | |
| fsm.handle_event(Event::Execute); | |
| // and that's it. the job runs again at the scheduled time | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment