From 00d5d465602f8ea5b4862412670c56e812362e59 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 16 Oct 2016 05:22:37 +0100 Subject: [PATCH] feat: create a resolver in memory when no block-service is passed --- package.json | 1 + src/index.js | 50 +++--- src/old-resolve.js | 81 ---------- test/node.js | 5 +- test/old-ipld-tests.js | 334 --------------------------------------- test/test-ipld-dag-pb.js | 11 +- 6 files changed, 28 insertions(+), 454 deletions(-) delete mode 100644 src/old-resolve.js delete mode 100644 test/old-ipld-tests.js diff --git a/package.json b/package.json index 61a5f7b..f81f1c7 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ }, "dependencies": { "babel-runtime": "^6.11.6", + "interface-pull-blob-store": "^0.5.0", "ipfs-block": "^0.3.0", "ipld": "^0.6.0", "is-ipfs": "^0.2.0", diff --git a/src/index.js b/src/index.js index 0dbbd00..f5ce8f2 100644 --- a/src/index.js +++ b/src/index.js @@ -1,26 +1,32 @@ 'use strict' -// const isIPFS = require('is-ipfs') const Block = require('ipfs-block') -// const ipld = require('ipld-dag-cbor') const pull = require('pull-stream') const traverse = require('pull-traverse') -// const mh = require('multihashes') -const dagPB = require('ipld-dag-pb') - const utils = require('./utils') +const IPFSRepo = require('ipfs-repo') +const MemoryStore = require('../node_modules/interface-pull-blob-store/lib/reference.js') +const BlockService = require('ipfs-block-service') -module.exports = class IPLDResolver { +const dagPB = require('ipld-dag-pb') +// const dagCBOR = require('ipld-dag-cbor') +// const isIPFS = require('is-ipfs') +// const mh = require('multihashes') + +class IPLDResolver { constructor (blockService) { - // TODO instead of throwing, just create an in-memory - // block-service, so it is nice for demos + // nicola will love this! if (!blockService) { - throw new Error('IPLDService requires a BlockService instance') + const repo = new IPFSRepo('in-memory', { stores: MemoryStore }) + blockService = new BlockService(repo) } this.bs = blockService this.resolvers = {} + + // Support by default dag-pb and dag-cbor this.support(dagPB.resolver.multicodec, dagPB.DAGNode, dagPB.resolver) + // this.support(dagCBOR.resolver.multicodec, dagCBOR.DAGNode, dagCBOR.resolver) } // Adds support for an IPLD format @@ -36,6 +42,8 @@ module.exports = class IPLDResolver { // TODO } + // Node operations (get and retrieve nodes, not values) + put (node, callback) { callback = callback || noop pull( @@ -118,26 +126,4 @@ module.exports = class IPLDResolver { function noop () {} -/* -function normalizeKey (key) { - let res - const isMhash = isIPFS.multihash(key) - const isPath = isIPFS.path(key) - - if (!isMhash && !isPath) { - return null - } - - if (isMhash) { - res = key - } else if (isPath) { - res = key.replace('/ipfs/', '') - } - - if (typeof res === 'string') { - return mh.fromB58String(res) - } - - return res -} -*/ +module.exports = IPLDResolver diff --git a/src/old-resolve.js b/src/old-resolve.js deleted file mode 100644 index 581c6dc..0000000 --- a/src/old-resolve.js +++ /dev/null @@ -1,81 +0,0 @@ -'use strict' - -const isIPFS = require('is-ipfs') -const includes = require('lodash.includes') -const ipld = require('ipld') - -const IPLDService = require('./ipld-service') - -const LINK_SYMBOL = ipld.LINK_SYMBOL - -module.exports = function resolve (service, path, cb) { - if (!(service instanceof IPLDService)) { - return cb(new Error('Missing IPLDService')) - } - - function access (parts, obj, cb) { - const isRoot = obj === null && (isIPFS.multihash(parts[0]) || isIPFS.ipfsPath('/' + parts.join('/'))) - const next = parts.shift() - const isLink = obj && Object.keys(obj).length === 1 && obj[LINK_SYMBOL] - const fetchLink = obj && (next ? !includes(Object.keys(obj), next) : true) - - if (!obj && !isRoot) { - cb(new Error('No root object provided')) - } else if (isLink && fetchLink) { - // resolve links in objects with an / property - const link = obj[LINK_SYMBOL] - const linkParts = splitLink(link) - let blockLink = '' - - if (linkParts[0] === 'ipfs') { - // /ipfs/ - blockLink = linkParts[1] - parts = linkParts.slice(2).concat(parts) - } else if (isIPFS.multihash(linkParts[0])) { - // / - blockLink = linkParts[0] - - parts = linkParts.slice(1).concat(parts) - } else { - return cb(new Error(`Invalid link: "${link}"`)) - } - - service.get(blockLink, (err, block) => { - if (err) { - return cb(err) - } - if (next) { - // Put back so it's resolved in the next node - parts.unshift(next) - } - access(parts, block, cb) - }) - } else if (isRoot) { - let blockLink = next - if (next === 'ipfs') { - blockLink = parts.shift() - } - service.get(blockLink, (err, block) => { - if (err) { - return cb(err) - } - - access(parts, block, cb) - }) - } else if (next) { - access(parts, obj[next], cb) - } else { - cb(null, obj) - } - } - - access(splitLink(path), null, cb) -} - -function splitLink (link) { - return link - // Remove prefix / - .replace(/^\//, '') - // Hack to ignore escaped slashes - .replace(/([^\\])\//g, '$1\u000B').split('\u000B') -} diff --git a/test/node.js b/test/node.js index 081b5df..b8c0523 100644 --- a/test/node.js +++ b/test/node.js @@ -20,10 +20,7 @@ describe('Node.js', () => { }) after((done) => { - rimraf(repoTests, (err) => { - expect(err).to.equal(null) - done() - }) + rimraf(repoTests, done) }) const repo = new IPFSRepo(repoTests, {stores: Store}) diff --git a/test/old-ipld-tests.js b/test/old-ipld-tests.js deleted file mode 100644 index f616901..0000000 --- a/test/old-ipld-tests.js +++ /dev/null @@ -1,334 +0,0 @@ -/* eslint-env mocha */ -'use strict' - -const expect = require('chai').expect -const BlockService = require('ipfs-block-service') -const ipld = require('ipld') -const multihash = require('multihashing') -const series = require('async/series') -const pull = require('pull-stream') - -const IPLDService = require('../src').IPLDService -const resolve = require('../src').resolve - -module.exports = (repo) => { - const bs = new BlockService(repo) - const ipldService = new IPLDService(bs) - - describe('IPLD Resolver (old tests)', () => { - it('throws when not passed a repo', () => { - expect(() => new IPLDService()).to.throw(/requires a BlockService/) - }) - - it('adds an ipld node', (done) => { - const node = { - name: 'hello.txt', - size: 11 - } - - ipldService.put(node, done) - }) - - it('putStream', (done) => { - pull( - pull.values([ - {name: 'pull.txt', size: 12} - ]), - ipldService.putStream(done) - ) - }) - - it('gets an ipld node', (done) => { - const node = { - name: 'world.txt', - size: 11 - } - - ipldService.put(node, (err) => { - expect(err).to.not.exist - - const mh = multihash(ipld.marshal(node), 'sha2-256') - - ipldService.get(mh, (err, fetchedNode) => { - expect(err).to.not.exist - expect(node).to.deep.equal(fetchedNode) - done() - }) - }) - }) - - it('getStream', (done) => { - const node = { - name: 'put.txt', - size: 15 - } - const mh = multihash(ipld.marshal(node), 'sha2-256') - pull( - pull.values([node]), - ipldService.putStream(read) - ) - - function read (err) { - expect(err).to.not.exist - pull( - ipldService.getStream(mh), - pull.collect((err, res) => { - expect(err).to.not.exist - expect(res[0]).to.be.eql(node) - done() - }) - ) - } - }) - - it('get ipld nodes recursively', (done) => { - // 1 -> 2 -> 3 - const node1 = {data: '1'} - const node2 = {data: '2'} - const node3 = {data: '3'} - - node2.ref = { - '/': ipld.multihash(ipld.marshal(node3)) - } - - node1.ref = { - '/': ipld.multihash(ipld.marshal(node2)) - } - - series([ - (cb) => ipldService.put(node1, cb), - (cb) => ipldService.put(node2, cb), - (cb) => ipldService.put(node3, cb), - (cb) => { - const mh = multihash(ipld.marshal(node1), 'sha2-256') - ipldService.getRecursive(mh, (err, nodes) => { - expect(err).to.not.exist - expect(nodes).to.have.length(3) - cb() - }) - } - ], (err) => { - expect(err).to.not.exist - done() - }) - }) - - it('removes and ipld node', (done) => { - const node = {data: 'short lived node'} - const mh = multihash(ipld.marshal(node), 'sha2-256') - - series([ - (cb) => ipldService.put(node, cb), - (cb) => ipldService.get(mh, cb), - (cb) => ipldService.remove(mh, cb), - (cb) => ipldService.get(mh, (err) => { - expect(err).to.exist - cb() - }) - ], done) - }) - }) - - describe('resolve', () => { - describe('inside a single object', (done) => { - const node = { - string: 'hello', - number: 42, - object: { - title: 'world' - }, - numbers: [0, 1, 2], - objects: [{ - title: 'test' - }], - multiple: { - levels: { - down: 'all good!' - } - } - } - const mh = ipld.multihash(ipld.marshal(node)) - - before((done) => { - ipldService.put(node, done) - }) - - it('resolves direct leaves of type string', (done) => { - resolve(ipldService, `${mh}/string`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql('hello') - done() - }) - }) - - it('resolves direct leaves of type number', (done) => { - resolve(ipldService, `${mh}/number`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(42) - done() - }) - }) - - it('resolves direct leaves of type object', (done) => { - resolve(ipldService, `${mh}/object`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql({ - title: 'world' - }) - done() - }) - }) - - it('resolves subpaths', (done) => { - resolve(ipldService, `${mh}/multiple/levels/down`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql('all good!') - done() - }) - }) - - it('resolves arrays of primitives', (done) => { - resolve(ipldService, `${mh}/numbers/1`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(1) - done() - }) - }) - - it('resolves arrays of objects', (done) => { - resolve(ipldService, `${mh}/objects/0/title`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql('test') - done() - }) - }) - }) - - describe('links are hashes', () => { - const aliceAbout = { - age: 22 - } - const bob = { - name: 'Bob' - } - const alice = { - name: 'Alice', - about: { - '/': ipld.multihash(ipld.marshal(aliceAbout)) - }, - friends: [{ - '/': ipld.multihash(ipld.marshal(bob)) - }] - } - const mh = ipld.multihash(ipld.marshal(alice)) - - before((done) => { - series([ - (cb) => ipldService.put(aliceAbout, cb), - (cb) => ipldService.put(alice, cb), - (cb) => ipldService.put(bob, cb) - ], done) - }) - - it('link to object', (done) => { - resolve(ipldService, `${mh}/about`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(aliceAbout) - done() - }) - }) - - it('link to property in a different object', (done) => { - resolve(ipldService, `${mh}/about/age`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(aliceAbout.age) - done() - }) - }) - - it('link to an element in array', (done) => { - resolve(ipldService, `${mh}/friends/0`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(bob) - done() - }) - }) - - it('link to property in an element in array', (done) => { - resolve(ipldService, `${mh}/friends/0/name`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(bob.name) - done() - }) - }) - }) - - describe('links are merkle paths', () => { - const draft = { - title: 'Title of the blogpost' - } - - const alice = { - name: 'Alice' - } - - const author = { - name: { - '/': `/${ipld.multihash(ipld.marshal(alice))}/name` - } - } - - const blogpost = { - title: { - '/': `/${ipld.multihash(ipld.marshal(draft))}/title` - }, - author: { - '/': `/ipfs/${ipld.multihash(ipld.marshal(author))}` - } - } - - const mh = ipld.multihash(ipld.marshal(blogpost)) - - before((done) => { - series([ - (cb) => ipldService.put(draft, cb), - (cb) => ipldService.put(alice, cb), - (cb) => ipldService.put(author, cb), - (cb) => ipldService.put(blogpost, cb) - ], done) - }) - - it('merkle-link pointing to a string', (done) => { - resolve(ipldService, `${mh}/title`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(draft.title) - done() - }) - }) - - it('merkle-link pointing to an object', (done) => { - resolve(ipldService, `${mh}/author`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(author) - done() - }) - }) - - it('merkle-link pointing to link to an object', (done) => { - resolve(ipldService, `${mh}/author/name`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(alice.name) - done() - }) - }) - - it('ipfs merkle-link to an object', (done) => { - resolve(ipldService, `/ipfs/${mh}/author`, (err, res) => { - expect(err).to.not.exist - expect(res).to.be.eql(author) - done() - }) - }) - }) - }) -} diff --git a/test/test-ipld-dag-pb.js b/test/test-ipld-dag-pb.js index a560e3d..9f267ec 100644 --- a/test/test-ipld-dag-pb.js +++ b/test/test-ipld-dag-pb.js @@ -24,8 +24,9 @@ module.exports = (repo) => { node3 = new dagPB.DAGNode(new Buffer('I am 3')) }) - it('throws when not passed a repo', () => { - expect(() => new IPLDResolver()).to.throw(/requires a BlockService/) + it('creates an in memory repo if no blockService is passed', () => { + const r = new IPLDResolver() + expect(r.bs).to.exist }) it('resolver.put', (done) => { @@ -124,5 +125,9 @@ module.exports = (repo) => { }) }) - describe('IPLD Path Resolver', () => {}) + describe('IPLD Path Resolver', () => { + it.skip('resolves path of a non nested value', () => {}) + it.skip('resolves path of a level 1 nested value', () => {}) + it.skip('resolves path of a level 2 nested value', () => {}) + }) }