--- name: job_cache_sha256 kind: function lang: cpp domain: infra version: "1.0.0" purity: impure signature: "std::string fn::cache_sha256::path_for(const std::string& root, const std::string& key, const std::string& suffix = \"\"); bool fn::cache_sha256::ensure_dir(const std::string& root, const std::string& key); bool fn::cache_sha256::read(const std::string& root, const std::string& key, const std::string& suffix, std::string* out); bool fn::cache_sha256::write(const std::string& root, const std::string& key, const std::string& suffix, const std::string& bytes); bool fn::cache_sha256::exists(const std::string& root, const std::string& key, const std::string& suffix)" description: "Cache addressable con layout '//'. El caller hashea (tipicamente SHA-256 hex), esta funcion gestiona path + I/O. Suffix opcional permite multiples blobs por key (.html, .md, .json). Pieza extraida del jobs system de graph_explorer (issue 0026/0027) para reuso entre apps C++ que recolectan datos online." tags: [cache, sha256, addressable, jobs, fs, scraping, pendiente-usar] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [string, cstdio, filesystem, fstream, sstream] tested: false tests: [] test_file_path: "" file_path: "cpp/functions/infra/job_cache_sha256.cpp" framework: "" params: - name: root desc: "Directorio raiz del cache. Tipicamente /local_files/cache/. La funcion crea subdirectorios on-demand." - name: key desc: "Clave de cache. Tipicamente SHA-256 hex (64 chars) de un valor canonico (URL, hash de params). El caller calcula el hash." - name: suffix desc: "Sufijo del archivo. Permite multiples blobs por la misma key. Ejemplos: '.html', '.md', '.json'. Pasa '' si solo hay un blob por key." - name: out desc: "Buffer de salida para read(). Recibe los bytes del archivo. Devuelve false si no existia." - name: bytes desc: "Contenido a escribir en write(). Se trata como binario (no se anade newline ni se interpreta)." output: "path_for: string con el path absoluto. ensure_dir/read/write/exists: bool true en exito; read tambien rellena out. Ningun error_type custom — fallo de fs se traduce a false (ver fstream/filesystem para detalles)." notes: "1) Pure: solo path_for. Resto impuro (toca filesystem). 2) Layout compatible con el cache que ya usan los enrichers Python de graph_explorer (`//.{html,md}`), por lo que apps C++ pueden leer blobs escritos por subprocess Python sin migrar formato. 3) Si el caller necesita SHA-256 propio, anadir funcion separada `sha256_hex_cpp_core` (no implementada aun)." documentation: "Pieza minima del refactor de issue 0065. El cache es un helper standalone que cualquier app C++ que recolecte datos online puede usar para evitar refetchear. odr_console (issue 0066) lo usa via la cache_dir que pasa al subprocess Python en stdin JSON, manteniendo compatibilidad con enrichers existentes." example: | #include "cpp/functions/infra/job_cache_sha256.h" #include // o cualquier impl SHA-256 std::string url = "https://example.com/data.json"; // Hash de la URL como key (usuario provee la impl). std::string key = sha256_hex(url); std::string root = "/path/to/app/local_files/cache"; if (!fn::cache_sha256::exists(root, key, ".json")) { std::string body = fetch_http(url); fn::cache_sha256::write(root, key, ".json", body); } std::string cached; if (fn::cache_sha256::read(root, key, ".json", &cached)) { // ... usar cached ... } --- ## Notas Helper de I/O addressable. No hace SHA-256 — el caller provee la key (normalmente hex). Layout `//` es identico al que usan los enrichers de graph_explorer en sus `run.py`, por lo que C++ y Python pueden leer/escribir el mismo cache. ### Decisiones de diseño - **Hash fuera de la funcion**: separar el hashing del path-handling deja el modulo libre de dependencias criptograficas. Si una app prefiere blake3, xxhash o md5 para keys mas cortas, esta funcion sigue valiendo. - **Suffix opcional**: enrichers de graph_explorer guardan dos blobs por URL (`.html` y `.md`); odr_console probablemente guarde `.json`/`.parquet`. Suffix unifica casos. - **Sin SQLite**: cache es solo files. Si una app necesita metadata por entry (TTL, last-access, content-type), eso vive en operations.db o en una tabla aparte. - **Layout compatible**: identico al Python `cache_paths()` en `enrichers/fetch_webpage/run.py`. C++ puede leer blobs escritos por enrichers Python y viceversa. ### Que NO incluye - No incluye SHA-256 ni ningun hash. Caller responsable. - No incluye TTL ni eviction. Implementar fuera si se necesita. - No incluye locking entre procesos. Si dos workers escriben la misma key concurrente, ultimo gana — para invalidacion atomica usar nombre temporal + rename.