Add IPFS CID support for asset lookup

- Upload endpoint returns both CID and content_hash
- Cache manager handles both SHA3-256 hashes and IPFS CIDs
- get_by_cid() fetches from IPFS if not cached locally
- Execute tasks support :cid in addition to :hash

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-12 07:36:18 +00:00
parent c7c7c90909
commit 494a2a8650
4 changed files with 51 additions and 14 deletions

View File

@@ -427,8 +427,17 @@ class L1CacheManager:
"""Get cached file path by node_id."""
return self.cache.get(node_id)
def _is_ipfs_cid(self, identifier: str) -> bool:
"""Check if identifier looks like an IPFS CID."""
# CIDv0 starts with "Qm", CIDv1 starts with "bafy" or other multibase prefixes
return identifier.startswith("Qm") or identifier.startswith("bafy") or identifier.startswith("baf")
def get_by_content_hash(self, content_hash: str) -> Optional[Path]:
"""Get cached file path by content_hash. Falls back to IPFS if not in local cache."""
"""Get cached file path by content_hash or IPFS CID. Falls back to IPFS if not in local cache."""
# If it looks like an IPFS CID, use get_by_cid instead
if self._is_ipfs_cid(content_hash):
return self.get_by_cid(content_hash)
# Check index first (Redis then local)
node_id = self._get_content_index(content_hash)
@@ -469,6 +478,32 @@ class L1CacheManager:
return None
def get_by_cid(self, ipfs_cid: str) -> Optional[Path]:
"""Get cached file path by IPFS CID. Fetches from IPFS if not in local cache."""
# Check if we have this CID cached locally (indexed by CID)
cached_path = self.legacy_dir / ipfs_cid
if cached_path.exists() and cached_path.is_file():
return cached_path
# Check cache directory structure
cid_cache_dir = self.cache_dir / ipfs_cid
if cid_cache_dir.exists() and cid_cache_dir.is_dir():
# Look for output file
for f in cid_cache_dir.iterdir():
if f.is_file() and not f.name.endswith('.json'):
return f
# Fetch from IPFS
logger.info(f"Fetching from IPFS: {ipfs_cid[:16]}...")
recovery_path = self.legacy_dir / ipfs_cid
recovery_path.parent.mkdir(parents=True, exist_ok=True)
if ipfs_client.get_file(ipfs_cid, recovery_path):
logger.info(f"Fetched from IPFS: {recovery_path}")
return recovery_path
return None
def has_content(self, content_hash: str) -> bool:
"""Check if content exists in cache."""
return self.get_by_content_hash(content_hash) is not None