"""DSMS (Dezentrales Daten Speicher System) Client — archives compliance artifacts to IPFS via the dsms-gateway for tamper-proof versioning. Usage: from compliance.services.dsms_client import archive_to_dsms, verify_dsms result = await archive_to_dsms( content=pdf_bytes, filename="gap-report-2026-05-11.json", document_type="gap_report", document_id=str(report_id), version="1", ) cid = result["cid"] # IPFS Content Identifier """ import logging import os import httpx logger = logging.getLogger(__name__) DSMS_GATEWAY_URL = os.environ.get("DSMS_GATEWAY_URL", "http://dsms-gateway:8082") async def archive_to_dsms( content: bytes, filename: str, document_type: str, document_id: str, version: str = "1", parent_cid: str | None = None, language: str = "de", tenant_id: str | None = None, ) -> dict: """Archive binary content to DSMS (IPFS). Returns dict with keys: cid, size, gateway_url. Returns empty dict on failure (non-critical — logs warning). """ data = { "document_type": document_type, "document_id": document_id, "version": version, "language": language, } if parent_cid: data["parent_cid"] = parent_cid if tenant_id: data["tenant_id"] = tenant_id try: async with httpx.AsyncClient(timeout=60.0) as client: resp = await client.post( f"{DSMS_GATEWAY_URL}/api/v1/documents", files={"file": (filename, content)}, data=data, headers={"Authorization": "Bearer system-backend"}, ) if resp.status_code != 200: logger.warning("DSMS archive failed (%d): %s", resp.status_code, resp.text[:200]) return {} result = resp.json() logger.info("DSMS archived: %s → CID %s (%d bytes)", filename, result.get("cid", "?"), result.get("size", 0)) return result except Exception as e: logger.warning("DSMS archive unavailable: %s", e) return {} async def verify_dsms(cid: str) -> dict: """Verify a document's integrity by CID. Returns dict with verification result or empty dict on failure. """ try: async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.get(f"{DSMS_GATEWAY_URL}/api/v1/verify/{cid}") if resp.status_code != 200: return {"valid": False, "error": f"HTTP {resp.status_code}"} return resp.json() except Exception as e: logger.warning("DSMS verify unavailable: %s", e) return {"valid": False, "error": str(e)}