Skip to content

Instantly share code, notes, and snippets.

@boj
Last active October 11, 2025 00:48
Show Gist options
  • Select an option

  • Save boj/ff0f25558a9ece405b1f6e4a5e0a9126 to your computer and use it in GitHub Desktop.

Select an option

Save boj/ff0f25558a9ece405b1f6e4a5e0a9126 to your computer and use it in GitHub Desktop.
DMCA FSM Example
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