use clap::{Args, Subcommand};
use graphforge_api::{CancellationToken, GfError, GraphForge};
use std::{
io::{Read, Write},
path::PathBuf,
};
#[derive(Args)]
pub(crate) struct Request {
#[arg(long)]
file: PathBuf,
}
#[derive(Subcommand)]
pub(crate) enum ClaimCommand {
Create(Request),
Relate(Request),
ChangeBranch(Request),
Decide(Request),
Inspect(Request),
History(Request),
Decisions(Request),
Canonical(Request),
}
fn request<T: serde::de::DeserializeOwned>(args: Request) -> Result<T, GfError> {
let file = std::fs::File::open(args.file)
.map_err(|_| GfError::Validation("cannot open research claim request".into()))?;
let mut bytes = Vec::new();
file.take(2 * 1024 * 1024 + 1)
.read_to_end(&mut bytes)
.map_err(|_| GfError::Validation("cannot read research claim request".into()))?;
if bytes.len() > 2 * 1024 * 1024 {
return Err(GfError::Api {
code: graphforge_api::ApiErrorCode::ResourceLimit,
message: "research claim request exceeds byte limit".into(),
});
}
serde_json::from_slice(&bytes)
.map_err(|_| GfError::Validation("invalid contextual research JSON contract".into()))
}
pub(crate) fn run(
graph: &mut GraphForge,
command: ClaimCommand,
json: bool,
output: &mut dyn Write,
) -> Result<(), GfError> {
let token = CancellationToken::new();
let result = match command {
ClaimCommand::Create(args) => graph.create_research_claim(&request(args)?, &token)?,
ClaimCommand::Relate(args) => graph.relate_research_claims(&request(args)?, &token)?,
ClaimCommand::Decide(args) => graph.record_research_decisions(&request(args)?, &token)?,
ClaimCommand::Inspect(args) => graph.inspect_research_claims(&request(args)?)?,
ClaimCommand::History(args) => graph.research_claim_history(&request(args)?)?,
ClaimCommand::Decisions(args) => {
let q: graphforge_api::ResearchAuthorityQuery = request(args)?;
graph.research_decision_history(&q.context, q.community_uuid)?
}
ClaimCommand::Canonical(args) => {
let q: graphforge_api::ResearchAuthorityQuery = request(args)?;
graph.research_canonical_choices(&q.context, q.community_uuid)?
}
ClaimCommand::ChangeBranch(args) => {
let receipt = graph.change_research_branch_claim(&request(args)?, &token)?;
serde_json::to_writer(&mut *output, &receipt)
.map_err(|e| GfError::Execution(e.to_string()))?;
return writeln!(output).map_err(|e| GfError::Execution(e.to_string()));
}
};
crate::write_execution_result(&result, json, output)
}