use std::io::Cursor;
use tiny_http::Response;
use crate::handlers::{error_response, json_response, State};
use lex_ast::{stage_id, Stage};
use lex_vcs::{Intent, IntentLog};
pub(crate) fn stages_batch_handler(state: &State, body: &str) -> Response<Cursor<Vec<u8>>> {
let stages: Vec<Stage> = match serde_json::from_str(body) {
Ok(s) => s,
Err(e) => return error_response(400, format!("body must be a JSON array of Stage: {e}")),
};
let store = state.store.lock().unwrap();
let (mut added, mut skipped) = (0usize, 0usize);
for stage in &stages {
let id = match stage_id(stage) {
Some(id) => id,
None => { skipped += 1; continue } };
let existed = store.get_ast(&id).is_ok();
if let Err(e) = store.publish(stage) {
return error_response(500, format!("publish stage {id}: {e}"));
}
if existed { skipped += 1 } else { added += 1 }
}
json_response(200, &serde_json::json!({
"received": stages.len(), "added": added, "skipped": skipped,
}))
}
pub(crate) fn stages_fetch_handler(state: &State, body: &str) -> Response<Cursor<Vec<u8>>> {
let ids = match parse_ids(body) {
Ok(ids) => ids,
Err(resp) => return resp,
};
let store = state.store.lock().unwrap();
let stages: Vec<Stage> = ids.iter().filter_map(|id| store.get_ast(id).ok()).collect();
json_response(200, &serde_json::json!({ "stages": stages }))
}
pub(crate) fn intents_batch_handler(state: &State, body: &str) -> Response<Cursor<Vec<u8>>> {
let intents: Vec<Intent> = match serde_json::from_str(body) {
Ok(i) => i,
Err(e) => return error_response(400, format!("body must be a JSON array of Intent: {e}")),
};
let store = state.store.lock().unwrap();
let log = match IntentLog::open(store.root()) {
Ok(l) => l,
Err(e) => return error_response(500, format!("opening intent log: {e}")),
};
let mut added = 0usize;
for intent in &intents {
let existed = matches!(log.get(&intent.intent_id), Ok(Some(_)));
if let Err(e) = log.put(intent) {
return error_response(500, format!("put intent {}: {e}", intent.intent_id));
}
if !existed { added += 1 }
}
json_response(200, &serde_json::json!({
"received": intents.len(), "added": added,
}))
}
pub(crate) fn intents_fetch_handler(state: &State, body: &str) -> Response<Cursor<Vec<u8>>> {
let ids = match parse_ids(body) {
Ok(ids) => ids,
Err(resp) => return resp,
};
let store = state.store.lock().unwrap();
let log = match IntentLog::open(store.root()) {
Ok(l) => l,
Err(e) => return error_response(500, format!("opening intent log: {e}")),
};
let intents: Vec<Intent> = ids.iter().filter_map(|id| log.get(id).ok().flatten()).collect();
json_response(200, &serde_json::json!({ "intents": intents }))
}
fn parse_ids(body: &str) -> Result<Vec<String>, Response<Cursor<Vec<u8>>>> {
let v: serde_json::Value = serde_json::from_str(body)
.map_err(|e| error_response(400, format!("body must be JSON: {e}")))?;
let ids = v.get("ids").and_then(|i| i.as_array())
.ok_or_else(|| error_response(400, "missing array field `ids`"))?;
Ok(ids.iter().filter_map(|x| x.as_str().map(String::from)).collect())
}