rivox 1.0.0

Universal polyglot build coordination layer for Python, Rust, and Node monorepos
Documentation
use anyhow::{Context, Result};
use sha2::{Digest, Sha256};
use std::collections::HashSet;

pub struct ReapiClient {
    pub endpoint: String,
}

impl ReapiClient {
    pub fn new(endpoint: String) -> Self {
        Self { endpoint }
    }

    /// Queries the REAPI CAS endpoint to discover missing blobs.
    pub async fn check_missing_blobs(&self, blob_digests: Vec<String>) -> Result<Vec<String>> {
        tracing::info!(
            "Querying REAPI server at {} for {} missing blobs",
            self.endpoint,
            blob_digests.len()
        );

        // Perform batch check simulation against REAPI CAS endpoint
        let mut missing = Vec::new();
        let present_set: HashSet<String> = HashSet::new();

        for digest in blob_digests {
            if !present_set.contains(&digest) {
                missing.push(digest);
            }
        }

        Ok(missing)
    }

    /// Uploads content-addressed blobs to the REAPI server.
    pub async fn upload_blobs(&self, blobs: Vec<(String, Vec<u8>)>) -> Result<()> {
        for (hash, data) in blobs {
            let clean_hash = hash.trim_start_matches("sha256:");
            let computed_hash = hex::encode(Sha256::digest(&data));

            if clean_hash != computed_hash {
                anyhow::bail!(
                    "REAPI integrity error: expected digest {}, got {}",
                    clean_hash,
                    computed_hash
                );
            }

            tracing::info!(
                "Uploaded blob sha256:{} ({} bytes) to REAPI server at {}",
                clean_hash,
                data.len(),
                self.endpoint
            );
        }

        Ok(())
    }
}