Browse Source

add IPFS loader support.. use cloudflare instead of the ipfs.io

one because the IPv6 address seems to hang often right now..
main
John-Mark Gurney 5 years ago
parent
commit
715e4bc4b3
1 changed files with 71 additions and 1 deletions
  1. +71
    -1
      casimport/__init__.py

+ 71
- 1
casimport/__init__.py View File

@@ -23,6 +23,7 @@
# SUCH DAMAGE.

import contextlib
import functools
import glob
import hashlib
import importlib.resources
@@ -32,11 +33,27 @@ import pathlib
import shutil
import sys
import tempfile
import urllib
import urllib.request

from importlib.abc import MetaPathFinder, Loader
from importlib.machinery import ModuleSpec

def _printanyexc(f):
'''Prints any exception that gets raised by the wrapped function.'''

@functools.wraps(f)
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception:
import traceback

traceback.print_exc()

raise

return wrapper

@contextlib.contextmanager
def tempset(obj, key, value):
'''A context (with) manager for changing the value of an item in a
@@ -88,6 +105,26 @@ def tempattrset(obj, key, value):
else:
delattr(obj, key)

class IPFSCAS(object):
gwhost = 'gateway.ipfs.io'
gwhost = 'cloudflare-ipfs.com'

def make_url(self, url):
return urllib.parse.urlunparse(('https', self.gwhost,
'/ipfs/' + url.netloc) + ('', ) * 3)

def fetch_data(self, url):
if url.scheme != 'ipfs':
raise ValueError('cannot handle scheme %s' %
repr(url.scheme))
gwurl = self.make_url(url)

with urllib.request.urlopen(gwurl) as req:
if req.status // 100 != 2:
raise RuntimeError('bad fetch')

return req.read()

class FileDirCAS(object):
'''A file loader for CAS that operates on a directory. It looks
at files, caches their hash, and loads them upon request.'''
@@ -296,6 +333,7 @@ def defaultinit(casf):
cachedir.mkdir(exist_ok=True)

casf.register(FileDirCAS(cachedir))
casf.register(IPFSCAS())

# The global version
_casfinder = CASFinder()
@@ -423,6 +461,9 @@ class Test(unittest.TestCase):
# it can be imported
from cas.v1_f_330884aa2febb5e19fb7194ec6a69ed11dd3d77122f1a5175ee93e73cf0161c3 import hello

# and that the last loader is the IPFSCAS
self.assertIsInstance(f._loaders[-1], IPFSCAS)

with CASFinder() as f:
defaultinit(f)

@@ -514,6 +555,35 @@ class Test(unittest.TestCase):
finally:
sys.path.remove(fixdir)

@mock.patch('urllib.request.urlopen')
def test_ipfscasloader(self, uomock):
# prep return test data
with open(self.fixtures / 'hello.py') as fp:
# that returns the correct data
ipfsdata = fp.read()

# that the ipfs CAS loader
ipfs = IPFSCAS()

# that the request is successfull
uomock.return_value.__enter__.return_value.status = 200

# and returns the correct data
uomock.return_value.__enter__.return_value.read.return_value = ipfsdata

# that when called
hashurl = urllib.parse.urlparse('ipfs://bafkreibtbcckul7lwxqz7nyzj3dknhwrdxj5o4jc6gsroxxjhzz46albym')
data = ipfs.fetch_data(hashurl)

# it opens the correct url
uomock.assert_called_with('https://cloudflare-ipfs.com/ipfs/bafkreibtbcckul7lwxqz7nyzj3dknhwrdxj5o4jc6gsroxxjhzz46albym')

# and returns the correct data
self.assertEqual(data, ipfsdata)

with self.assertRaises(ValueError):
ipfs.fetch_data(urllib.parse.urlparse('hash://sha256/asldfkj'))

def test_overlappingaliases(self):
# make sure that an aliases file is consistent and does not
# override other urls. That is that any hashes are


Loading…
Cancel
Save