mockforge_http/handlers/
incident_replay.rs1use axum::extract::{Path, Query, State};
4use axum::response::Json;
5use mockforge_chaos::incident_replay::{
6 IncidentFormatAdapter, IncidentReplayGenerator, IncidentTimeline,
7};
8use mockforge_chaos::OrchestratedScenario;
9use serde::{Deserialize, Serialize};
10use serde_json::{json, Value};
11use std::sync::Arc;
12
13#[derive(Clone)]
15pub struct IncidentReplayState {
16 pub generator: Arc<IncidentReplayGenerator>,
18}
19
20impl IncidentReplayState {
21 pub fn new() -> Self {
23 Self {
24 generator: Arc::new(IncidentReplayGenerator::new()),
25 }
26 }
27}
28
29impl Default for IncidentReplayState {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35#[derive(Debug, Deserialize)]
37pub struct GenerateReplayRequest {
38 pub timeline: IncidentTimeline,
40 #[serde(default)]
42 pub format: Option<String>,
43}
44
45#[derive(Debug, Deserialize)]
47pub struct ImportIncidentRequest {
48 pub data: Value,
50 pub format: String,
52}
53
54#[derive(Debug, Serialize)]
56pub struct ReplayGenerationResponse {
57 pub success: bool,
59 pub scenario: OrchestratedScenario,
61 pub scenario_json: String,
63 pub scenario_yaml: String,
65}
66
67pub async fn generate_replay(
71 State(state): State<IncidentReplayState>,
72 Json(request): Json<GenerateReplayRequest>,
73) -> Result<Json<Value>, String> {
74 let generator = &state.generator;
75 let scenario = generator.generate_scenario(&request.timeline);
76
77 let scenario_json = generator
79 .export_scenario_to_json(&scenario)
80 .map_err(|e| format!("Failed to export scenario to JSON: {}", e))?;
81 let scenario_yaml = generator
82 .export_scenario_to_yaml(&scenario)
83 .map_err(|e| format!("Failed to export scenario to YAML: {}", e))?;
84
85 Ok(Json(json!({
86 "success": true,
87 "scenario": scenario,
88 "scenario_json": scenario_json,
89 "scenario_yaml": scenario_yaml,
90 })))
91}
92
93pub async fn import_incident(
97 State(_state): State<IncidentReplayState>,
98 Json(request): Json<ImportIncidentRequest>,
99) -> Result<Json<Value>, String> {
100 let timeline = match request.format.as_str() {
101 "pagerduty" => IncidentFormatAdapter::from_pagerduty(&request.data)
102 .map_err(|e| format!("Failed to parse PagerDuty format: {}", e))?,
103 "datadog" => IncidentFormatAdapter::from_datadog(&request.data)
104 .map_err(|e| format!("Failed to parse Datadog format: {}", e))?,
105 "custom" => {
106 serde_json::from_value::<IncidentTimeline>(request.data)
108 .map_err(|e| format!("Failed to parse custom format: {}", e))?
109 }
110 _ => return Err(format!("Unsupported format: {}", request.format)),
111 };
112
113 Ok(Json(json!({
114 "success": true,
115 "timeline": timeline,
116 })))
117}
118
119pub async fn import_and_generate(
123 State(state): State<IncidentReplayState>,
124 Json(request): Json<ImportIncidentRequest>,
125) -> Result<Json<Value>, String> {
126 let timeline = match request.format.as_str() {
128 "pagerduty" => IncidentFormatAdapter::from_pagerduty(&request.data)
129 .map_err(|e| format!("Failed to parse PagerDuty format: {}", e))?,
130 "datadog" => IncidentFormatAdapter::from_datadog(&request.data)
131 .map_err(|e| format!("Failed to parse Datadog format: {}", e))?,
132 "custom" => serde_json::from_value::<IncidentTimeline>(request.data)
133 .map_err(|e| format!("Failed to parse custom format: {}", e))?,
134 _ => return Err(format!("Unsupported format: {}", request.format)),
135 };
136
137 let generator = &state.generator;
139 let scenario = generator.generate_scenario(&timeline);
140
141 let scenario_json = generator
143 .export_scenario_to_json(&scenario)
144 .map_err(|e| format!("Failed to export scenario to JSON: {}", e))?;
145 let scenario_yaml = generator
146 .export_scenario_to_yaml(&scenario)
147 .map_err(|e| format!("Failed to export scenario to YAML: {}", e))?;
148
149 Ok(Json(json!({
150 "success": true,
151 "timeline": timeline,
152 "scenario": scenario,
153 "scenario_json": scenario_json,
154 "scenario_yaml": scenario_yaml,
155 })))
156}