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. # SUCH DAMAGE.


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


from importlib.abc import MetaPathFinder, Loader from importlib.abc import MetaPathFinder, Loader
from importlib.machinery import ModuleSpec 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 @contextlib.contextmanager
def tempset(obj, key, value): def tempset(obj, key, value):
'''A context (with) manager for changing the value of an item in a '''A context (with) manager for changing the value of an item in a
@@ -88,6 +105,26 @@ def tempattrset(obj, key, value):
else: else:
delattr(obj, key) 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): class FileDirCAS(object):
'''A file loader for CAS that operates on a directory. It looks '''A file loader for CAS that operates on a directory. It looks
at files, caches their hash, and loads them upon request.''' at files, caches their hash, and loads them upon request.'''
@@ -296,6 +333,7 @@ def defaultinit(casf):
cachedir.mkdir(exist_ok=True) cachedir.mkdir(exist_ok=True)


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


# The global version # The global version
_casfinder = CASFinder() _casfinder = CASFinder()
@@ -423,6 +461,9 @@ class Test(unittest.TestCase):
# it can be imported # it can be imported
from cas.v1_f_330884aa2febb5e19fb7194ec6a69ed11dd3d77122f1a5175ee93e73cf0161c3 import hello 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: with CASFinder() as f:
defaultinit(f) defaultinit(f)


@@ -514,6 +555,35 @@ class Test(unittest.TestCase):
finally: finally:
sys.path.remove(fixdir) 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): def test_overlappingaliases(self):
# make sure that an aliases file is consistent and does not # make sure that an aliases file is consistent and does not
# override other urls. That is that any hashes are # override other urls. That is that any hashes are


Loading…
Cancel
Save