kotoba_server_workflow/
handlers.rs

1//! Workflow HTTP handlers
2
3use axum::{
4    extract::{Path as AxumPath, State},
5    response::Json,
6    http::StatusCode,
7};
8use serde::{Deserialize, Serialize};
9use std::sync::Arc;
10use chrono::{DateTime, Utc};
11
12#[cfg(feature = "workflow")]
13use crate::{WorkflowEngineInterface, WorkflowExecutionId, WorkflowIR, WorkflowExecution};
14
15/// Shared state for workflow handlers
16#[cfg(feature = "workflow")]
17#[derive(Clone)]
18pub struct WorkflowState<E> {
19    pub engine: Arc<E>,
20}
21
22#[cfg(feature = "workflow")]
23impl<E> WorkflowState<E> {
24    pub fn new(engine: E) -> Self {
25        Self {
26            engine: Arc::new(engine),
27        }
28    }
29}
30
31/// Start workflow response
32#[derive(Debug, Serialize, Deserialize)]
33pub struct StartWorkflowResponse {
34    pub execution_id: String,
35}
36
37/// Workflow API handler
38#[cfg(feature = "workflow")]
39#[derive(Clone)]
40pub struct WorkflowApiHandler<E> {
41    state: WorkflowState<E>,
42}
43
44#[cfg(feature = "workflow")]
45impl<E> WorkflowApiHandler<E>
46where
47    E: WorkflowEngineInterface + Send + Sync + 'static,
48{
49    pub fn new(engine: E) -> Self {
50        Self {
51            state: WorkflowState::new(engine),
52        }
53    }
54
55    pub async fn start_workflow(
56        State(state): State<WorkflowState<E>>,
57        Json(payload): Json<WorkflowIR>,
58    ) -> Result<Json<StartWorkflowResponse>, (StatusCode, String)> {
59        let execution_id = state.engine
60            .start_workflow(&payload, serde_json::Value::Null)
61            .await
62            .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
63
64        Ok(Json(StartWorkflowResponse {
65            execution_id: execution_id.0,
66        }))
67    }
68
69    pub async fn get_workflow_status(
70        State(state): State<WorkflowState<E>>,
71        AxumPath(execution_id): AxumPath<String>,
72    ) -> Result<Json<WorkflowExecution>, (StatusCode, String)> {
73        let exec_id = WorkflowExecutionId(execution_id);
74        let execution = state.engine
75            .get_execution(&exec_id)
76            .await
77            .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
78            .ok_or_else(|| (StatusCode::NOT_FOUND, "Workflow execution not found".to_string()))?;
79
80        Ok(Json(execution))
81    }
82
83    pub async fn list_workflows(
84        State(state): State<WorkflowState<E>>,
85    ) -> Result<Json<Vec<WorkflowExecution>>, (StatusCode, String)> {
86        let executions = state.engine
87            .list_executions()
88            .await
89            .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
90
91        Ok(Json(executions))
92    }
93
94    pub async fn cancel_workflow(
95        State(state): State<WorkflowState<E>>,
96        AxumPath(execution_id): AxumPath<String>,
97    ) -> Result<StatusCode, (StatusCode, String)> {
98        let exec_id = WorkflowExecutionId(execution_id);
99        state.engine
100            .cancel_execution(&exec_id)
101            .await
102            .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
103
104        Ok(StatusCode::NO_CONTENT)
105    }
106}
107
108/// Workflow status handler for simpler use cases
109#[derive(Clone)]
110pub struct WorkflowStatusHandler;
111
112impl WorkflowStatusHandler {
113    pub fn new() -> Self {
114        Self
115    }
116
117    pub async fn health() -> Result<Json<serde_json::Value>, (StatusCode, String)> {
118        Ok(Json(serde_json::json!({
119            "status": "workflow_integration_available",
120            "version": env!("CARGO_PKG_VERSION")
121        })))
122    }
123}
124
125impl Default for WorkflowStatusHandler {
126    fn default() -> Self {
127        Self::new()
128    }
129}
130
131/// Workflow API response types
132#[derive(Debug, Serialize, Deserialize)]
133pub struct WorkflowListResponse {
134    pub workflows: Vec<WorkflowSummary>,
135    pub total: usize,
136}
137
138#[derive(Debug, Serialize, Deserialize)]
139pub struct WorkflowSummary {
140    pub execution_id: String,
141    pub status: String,
142    pub created_at: DateTime<Utc>,
143    pub updated_at: DateTime<Utc>,
144}