use std::collections::HashMap; use mongod::{vec_to_api, Model, Referencable, ToAPI}; use mongodb::bson::doc; use rocket::{get, post, serde::json::Json, State}; use serde::{Deserialize, Serialize}; use serde_json::json; use crate::{ check_auth, config::Config, flow::{Flow, FlowInfo}, json_store::JSONStore, routes::{api_error, FallibleApiResponse, Token}, transaction::{Price, Transaction}, }; use super::ApiError; #[get("/flow//info")] pub async fn flow_info( id: &str, flows: &State>, t: Token, c: &State, ) -> FallibleApiResponse { check_auth!(t, c); let flowinfo = flows.get(id).ok_or_else(|| api_error("Flow not found"))?; Ok(flowinfo.api().await) } #[get("/flow//active")] pub async fn active_flows_route( id: &str, flows: &State>, t: Token, c: &State, ) -> 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)) } #[get("/flows")] pub async fn flows_list( flows: &State>, t: Token, c: &State, ) -> FallibleApiResponse { check_auth!(t, c); let mut ret = HashMap::::new(); for l in flows.iter() { ret.insert(l.0.clone(), l.1.api().await); } Ok(json!(ret)) } pub async fn create_flow( kind: &str, flows: &State>, form: &CreateFlow, ) -> Result { 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>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EndFlow { pub produced: Option>>, } #[post("/flow/", data = "
")] pub async fn create_flow_route( id: &str, form: Json, flows: &State>, ) -> FallibleApiResponse { let flow = create_flow(id, flows, &form).await?; Ok(json!({"uuid": flow._id })) } #[get("/flow/")] pub async fn flow_api_route(id: &str) -> FallibleApiResponse { let flow = Flow::get(id) .await .ok_or_else(|| api_error("No such flow"))?; Ok(flow.api().await) } #[post("/flow//end", data = "")] pub async fn end_flow_route(id: &str, form: Json) -> FallibleApiResponse { let flow = Flow::get(id) .await .ok_or_else(|| api_error("Flow not found"))?; if let Some(produced) = &form.produced { let prod = flow.end_with_produce(produced).await?; Ok(json!({"produced": prod})) } else { flow.end().await; Ok(json!({"ok": 1})) } } #[post("/flow//continue", data = "")] pub async fn continue_flow_route( id: &str, flows: &State>, form: Json, ) -> 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})) }