parent_ai_json_engine 0.0.2

Crate provides a JSON engine for collecting, aggregating, and managing models.
Documentation
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;

pub const MAX_MODEL_BYTES: usize = 200_000_000;

fn current_max_model_bytes() -> usize {
    if let Ok(s) = std::env::var("JSON_ENGINE_MAX_MODEL_BYTES") {
        if let Ok(n) = s.parse::<usize>() {
            return n;
        }
    }
    MAX_MODEL_BYTES
}

pub fn save_model(
    path: &Path,
    data: &[u8],
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let limit = current_max_model_bytes();
    if data.len() > limit {
        return Err(format!("model size {} exceeds limit {}", data.len(), limit).into());
    }

    if let Some(parent) = path.parent() {
        std::fs::create_dir_all(parent)?;
    }

    let ts = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)?
        .as_nanos();
    let tmp = path.with_extension(format!("tmp.{}", ts));

    {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(&tmp)?;
        f.write_all(data)?;
        f.sync_all()?;
    }

    std::fs::rename(&tmp, path)?;

    if let Some(dir) = path.parent() {
        if let Ok(dir_file) = OpenOptions::new().read(true).open(dir) {
            if let Err(e) = dir_file.sync_all() {
                eprintln!(
                    "{{\"msg\":\"model_store: dir sync failed\",\"path\":\"{}\",\"error\":\"{}\"}}",
                    dir.display(),
                    e
                );
            }
        }
    }

    Ok(())
}