Skip to main content

vibelang_http/routes/
eval.rs

1//! Eval endpoint handler for executing Rhai code dynamically.
2
3use axum::{extract::State, http::StatusCode, Json};
4use serde::{Deserialize, Serialize};
5use std::sync::Arc;
6use tokio::sync::oneshot;
7
8use crate::AppState;
9
10/// Request body for code evaluation
11#[derive(Debug, Deserialize)]
12pub struct EvalRequest {
13    /// The Rhai code to evaluate
14    pub code: String,
15}
16
17/// Response from code evaluation
18#[derive(Debug, Serialize)]
19pub struct EvalResponse {
20    /// Whether evaluation succeeded
21    pub success: bool,
22    /// Result value (if any)
23    pub result: Option<String>,
24    /// Error message (if failed)
25    pub error: Option<String>,
26}
27
28/// Internal request sent to the main thread for evaluation
29pub struct EvalJob {
30    pub code: String,
31    pub response_tx: oneshot::Sender<EvalResult>,
32}
33
34/// Result of code evaluation
35pub struct EvalResult {
36    pub success: bool,
37    pub result: Option<String>,
38    pub error: Option<String>,
39}
40
41/// POST /eval - Evaluate Rhai code
42pub async fn eval_code(
43    State(state): State<Arc<AppState>>,
44    Json(req): Json<EvalRequest>,
45) -> (StatusCode, Json<EvalResponse>) {
46    // Check if eval channel is available
47    let eval_tx = match &state.eval_tx {
48        Some(tx) => tx,
49        None => {
50            return (
51                StatusCode::SERVICE_UNAVAILABLE,
52                Json(EvalResponse {
53                    success: false,
54                    result: None,
55                    error: Some("Eval not available in this mode".to_string()),
56                }),
57            );
58        }
59    };
60
61    // Create a oneshot channel for the response
62    let (response_tx, response_rx) = oneshot::channel();
63
64    // Send the eval job to the main thread
65    let job = EvalJob {
66        code: req.code,
67        response_tx,
68    };
69
70    if eval_tx.send(job).is_err() {
71        return (
72            StatusCode::INTERNAL_SERVER_ERROR,
73            Json(EvalResponse {
74                success: false,
75                result: None,
76                error: Some("Failed to send eval request".to_string()),
77            }),
78        );
79    }
80
81    // Wait for the result
82    match response_rx.await {
83        Ok(result) => (
84            if result.success {
85                StatusCode::OK
86            } else {
87                StatusCode::BAD_REQUEST
88            },
89            Json(EvalResponse {
90                success: result.success,
91                result: result.result,
92                error: result.error,
93            }),
94        ),
95        Err(_) => (
96            StatusCode::INTERNAL_SERVER_ERROR,
97            Json(EvalResponse {
98                success: false,
99                result: None,
100                error: Some("Eval request cancelled".to_string()),
101            }),
102        ),
103    }
104}