#![allow(dead_code)] // Allow dead code for demo purposes use md5; use rand::{self, Rng}; // Add `rand = "0.8"` and `md5 = "0.7"` to your Cargo.toml #[derive(Debug, Clone)] // Derive Clone to simplify state updates in the example enum WebhookProcessingState { AwaitingPayload { webhook_id: String }, PayloadReceived { webhook_id: String, payload_hash: String }, Processing { webhook_id: String, handler_id: String, start_time_ms: u64 }, Completed { webhook_id: String, status_code: u16, end_time_ms: u64 }, Failed { webhook_id: String, error_reason: String, failed_time_ms: u64 }, } impl WebhookProcessingState { /// Attempts to transition the webhook state safely. /// Returns a new state or an error if the transition is invalid. /// This prevents transitioning to an illogical state or accessing irrelevant data. fn try_advance(self) -> Result { match self { WebhookProcessingState::AwaitingPayload { webhook_id } => { println!("Webhook {} received payload.", webhook_id); Ok(WebhookProcessingState::PayloadReceived { webhook_id: webhook_id, payload_hash: format!("{:x}", md5::compute(format!("{}-payload", webhook_id))), // Simulate payload hashing }) } WebhookProcessingState::PayloadReceived { webhook_id, payload_hash } => { println!("Webhook {} (hash {}) starting processing.", webhook_id, payload_hash); Ok(WebhookProcessingState::Processing { webhook_id: webhook_id, handler_id: "worker-node-1".to_string(), start_time_ms: 1_678_886_400_000, // Example timestamp }) } WebhookProcessingState::Processing { webhook_id, handler_id, start_time_ms } => { println!("Webhook {} processed by {} started at {}.", webhook_id, handler_id, start_time_ms); let mut rng = rand::thread_rng(); if rng.gen_bool(0.7) { // 70% chance of success Ok(WebhookProcessingState::Completed { webhook_id: webhook_id, status_code: 200, end_time_ms: 1_678_886_401_000, // Example timestamp }) } else { Ok(WebhookProcessingState::Failed { webhook_id: webhook_id, error_reason: "Simulated processing error".to_string(), failed_time_ms: 1_678_886_401_000, // Example timestamp }) } } // All other states (Completed, Failed) are terminal and cannot be advanced from. _ => Err(format!("Cannot advance from terminal state: {:?}", self)), } } } fn main() { let mut state = WebhookProcessingState::AwaitingPayload { webhook_id: "wh-001".to_string() }; println!("Initial: {:?}", state); state = state.try_advance().expect("Failed to advance state"); println!("-> {:?}", state); state = state.try_advance().expect("Failed to advance state"); println!("-> {:?}", state); state = state.try_advance().expect("Failed to advance state"); println!("-> {:?}", state); // This will likely result in an error as it's a terminal state match state.try_advance() { Ok(s) => println!("-> {:?}", s), Err(e) => println!("Error advancing: {}", e), } }