Skip to main content

graphwalker_restful/
rest.rs

1use std::sync::mpsc;
2
3use axum::extract::{Path, State};
4use axum::http::StatusCode;
5use axum::response::Json;
6use serde_json::{json, Value};
7use tokio::sync::oneshot;
8
9use crate::actor::Command;
10
11#[derive(Clone)]
12pub struct RestState {
13    pub machine_tx: mpsc::Sender<Command>,
14    pub default_seed: Option<u64>,
15}
16
17async fn send_command(
18    tx: &mpsc::Sender<Command>,
19    build: impl FnOnce(oneshot::Sender<Result<Value, String>>) -> Command,
20) -> (StatusCode, Json<Value>) {
21    let (reply_tx, reply_rx) = oneshot::channel();
22    if tx.send(build(reply_tx)).is_err() {
23        return (
24            StatusCode::INTERNAL_SERVER_ERROR,
25            Json(json!({"result": "nok", "error": "Machine thread unavailable"})),
26        );
27    }
28    match reply_rx.await {
29        Ok(Ok(val)) => (StatusCode::OK, Json(val)),
30        Ok(Err(msg)) => (StatusCode::OK, Json(json!({"result": "nok", "error": msg}))),
31        Err(_) => (
32            StatusCode::INTERNAL_SERVER_ERROR,
33            Json(json!({"result": "nok", "error": "Machine thread dropped"})),
34        ),
35    }
36}
37
38pub async fn load(State(state): State<RestState>, body: String) -> (StatusCode, Json<Value>) {
39    tracing::debug!(body_length = body.len(), "REST load request");
40    send_command(&state.machine_tx, |reply| Command::Load {
41        json_body: body,
42        seed: state.default_seed,
43        global_data: None,
44        reply,
45    })
46    .await
47}
48
49pub async fn has_next(State(state): State<RestState>) -> (StatusCode, Json<Value>) {
50    send_command(&state.machine_tx, |reply| Command::HasNext { reply }).await
51}
52
53pub async fn get_next(State(state): State<RestState>) -> (StatusCode, Json<Value>) {
54    tracing::trace!("REST next-step request");
55    send_command(&state.machine_tx, |reply| Command::GetNext {
56        verbose: false,
57        reply,
58    })
59    .await
60}
61
62pub async fn get_data(State(state): State<RestState>) -> (StatusCode, Json<Value>) {
63    send_command(&state.machine_tx, |reply| Command::GetData { reply }).await
64}
65
66pub async fn set_data(
67    State(state): State<RestState>,
68    Path(script): Path<String>,
69) -> (StatusCode, Json<Value>) {
70    tracing::debug!(script_length = script.len(), "REST set-data request");
71    send_command(&state.machine_tx, |reply| Command::SetData {
72        script,
73        reply,
74    })
75    .await
76}
77
78pub async fn restart(State(state): State<RestState>) -> (StatusCode, Json<Value>) {
79    tracing::debug!("REST restart request");
80    send_command(&state.machine_tx, |reply| Command::Restart { reply }).await
81}
82
83pub async fn get_statistics(State(state): State<RestState>) -> (StatusCode, Json<Value>) {
84    send_command(&state.machine_tx, |reply| Command::GetStatistics { reply }).await
85}