Use direct HTTP API for IPFS instead of ipfshttpclient
Replace ipfshttpclient library with direct HTTP requests to IPFS API. This fixes compatibility with newer Kubo versions (0.39.0+) which are not supported by the outdated ipfshttpclient library. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,14 +3,15 @@
|
||||
IPFS client for Art DAG L2 server.
|
||||
|
||||
Provides functions to fetch and pin content from IPFS.
|
||||
L2 uses IPFS to retrieve content from the federated network.
|
||||
Uses direct HTTP API calls for compatibility with all Kubo versions.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
import ipfshttpclient
|
||||
import requests
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,9 +22,26 @@ IPFS_API = os.getenv("IPFS_API", "/ip4/127.0.0.1/tcp/5001")
|
||||
IPFS_TIMEOUT = int(os.getenv("IPFS_TIMEOUT", "60"))
|
||||
|
||||
|
||||
def get_client():
|
||||
"""Get an IPFS client connection."""
|
||||
return ipfshttpclient.connect(IPFS_API, timeout=IPFS_TIMEOUT)
|
||||
def _multiaddr_to_url(multiaddr: str) -> str:
|
||||
"""Convert IPFS multiaddr to HTTP URL."""
|
||||
# Handle /dns/hostname/tcp/port format
|
||||
dns_match = re.match(r"/dns[46]?/([^/]+)/tcp/(\d+)", multiaddr)
|
||||
if dns_match:
|
||||
return f"http://{dns_match.group(1)}:{dns_match.group(2)}"
|
||||
|
||||
# Handle /ip4/address/tcp/port format
|
||||
ip4_match = re.match(r"/ip4/([^/]+)/tcp/(\d+)", multiaddr)
|
||||
if ip4_match:
|
||||
return f"http://{ip4_match.group(1)}:{ip4_match.group(2)}"
|
||||
|
||||
# Fallback: assume it's already a URL or use default
|
||||
if multiaddr.startswith("http"):
|
||||
return multiaddr
|
||||
return "http://127.0.0.1:5001"
|
||||
|
||||
|
||||
# Base URL for IPFS API
|
||||
IPFS_BASE_URL = _multiaddr_to_url(IPFS_API)
|
||||
|
||||
|
||||
def get_bytes(cid: str) -> Optional[bytes]:
|
||||
@@ -37,10 +55,15 @@ def get_bytes(cid: str) -> Optional[bytes]:
|
||||
Content as bytes or None on failure
|
||||
"""
|
||||
try:
|
||||
with get_client() as client:
|
||||
data = client.cat(cid)
|
||||
logger.info(f"Retrieved from IPFS: {cid} ({len(data)} bytes)")
|
||||
return data
|
||||
url = f"{IPFS_BASE_URL}/api/v0/cat"
|
||||
params = {"arg": cid}
|
||||
|
||||
response = requests.post(url, params=params, timeout=IPFS_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
data = response.content
|
||||
|
||||
logger.info(f"Retrieved from IPFS: {cid} ({len(data)} bytes)")
|
||||
return data
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get from IPFS: {e}")
|
||||
return None
|
||||
@@ -57,10 +80,14 @@ def pin(cid: str) -> bool:
|
||||
True on success, False on failure
|
||||
"""
|
||||
try:
|
||||
with get_client() as client:
|
||||
client.pin.add(cid)
|
||||
logger.info(f"Pinned on IPFS: {cid}")
|
||||
return True
|
||||
url = f"{IPFS_BASE_URL}/api/v0/pin/add"
|
||||
params = {"arg": cid}
|
||||
|
||||
response = requests.post(url, params=params, timeout=IPFS_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
|
||||
logger.info(f"Pinned on IPFS: {cid}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to pin on IPFS: {e}")
|
||||
return False
|
||||
@@ -77,10 +104,14 @@ def unpin(cid: str) -> bool:
|
||||
True on success, False on failure
|
||||
"""
|
||||
try:
|
||||
with get_client() as client:
|
||||
client.pin.rm(cid)
|
||||
logger.info(f"Unpinned from IPFS: {cid}")
|
||||
return True
|
||||
url = f"{IPFS_BASE_URL}/api/v0/pin/rm"
|
||||
params = {"arg": cid}
|
||||
|
||||
response = requests.post(url, params=params, timeout=IPFS_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
|
||||
logger.info(f"Unpinned from IPFS: {cid}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to unpin from IPFS: {e}")
|
||||
return False
|
||||
@@ -94,9 +125,9 @@ def is_available() -> bool:
|
||||
True if IPFS is available, False otherwise
|
||||
"""
|
||||
try:
|
||||
with get_client() as client:
|
||||
client.id()
|
||||
return True
|
||||
url = f"{IPFS_BASE_URL}/api/v0/id"
|
||||
response = requests.post(url, timeout=5)
|
||||
return response.status_code == 200
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@@ -109,9 +140,10 @@ def get_node_id() -> Optional[str]:
|
||||
Peer ID string or None on failure
|
||||
"""
|
||||
try:
|
||||
with get_client() as client:
|
||||
info = client.id()
|
||||
return info.get("ID")
|
||||
url = f"{IPFS_BASE_URL}/api/v0/id"
|
||||
response = requests.post(url, timeout=IPFS_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
return response.json().get("ID")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get node ID: {e}")
|
||||
return None
|
||||
|
||||
@@ -7,4 +7,3 @@ python-jose[cryptography]>=3.3.0
|
||||
markdown>=3.5.0
|
||||
python-multipart>=0.0.6
|
||||
asyncpg>=0.29.0
|
||||
ipfshttpclient>=0.7.0
|
||||
|
||||
Reference in New Issue
Block a user