cdb/src/routes/flow.rs

184 lines
4.4 KiB
Rust
Raw Normal View History

2024-09-12 10:34:14 +02:00
use std::collections::HashMap;
2024-09-19 08:38:37 +02:00
use mongod::{vec_to_api, Model, Referencable, ToAPI};
use mongodb::bson::doc;
2024-09-12 16:55:36 +02:00
use rocket::{get, post, serde::json::Json, State};
use serde::{Deserialize, Serialize};
2024-09-12 10:34:14 +02:00
use serde_json::json;
use crate::{
check_auth,
config::Config,
2024-09-12 16:55:36 +02:00
flow::{Flow, FlowInfo},
2024-09-12 10:34:14 +02:00
json_store::JSONStore,
routes::{api_error, FallibleApiResponse, Token},
2024-09-12 16:55:36 +02:00
transaction::{Price, Transaction},
2024-09-12 10:34:14 +02:00
};
2024-09-12 16:55:36 +02:00
use super::ApiError;
2024-09-12 10:34:14 +02:00
#[get("/flow/<id>/info")]
pub async fn flow_info(
id: &str,
flows: &State<JSONStore<FlowInfo>>,
t: Token,
c: &State<Config>,
) -> FallibleApiResponse {
check_auth!(t, c);
let flowinfo = flows.get(id).ok_or_else(|| api_error("Flow not found"))?;
Ok(flowinfo.api().await)
}
2024-09-19 08:38:37 +02:00
#[get("/flow/<id>/active")]
pub async fn active_flows_route(
id: &str,
flows: &State<JSONStore<FlowInfo>>,
t: Token,
c: &State<Config>,
) -> FallibleApiResponse {
check_auth!(t, c);
let flowinfo = flows.get(id).ok_or_else(|| api_error("Flow not found"))?;
let flow = Flow::find(
doc! {
"kind": flowinfo.reference(),
"done": { "$not": { "$type": "object" } }
},
None,
None,
)
.await
.unwrap();
Ok(json!(vec_to_api(&flow).await))
}
2024-09-12 10:34:14 +02:00
#[get("/flows")]
pub async fn flows_list(
flows: &State<JSONStore<FlowInfo>>,
t: Token,
c: &State<Config>,
) -> FallibleApiResponse {
check_auth!(t, c);
let mut ret = HashMap::<String, serde_json::Value>::new();
for l in flows.iter() {
ret.insert(l.0.clone(), l.1.api().await);
}
Ok(json!(ret))
}
2024-09-12 16:55:36 +02:00
pub async fn create_flow(
kind: &str,
flows: &State<JSONStore<FlowInfo>>,
form: &CreateFlow,
) -> Result<Flow, ApiError> {
let info = flows.get(kind).ok_or_else(|| api_error("Unknown Flow"))?;
let mut input_ref = Vec::new();
// verify valid input transactions
if let Some(input) = &form.input {
for t in input {
let t = Transaction::get(t)
.await
.ok_or_else(|| api_error(&format!("No such transaction {t}")))?;
let item_variant = format!("{}::{}", t.item, t.variant);
let valid = info.depends.iter().any(|x| item_variant.starts_with(x));
if !valid {
return Err(api_error(&format!(
"Invalid item variant. This flow only accepts {:?}",
info.depends
)));
}
input_ref.push(t);
}
}
let flow = Flow::create(
kind,
if input_ref.is_empty() {
None
} else {
Some(input_ref.iter().map(|x| x.reference()).collect())
},
)
.await;
for t in input_ref {
t.consume(Price::zero(), &format!("flow::{kind}::{}", flow._id))
.await;
}
Ok(flow)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateFlow {
pub input: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EndFlow {
pub produced: Option<Vec<HashMap<String, u64>>>,
}
#[post("/flow/<id>", data = "<form>")]
pub async fn create_flow_route(
id: &str,
form: Json<CreateFlow>,
flows: &State<JSONStore<FlowInfo>>,
) -> FallibleApiResponse {
let flow = create_flow(id, flows, &form).await?;
Ok(json!({"uuid": flow._id }))
}
#[post("/flow/<id>/end", data = "<form>")]
pub async fn end_flow_route(id: &str, form: Json<EndFlow>) -> FallibleApiResponse {
let flow = Flow::get(id)
.await
.ok_or_else(|| api_error("Flow not found"))?;
if let Some(produced) = &form.produced {
2024-09-13 14:17:55 +02:00
let prod = flow.end_with_produce(produced).await?;
2024-09-12 16:55:36 +02:00
Ok(json!({"produced": prod}))
} else {
flow.end().await;
Ok(json!({"ok": 1}))
}
}
#[post("/flow/<id>/continue", data = "<form>")]
pub async fn continue_flow_route(
id: &str,
flows: &State<JSONStore<FlowInfo>>,
form: Json<CreateFlow>,
) -> FallibleApiResponse {
let this_flow = Flow::get(id)
.await
.ok_or_else(|| api_error("Flow not found"))?;
// create next flow
let next_kind = flows
.get(this_flow.kind.id())
.ok_or_else(|| api_error("Flow not found"))?
.next
.clone()
.ok_or_else(|| api_error("Flow has no continuation"))?;
let next_flow = create_flow(&next_kind, flows, &form).await?;
// end current flow
this_flow.continue_next(&next_flow).await;
Ok(json!({"uuid": next_flow._id}))
}