Add IPFS node to L2 for federated content storage
- Add IPFS container to docker-compose - Add ipfshttpclient dependency - Add ipfs_client.py module for IPFS operations - Add ipfs_cid field to Asset model and database schema - Pin content on L2 IPFS when assets are published/registered L2 now stores content on its own IPFS node, enabling federation - content remains available even if L1 goes down. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
23
server.py
23
server.py
@@ -86,6 +86,7 @@ class Asset(BaseModel):
|
||||
"""An owned asset."""
|
||||
name: str
|
||||
content_hash: str
|
||||
ipfs_cid: Optional[str] = None # IPFS content identifier
|
||||
asset_type: str # image, video, effect, recipe, infrastructure
|
||||
tags: list[str] = []
|
||||
metadata: dict = {}
|
||||
@@ -108,6 +109,7 @@ class RegisterRequest(BaseModel):
|
||||
"""Request to register an asset."""
|
||||
name: str
|
||||
content_hash: str
|
||||
ipfs_cid: Optional[str] = None # IPFS content identifier
|
||||
asset_type: str
|
||||
tags: list[str] = []
|
||||
metadata: dict = {}
|
||||
@@ -125,6 +127,7 @@ class RecordRunRequest(BaseModel):
|
||||
class PublishCacheRequest(BaseModel):
|
||||
"""Request to publish a cache item from L1."""
|
||||
content_hash: str
|
||||
ipfs_cid: Optional[str] = None # IPFS content identifier
|
||||
asset_name: str
|
||||
asset_type: str = "image"
|
||||
origin: dict # {type: "self"|"external", url?: str, note?: str}
|
||||
@@ -1613,11 +1616,21 @@ async def _register_asset_impl(req: RegisterRequest, owner: str):
|
||||
if await db.asset_exists(req.name):
|
||||
raise HTTPException(400, f"Asset already exists: {req.name}")
|
||||
|
||||
# Pin content on IPFS if CID provided
|
||||
if req.ipfs_cid:
|
||||
try:
|
||||
import ipfs_client
|
||||
if ipfs_client.is_available():
|
||||
ipfs_client.pin(req.ipfs_cid)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to pin IPFS content {req.ipfs_cid}: {e}")
|
||||
|
||||
# Create asset
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
asset = {
|
||||
"name": req.name,
|
||||
"content_hash": req.content_hash,
|
||||
"ipfs_cid": req.ipfs_cid,
|
||||
"asset_type": req.asset_type,
|
||||
"tags": req.tags,
|
||||
"metadata": req.metadata,
|
||||
@@ -1735,11 +1748,21 @@ async def publish_cache(req: PublishCacheRequest, user: User = Depends(get_requi
|
||||
if await db.asset_exists(req.asset_name):
|
||||
raise HTTPException(400, f"Asset name already exists: {req.asset_name}")
|
||||
|
||||
# Pin content on IPFS if CID provided
|
||||
if req.ipfs_cid:
|
||||
try:
|
||||
import ipfs_client
|
||||
if ipfs_client.is_available():
|
||||
ipfs_client.pin(req.ipfs_cid)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to pin IPFS content {req.ipfs_cid}: {e}")
|
||||
|
||||
# Create asset
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
asset = {
|
||||
"name": req.asset_name,
|
||||
"content_hash": req.content_hash,
|
||||
"ipfs_cid": req.ipfs_cid,
|
||||
"asset_type": req.asset_type,
|
||||
"tags": req.tags,
|
||||
"description": req.description,
|
||||
|
||||
Reference in New Issue
Block a user