Archived
110 lines
3.4 KiB
Rust
110 lines
3.4 KiB
Rust
/// Transaction API routes.
|
|
///
|
|
/// POST /tx/apply — apply a command
|
|
/// POST /tx/rollback/{id} — roll back a command
|
|
/// GET /tx/history?since={ms} — command history
|
|
/// GET /tx/chain/{id} — causal chain for a command
|
|
use axum::{
|
|
extract::{Path, Query, State},
|
|
http::StatusCode,
|
|
Json,
|
|
};
|
|
use engram_tx::{Command, CommandResult};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::sync::Arc;
|
|
use uuid::Uuid;
|
|
|
|
use crate::state::AppState;
|
|
|
|
// ── POST /tx/apply ────────────────────────────────────────────────────────────
|
|
|
|
pub async fn tx_apply(
|
|
State(state): State<Arc<AppState>>,
|
|
Json(cmd): Json<Command>,
|
|
) -> Result<Json<CommandResult>, StatusCode> {
|
|
let mut engine = state
|
|
.tx_engine
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
let result = engine
|
|
.apply(cmd)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
Ok(Json(result))
|
|
}
|
|
|
|
// ── POST /tx/rollback/{command_id} ───────────────────────────────────────────
|
|
|
|
#[derive(Serialize)]
|
|
pub struct RollbackResponse {
|
|
pub rollback_command_id: Uuid,
|
|
pub status: String,
|
|
}
|
|
|
|
pub async fn tx_rollback(
|
|
State(state): State<Arc<AppState>>,
|
|
Path(command_id): Path<Uuid>,
|
|
) -> Result<Json<RollbackResponse>, StatusCode> {
|
|
let mut engine = state
|
|
.tx_engine
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
let rb = engine
|
|
.rollback(command_id)
|
|
.map_err(|e| {
|
|
tracing::warn!("rollback failed: {}", e);
|
|
StatusCode::BAD_REQUEST
|
|
})?;
|
|
Ok(Json(RollbackResponse {
|
|
rollback_command_id: rb.id,
|
|
status: format!("{:?}", rb.status),
|
|
}))
|
|
}
|
|
|
|
// ── GET /tx/history ───────────────────────────────────────────────────────────
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct HistoryParams {
|
|
pub since: Option<i64>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct HistoryResponse {
|
|
pub commands: Vec<Command>,
|
|
}
|
|
|
|
pub async fn tx_history(
|
|
State(state): State<Arc<AppState>>,
|
|
Query(params): Query<HistoryParams>,
|
|
) -> Result<Json<HistoryResponse>, StatusCode> {
|
|
let engine = state
|
|
.tx_engine
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
let since = params.since.unwrap_or(0);
|
|
let commands = engine
|
|
.history(since)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
Ok(Json(HistoryResponse { commands }))
|
|
}
|
|
|
|
// ── GET /tx/chain/{command_id} ────────────────────────────────────────────────
|
|
|
|
#[derive(Serialize)]
|
|
pub struct CausalChainResponse {
|
|
pub chain: Vec<Command>,
|
|
}
|
|
|
|
pub async fn tx_causal_chain(
|
|
State(state): State<Arc<AppState>>,
|
|
Path(command_id): Path<Uuid>,
|
|
) -> Result<Json<CausalChainResponse>, StatusCode> {
|
|
let engine = state
|
|
.tx_engine
|
|
.lock()
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
let chain = engine
|
|
.causal_chain(command_id)
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
Ok(Json(CausalChainResponse { chain }))
|
|
}
|