Skip to content

Commit eb2bf8e

Browse files
committed
implement IPIP-280 Gateway auto-discovery
fixes #29
1 parent 5cad637 commit eb2bf8e

File tree

2 files changed

+88
-28
lines changed

2 files changed

+88
-28
lines changed

ipfsspec/async_ipfs.py

+88-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import io
2+
import os
3+
import platform
24
import time
35
import weakref
6+
from functools import lru_cache
7+
from pathlib import Path
8+
import warnings
49

510
import asyncio
611
import aiohttp
712

813
from fsspec.asyn import AsyncFileSystem, sync, sync_wrapper
914
from fsspec.exceptions import FSTimeoutError
1015

11-
from .utils import get_default_gateways
12-
1316
import logging
1417

1518
logger = logging.getLogger("ipfsspec")
@@ -248,19 +251,92 @@ async def get_client(**kwargs):
248251
return aiohttp.ClientSession(**kwargs)
249252

250253

251-
DEFAULT_GATEWAY = None
254+
def gateway_from_file(gateway_path):
255+
if gateway_path.exists():
256+
with open(gateway_path) as gw_file:
257+
ipfs_gateway = gw_file.readline().strip()
258+
logger.debug("using IPFS gateway from %s: %s", gateway_path, ipfs_gateway)
259+
return AsyncIPFSGateway(ipfs_gateway)
260+
return None
252261

253262

263+
@lru_cache
254264
def get_gateway():
255-
global DEFAULT_GATEWAY
256-
if DEFAULT_GATEWAY is None:
257-
use_gateway(*get_default_gateways())
258-
return DEFAULT_GATEWAY
259-
260-
261-
def use_gateway(*urls):
262-
global DEFAULT_GATEWAY
263-
DEFAULT_GATEWAY = MultiGateway([AsyncIPFSGateway(url) for url in urls])
265+
"""
266+
Get IPFS gateway according to IPIP-280
267+
268+
see: https://github.com/ipfs/specs/pull/280
269+
"""
270+
271+
# IPFS_GATEWAY environment variable should override everything
272+
ipfs_gateway = os.environ.get("IPFS_GATEWAY", "")
273+
if ipfs_gateway:
274+
logger.debug("using IPFS gateway from IPFS_GATEWAY environment variable: %s", ipfs_gateway)
275+
return AsyncIPFSGateway(ipfs_gateway)
276+
277+
# internal configuration: accept IPFSSPEC_GATEWAYS for backwards compatibility
278+
if ipfsspec_gateways := os.environ.get("IPFSSPEC_GATEWAYS", ""):
279+
ipfs_gateway = ipfsspec_gateways.split()[0]
280+
logger.debug("using IPFS gateway from IPFSSPEC_GATEWAYS environment variable: %s", ipfs_gateway)
281+
warnings.warn("The IPFSSPEC_GATEWAYS environment variable is deprecated, please configure your IPFS Gateway according to IPIP-280, e.g. by using the IPFS_GATEWAY environment variable or using the ~/.ipfs/gateway file.", DeprecationWarning)
282+
return AsyncIPFSGateway(ipfs_gateway)
283+
284+
# check various well-known files for possible gateway configurations
285+
if ipfs_path := os.environ.get("IPFS_PATH", ""):
286+
if ipfs_gateway := gateway_from_file(Path(ipfs_path) / "gateway"):
287+
return ipfs_gateway
288+
289+
if home := os.environ.get("HOME", ""):
290+
if ipfs_gateway := gateway_from_file(Path(home) / ".ipfs" / "gateway"):
291+
return ipfs_gateway
292+
293+
if config_home := os.environ.get("XDG_CONFIG_HOME", ""):
294+
if ipfs_gateway := gateway_from_file(Path(config_home) / "ipfs" / "gateway"):
295+
return ipfs_gateway
296+
297+
if ipfs_gateway := gateway_from_file(Path("/etc") / "ipfs" / "gateway"):
298+
return ipfs_gateway
299+
300+
system = platform.system()
301+
302+
if system == "Windows":
303+
candidates = [
304+
Path(os.environ.get("LOCALAPPDATA")) / "ipfs" / "gateway",
305+
Path(os.environ.get("APPDATA")) / "ipfs" / "gateway",
306+
Path(os.environ.get("PROGRAMDATA")) / "ipfs" / "gateway",
307+
]
308+
elif system == "Darwin":
309+
candidates = [
310+
Path(os.environ.get("HOME")) / "Library" / "Application Support" / "ipfs" / "gateway",
311+
Path("/Library") / "Application Support" / "ipfs" / "gateway",
312+
]
313+
elif system == "Linux":
314+
candidates = [
315+
Path(os.environ.get("HOME")) / ".config" / "ipfs" / "gateway",
316+
Path("/etc") / "ipfs" / "gateway",
317+
]
318+
else:
319+
candidates = []
320+
321+
for candidate in candidates:
322+
if ipfs_gateway := gateway_from_file(candidate):
323+
return ipfs_gateway
324+
325+
# if we reach this point, no gateway is configured
326+
raise RuntimeError("IPFS Gateway could not be found!\n"
327+
"In order to access IPFS, you must configure an "
328+
"IPFS Gateway using a IPIP-280 configuration method. "
329+
"Possible options are: \n"
330+
" * set the environment variable IPFS_GATEWAY\n"
331+
" * write a gateway in the first line of the file ~/.ipfs/gateway\n"
332+
"\n"
333+
"It's always best to run your own IPFS gateway, e.g. by using "
334+
"IPFS Desktop (https://docs.ipfs.tech/install/ipfs-desktop/) or "
335+
"the command line version Kubo (https://docs.ipfs.tech/install/command-line/). "
336+
"If you can't run your own gateway, you may also try using the "
337+
"public IPFS gateway at https://ipfs.io or https://dweb.link . "
338+
"However, this is not recommended for productive use and you may experience "
339+
"severe performance issues.")
264340

265341

266342
class AsyncIPFSFileSystem(AsyncFileSystem):

ipfsspec/utils.py

-16
This file was deleted.

0 commit comments

Comments
 (0)