greentic-flow 0.4.63

Generic YGTC flow schema/loader/IR for self-describing component nodes.
Documentation
use anyhow::{Result, anyhow};
use greentic_types::cbor::canonical;
use greentic_types::schemas::component::v0_6_0::{
    ComponentDescribe, ComponentOperation, schema_hash,
};
use sha2::{Digest, Sha256};

pub fn decode_component_describe(bytes: &[u8]) -> Result<ComponentDescribe> {
    if bytes.is_empty() {
        return Err(anyhow!("describe() returned empty payload"));
    }
    let describe: ComponentDescribe =
        canonical::from_cbor(bytes).map_err(|err| anyhow!("decode describe cbor: {err}"))?;
    Ok(describe)
}

pub fn describe_hash(describe: &ComponentDescribe) -> Result<String> {
    let bytes = canonical::to_canonical_cbor_allow_floats(describe)
        .map_err(|err| anyhow!("encode describe for hashing: {err}"))?;
    let digest = Sha256::digest(bytes.as_slice());
    let mut hex = String::with_capacity(digest.len() * 2);
    for byte in digest {
        hex.push_str(&format!("{byte:02x}"));
    }
    Ok(hex)
}

pub fn find_operation<'a>(
    describe: &'a ComponentDescribe,
    operation_id: &str,
) -> Result<&'a ComponentOperation> {
    for op in &describe.operations {
        if op.id == operation_id {
            return Ok(op);
        }
    }
    Err(anyhow!(
        "operation '{}' not found in describe() payload",
        operation_id
    ))
}

pub fn recompute_schema_hash(
    op: &ComponentOperation,
    config_schema: &greentic_types::schemas::common::schema_ir::SchemaIr,
) -> Result<String> {
    schema_hash(&op.input.schema, &op.output.schema, config_schema)
        .map_err(|err| anyhow!("compute schema hash: {err}"))
}