use axum::{
extract::{Path, State},
http::StatusCode,
response::Json,
};
use tracing::*;
use super::ManagementState;
use super::MockConfig;
pub(crate) async fn list_mocks(State(state): State<ManagementState>) -> Json<serde_json::Value> {
let mocks = state.mocks.read().await;
Json(serde_json::json!({
"mocks": *mocks,
"total": mocks.len(),
"enabled": mocks.iter().filter(|m| m.enabled).count()
}))
}
pub(crate) async fn get_mock(
State(state): State<ManagementState>,
Path(id): Path<String>,
) -> Result<Json<MockConfig>, StatusCode> {
let mocks = state.mocks.read().await;
mocks
.iter()
.find(|m| m.id == id)
.cloned()
.map(Json)
.ok_or(StatusCode::NOT_FOUND)
}
pub(crate) async fn create_mock(
State(state): State<ManagementState>,
Json(mut mock): Json<MockConfig>,
) -> Result<Json<MockConfig>, StatusCode> {
let mut mocks = state.mocks.write().await;
if mock.id.is_empty() {
mock.id = uuid::Uuid::new_v4().to_string();
}
if mocks.iter().any(|m| m.id == mock.id) {
return Err(StatusCode::CONFLICT);
}
info!("Creating mock: {} {} {}", mock.method, mock.path, mock.id);
if let Some(hooks) = &state.lifecycle_hooks {
let event = mockforge_core::lifecycle::MockLifecycleEvent::Created {
id: mock.id.clone(),
name: mock.name.clone(),
config: serde_json::to_value(&mock).unwrap_or_default(),
};
hooks.invoke_mock_created(&event).await;
}
mocks.push(mock.clone());
if let Some(tx) = &state.ws_broadcast {
let _ = tx.send(crate::management_ws::MockEvent::mock_created(mock.clone()));
}
Ok(Json(mock))
}
pub(crate) async fn update_mock(
State(state): State<ManagementState>,
Path(id): Path<String>,
Json(updated_mock): Json<MockConfig>,
) -> Result<Json<MockConfig>, StatusCode> {
let mut mocks = state.mocks.write().await;
let position = mocks.iter().position(|m| m.id == id).ok_or(StatusCode::NOT_FOUND)?;
let old_mock = mocks[position].clone();
info!("Updating mock: {}", id);
mocks[position] = updated_mock.clone();
if let Some(hooks) = &state.lifecycle_hooks {
let event = mockforge_core::lifecycle::MockLifecycleEvent::Updated {
id: updated_mock.id.clone(),
name: updated_mock.name.clone(),
config: serde_json::to_value(&updated_mock).unwrap_or_default(),
};
hooks.invoke_mock_updated(&event).await;
if old_mock.enabled != updated_mock.enabled {
let state_event = if updated_mock.enabled {
mockforge_core::lifecycle::MockLifecycleEvent::Enabled {
id: updated_mock.id.clone(),
}
} else {
mockforge_core::lifecycle::MockLifecycleEvent::Disabled {
id: updated_mock.id.clone(),
}
};
hooks.invoke_mock_state_changed(&state_event).await;
}
}
if let Some(tx) = &state.ws_broadcast {
let _ = tx.send(crate::management_ws::MockEvent::mock_updated(updated_mock.clone()));
}
Ok(Json(updated_mock))
}
pub(crate) async fn delete_mock(
State(state): State<ManagementState>,
Path(id): Path<String>,
) -> Result<StatusCode, StatusCode> {
let mut mocks = state.mocks.write().await;
let position = mocks.iter().position(|m| m.id == id).ok_or(StatusCode::NOT_FOUND)?;
let deleted_mock = mocks[position].clone();
info!("Deleting mock: {}", id);
mocks.remove(position);
if let Some(hooks) = &state.lifecycle_hooks {
let event = mockforge_core::lifecycle::MockLifecycleEvent::Deleted {
id: deleted_mock.id.clone(),
name: deleted_mock.name.clone(),
};
hooks.invoke_mock_deleted(&event).await;
}
if let Some(tx) = &state.ws_broadcast {
let _ = tx.send(crate::management_ws::MockEvent::mock_deleted(id.clone()));
}
Ok(StatusCode::NO_CONTENT)
}