From afa2f25f553ef77541c0920e73600fc5ef3db0d7 Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 9 Mar 2017 10:39:30 +0000 Subject: [PATCH 1/8] feat: dag.get now supports CID as string and CID+Path as String --- src/core/components/dag.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/core/components/dag.js b/src/core/components/dag.js index 511bf9959d..34f4ac3587 100644 --- a/src/core/components/dag.js +++ b/src/core/components/dag.js @@ -1,6 +1,7 @@ 'use strict' const promisify = require('promisify-es6') +const CID = require('cids') module.exports = function dag (self) { return { @@ -8,6 +9,30 @@ module.exports = function dag (self) { self._ipldResolver.put(dagNode, options, callback) }), get: promisify((cid, path, options, callback) => { + if (typeof path === 'function') { + callback = path + path = undefined + } + + if (typeof options === 'function') { + callback = options + options = {} + } + + options = options || {} + + if (typeof cid === 'string') { + const split = cid.split('/') + cid = new CID(split[0]) + split.shift() + + if (split.length > 0) { + path = split.join('/') + } else { + path = '/' + } + } + self._ipldResolver.get(cid, path, options, callback) }) } From 77e2db8c4a0ee275f2f42a4bf9dfb77dc58747c0 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 12 Mar 2017 00:29:13 +0000 Subject: [PATCH 2/8] feat: .dag.tree --- src/core/components/dag.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/core/components/dag.js b/src/core/components/dag.js index 34f4ac3587..0c1a47ebde 100644 --- a/src/core/components/dag.js +++ b/src/core/components/dag.js @@ -2,12 +2,14 @@ const promisify = require('promisify-es6') const CID = require('cids') +const pull = require('pull-stream') module.exports = function dag (self) { return { put: promisify((dagNode, options, callback) => { self._ipldResolver.put(dagNode, options, callback) }), + get: promisify((cid, path, options, callback) => { if (typeof path === 'function') { callback = path @@ -34,6 +36,42 @@ module.exports = function dag (self) { } self._ipldResolver.get(cid, path, options, callback) + }), + + tree: promisify((cid, path, options, callback) => { + if (typeof path === 'function') { + callback = path + path = undefined + } + + if (typeof options === 'function') { + callback = options + options = {} + } + + options = options || {} + + if (typeof cid === 'string') { + const split = cid.split('/') + cid = new CID(split[0]) + split.shift() + + if (split.length > 0) { + path = split.join('/') + } else { + path = '/' + } + } + + pull( + self._ipldResolver.treeStream(cid, path, options), + pull.collect((err, results) => { + if (err) { + return callback(err) + } + callback(null, results) + }) + ) }) } } From 76a922236dc81d6c5e59eeb61bb22618b01deafe Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 12 Mar 2017 04:53:29 +0000 Subject: [PATCH 3/8] test: .tree tests everywhere --- src/core/components/dag.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/components/dag.js b/src/core/components/dag.js index 0c1a47ebde..effbd7f459 100644 --- a/src/core/components/dag.js +++ b/src/core/components/dag.js @@ -39,6 +39,12 @@ module.exports = function dag (self) { }), tree: promisify((cid, path, options, callback) => { + if (typeof path === 'object') { + callback = options + options = path + path = undefined + } + if (typeof path === 'function') { callback = path path = undefined @@ -59,7 +65,7 @@ module.exports = function dag (self) { if (split.length > 0) { path = split.join('/') } else { - path = '/' + path = undefined } } From db2013d5d3611c162771171ec530cf7048dabb63 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 12 Mar 2017 20:25:09 +0000 Subject: [PATCH 4/8] docs: add dag-api examples!! --- examples/README.md | 1 + examples/dag/README.md | 11 ++++ examples/dag/create-node.js | 28 +++++++++++ examples/dag/eth-blocks/block_302515 | Bin 0 -> 530 bytes examples/dag/eth-blocks/block_302516 | Bin 0 -> 530 bytes examples/dag/eth-blocks/block_302517 | Bin 0 -> 527 bytes examples/dag/eth.js | 53 ++++++++++++++++++++ examples/dag/get-path-accross-formats.js | 61 +++++++++++++++++++++++ examples/dag/get-path.js | 48 ++++++++++++++++++ examples/dag/get.js | 30 +++++++++++ examples/dag/put.js | 25 ++++++++++ examples/dag/tree.js | 61 +++++++++++++++++++++++ 12 files changed, 318 insertions(+) create mode 100644 examples/dag/README.md create mode 100644 examples/dag/create-node.js create mode 100644 examples/dag/eth-blocks/block_302515 create mode 100644 examples/dag/eth-blocks/block_302516 create mode 100644 examples/dag/eth-blocks/block_302517 create mode 100644 examples/dag/eth.js create mode 100644 examples/dag/get-path-accross-formats.js create mode 100644 examples/dag/get-path.js create mode 100644 examples/dag/get.js create mode 100644 examples/dag/put.js create mode 100644 examples/dag/tree.js diff --git a/examples/README.md b/examples/README.md index 98fda715cc..41c99f5266 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,5 +10,6 @@ Let us know if you find any issue or if you want to contribute and add a new tut - [How to bundle js-ipfs with Browserify](./bundle-browserify) - [How to bundle js-ipfs with WebPack](./bundle-webpack) - [Use IPFS to explore the Ethereum BlockChain](./explore-ethereum) +- [Create and resolve through graphs with the dag API](./dag) ## Tutorials diff --git a/examples/dag/README.md b/examples/dag/README.md new file mode 100644 index 0000000000..58b93b1aee --- /dev/null +++ b/examples/dag/README.md @@ -0,0 +1,11 @@ +Create and resolve through graphs with the dag API +================================================== + +In this set of examples, you can find snippets of code to: + +- [create nodes of a graph](./put.js) +- [retrieve a graph node](./get.js) +- [resolve a path in a graph](./get-path.js) +- [resolve through graphs of different kind](./get-path-accross-formats.js) +- [explore a graph with the .tree](./tree.js) +- [traverse through a slice of the ethereum blockchain](./eth.js) diff --git a/examples/dag/create-node.js b/examples/dag/create-node.js new file mode 100644 index 0000000000..e95f602bbc --- /dev/null +++ b/examples/dag/create-node.js @@ -0,0 +1,28 @@ +'use strict' + +const series = require('async/series') + +const IPFS = require('../../src/core') +// In your project, replace by the following line and install IPFS as a dep +// const IPFS = require('ipfs') + +function createNode (options, callback) { + if (typeof options === 'function') { + callback = options + options = {} + } + + options.path = options.path || '/tmp/ipfs' + Math.random() + + const node = new IPFS({ + repo: options.path + }) + + series([ + (cb) => node.init({ emptyRepo: true, bits: 2048 }, cb), + (cb) => node.load(cb), + (cb) => node.goOnline(cb) + ], (err) => callback(err, node)) +} + +module.exports = createNode diff --git a/examples/dag/eth-blocks/block_302515 b/examples/dag/eth-blocks/block_302515 new file mode 100644 index 0000000000000000000000000000000000000000..1e6b8fdc5179ffc55027bd82152b9eb5b657faab GIT binary patch literal 530 zcmey##J|Ay4NLWj2X~YtT;^%9w4W;28NW4Ov3H7YlQ+}+f=+9{1+r&+U)(z$TeZ4% zYx=e`SEMcrxk^vzDiQv$(CM$kmC5c?UZwlreJ=8M`rOBFKYYzvS(x3~cVdD6xt}3- zwSygZ*EuMveXz^a;JN*lYwp6&3ws!reOvRUYeCoxd2#78q09a^yFQzA;74Ax#{=n^ zIcpCvCh2c|oV-PGL9+3Z{mdSEeR2Bf#|6qZ=Wx%ep0&&;^J^}TV93=??t(iR8Sn!I zWN8*;4zX-PHV|tL$?Al_Iur=$Ybz2yP-Atp*+5ma*_KnWnc2RfC1S4T?f%q~jMSps z%)C?uU4_tK!v&dNC9|cU#H|rN5LNHYsDESzQ*mH)r+HOrY@0^O=MM9Z=PB$mbBpu- F007XRfQtYC literal 0 HcmV?d00001 diff --git a/examples/dag/eth-blocks/block_302516 b/examples/dag/eth-blocks/block_302516 new file mode 100644 index 0000000000000000000000000000000000000000..9c4a667658040dd45491fa8890b5708b6f25236c GIT binary patch literal 530 zcmey##J}J+e|*K~4QG@pW}V`Y`|2-Xc<5Z#^2fKu8z+7I`ix)X#RAzgzAx?_kF8qW zx;1^w z^*cMsbmFCLzSB?Hy414Wee5q=wlb-3>4`V{BNm+AWb=mY80YeRWjlk5GIH-!>!q$# z{yx>Bz38C6Z_cqr3j~gHPjfN5zs>Q%^6d>zJfams(jIXp={QcE7Cy@~C`f82BLfz| zfe=#wG8S|a9Z-syMDDM&3!EzMPM4Gr=Sa9uFnN^|1|nJrS`rki75=k+{~=MCNv aCz^5a!S)QX#YIS~LwB85W$ literal 0 HcmV?d00001 diff --git a/examples/dag/eth-blocks/block_302517 b/examples/dag/eth-blocks/block_302517 new file mode 100644 index 0000000000000000000000000000000000000000..3df292fd2d8fedbed277049fac4886e2c583ff0c GIT binary patch literal 527 zcmey##IqpVF2wQuKbIhx$3NuDcTbw}zW&zRpNf)_r~UuhW@O}?T_AhL_r<;Au~n;E zx2A79b4BX1kgN2Rt`gx73!VNtT$$`XCGiBu4K1sqMuw%lYY*C#S4SFh-&~+G;kPoI z-4j2%Io?zBwHABF?{7Bh)V!ROR^$`>@cb;^1z|7b#ih@LF8kl?`fSpHA9>Lp52R=2 ztUbV(q`&oX@)kvc3U)FwjC9aeWYBK0;%c*js(7<4k4!^L#9YnC{ZDo@Ki#|X`O { + if (err) { + throw err + } + + console.log('\nStart of the example:') + + const ethBlocks = [ + path.join(__dirname, '/eth-blocks/block_302516'), + path.join(__dirname, '/eth-blocks/block_302517') + ] + + asyncEach(ethBlocks, (ethBlockPath, cb) => { + const data = fs.readFileSync(ethBlockPath) + + multihashing(data, 'keccak-256', (err, multihash) => { + if (err) { + cb(err) + } + const cid = new CID(1, 'eth-block', multihash) + // console.log(cid.toBaseEncodedString()) + + ipfs.block.put(new Block(data), cid, cb) + }) + }, (err) => { + if (err) { + throw err + } + + const block302516 = 'z43AaGEywSDX5PUJcrn5GfZmb6FjisJyR7uahhWPk456f7k7LDA' + const block302517 = 'z43AaGF42R2DXsU65bNnHRCypLPr9sg6D7CUws5raiqATVaB1jj' + + function errOrLog (err, result) { + if (err) { + throw err + } + console.log(result.value.toString('hex')) + } + + ipfs.dag.get(block302516 + '/number', errOrLog) + ipfs.dag.get(block302517 + '/parent/number', errOrLog) + }) +}) diff --git a/examples/dag/get-path-accross-formats.js b/examples/dag/get-path-accross-formats.js new file mode 100644 index 0000000000..f3abae4d40 --- /dev/null +++ b/examples/dag/get-path-accross-formats.js @@ -0,0 +1,61 @@ +'use strict' + +const createNode = require('./create-node.js') +const series = require('async/series') +const dagPB = require('ipld-dag-pb') + +createNode((err, ipfs) => { + if (err) { + throw err + } + + console.log('\nStart of the example:') + + let cidPBNode + let cidCBORNode + + series([ + (cb) => { + const someData = new Buffer('capoeira') + + dagPB.DAGNode.create(someData, (err, node) => { + if (err) { + cb(err) + } + + ipfs.dag.put(node, { format: 'dag-pb', hashAlg: 'sha2-256' }, (err, cid) => { + if (err) { + cb(err) + } + cidPBNode = cid + cb() + }) + }) + }, + (cb) => { + const myData = { + name: 'David', + likes: ['js-ipfs', 'icecream', 'steak'], + hobbies: [{ '/': cidPBNode.toBaseEncodedString() }] + } + + ipfs.dag.put(myData, { format: 'dag-cbor', hashAlg: 'sha3-512' }, (err, cid) => { + if (err) { + throw err + } + + cidCBORNode = cid + cb() + }) + }, + (cb) => { + ipfs.dag.get(cidCBORNode, 'hobbies/0/Data', (err, result) => { + if (err) { + throw err + } + + console.log(result.value.toString()) + }) + } + ]) +}) diff --git a/examples/dag/get-path.js b/examples/dag/get-path.js new file mode 100644 index 0000000000..8e2b161792 --- /dev/null +++ b/examples/dag/get-path.js @@ -0,0 +1,48 @@ +'use strict' + +const createNode = require('./create-node.js') + +createNode((err, ipfs) => { + if (err) { + throw err + } + + console.log('\nStart of the example:') + + const myData = { + name: 'David', + likes: ['js-ipfs', 'icecream', 'steak'] + } + + ipfs.dag.put(myData, { format: 'dag-cbor', hashAlg: 'sha2-256' }, (err, cid) => { + if (err) { + throw err + } + + ipfs.dag.get(cid, 'name', (err, result) => { + if (err) { + throw err + } + + console.log(result.value, result.remainderPath) + }) + + ipfs.dag.get(cid, 'likes', (err, result) => { + if (err) { + throw err + } + + console.log(result.value) + }) + + const cidStr = cid.toBaseEncodedString() + + ipfs.dag.get(cidStr + '/likes/0', (err, result) => { + if (err) { + throw err + } + + console.log(result.value) + }) + }) +}) diff --git a/examples/dag/get.js b/examples/dag/get.js new file mode 100644 index 0000000000..8f0d90b68d --- /dev/null +++ b/examples/dag/get.js @@ -0,0 +1,30 @@ +'use strict' + +const createNode = require('./create-node.js') + +createNode((err, ipfs) => { + if (err) { + throw err + } + + console.log('\nStart of the example:') + + const myData = { + name: 'David', + likes: ['js-ipfs', 'icecream', 'steak'] + } + + ipfs.dag.put(myData, { format: 'dag-cbor', hashAlg: 'sha2-256' }, (err, cid) => { + if (err) { + throw err + } + + ipfs.dag.get(cid, (err, result) => { + if (err) { + throw err + } + + console.log(JSON.stringify(result.value)) + }) + }) +}) diff --git a/examples/dag/put.js b/examples/dag/put.js new file mode 100644 index 0000000000..9e8d2c93b2 --- /dev/null +++ b/examples/dag/put.js @@ -0,0 +1,25 @@ +'use strict' + +const createNode = require('./create-node.js') + +createNode((err, ipfs) => { + if (err) { + throw err + } + + console.log('\nStart of the example:') + + const myData = { + name: 'David', + likes: ['js-ipfs', 'icecream', 'steak'] + } + + ipfs.dag.put(myData, { format: 'dag-cbor', hashAlg: 'sha2-256' }, (err, cid) => { + if (err) { + throw err + } + console.log(cid.toBaseEncodedString()) + // should print: + // zdpuAzZSktMhXjJu5zneSFrg9ue5rLXKAMC9KLigqhQ7Q7vRm + }) +}) diff --git a/examples/dag/tree.js b/examples/dag/tree.js new file mode 100644 index 0000000000..6608faed27 --- /dev/null +++ b/examples/dag/tree.js @@ -0,0 +1,61 @@ +'use strict' + +const createNode = require('./create-node.js') +const series = require('async/series') +const dagPB = require('ipld-dag-pb') + +createNode((err, ipfs) => { + if (err) { + throw err + } + + console.log('\nStart of the example:') + + let cidPBNode + let cidCBORNode + + series([ + (cb) => { + const someData = new Buffer('capoeira') + + dagPB.DAGNode.create(someData, (err, node) => { + if (err) { + cb(err) + } + + ipfs.dag.put(node, { format: 'dag-pb', hashAlg: 'sha2-256' }, (err, cid) => { + if (err) { + cb(err) + } + cidPBNode = cid + cb() + }) + }) + }, + (cb) => { + const myData = { + name: 'David', + likes: ['js-ipfs', 'icecream', 'steak'], + hobbies: [{ '/': cidPBNode.toBaseEncodedString() }] + } + + ipfs.dag.put(myData, { format: 'dag-cbor', hashAlg: 'sha3-512' }, (err, cid) => { + if (err) { + throw err + } + + cidCBORNode = cid + cb() + }) + }, + (cb) => { + ipfs.dag.tree(cidCBORNode, { recursive: true }, (err, paths) => { + if (err) { + throw err + } + + console.log(paths) + }) + } + ]) +}) From 745ce9f2661355380abc652e694e0f689ccd9f55 Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 13 Mar 2017 14:29:14 +0000 Subject: [PATCH 5/8] chore: update deps --- package.json | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 1a36705dbb..74884eb9d1 100644 --- a/package.json +++ b/package.json @@ -69,13 +69,13 @@ "delay": "^1.3.1", "detect-node": "^2.0.3", "dir-compare": "^1.3.0", - "eslint-plugin-react": "^6.9.0", - "execa": "^0.6.0", + "eslint-plugin-react": "^6.10.0", + "execa": "^0.6.1", "expose-loader": "^0.7.3", "form-data": "^2.1.2", "gulp": "^3.9.1", - "interface-ipfs-core": "~0.24.1", - "ipfsd-ctl": "~0.18.3", + "interface-ipfs-core": "~0.25.0", + "ipfsd-ctl": "~0.19.0", "left-pad": "^1.1.3", "lodash": "^4.17.4", "mocha": "^3.2.0", @@ -83,17 +83,17 @@ "nexpect": "^0.5.0", "pre-commit": "^1.2.2", "pretty-bytes": "^4.0.2", - "qs": "^6.3.0", + "qs": "^6.4.0", "random-fs": "^1.0.3", - "rimraf": "^2.5.4", + "rimraf": "^2.6.1", "stream-to-promise": "^2.2.0", - "transform-loader": "^0.2.3" + "transform-loader": "^0.2.4" }, "dependencies": { - "async": "^2.1.4", + "async": "^2.1.5", "bl": "^1.2.0", "boom": "^4.2.0", - "debug": "^2.6.1", + "debug": "^2.6.2", "fs-pull-blob-store": "~0.4.1", "glob": "^7.1.1", "hapi": "^16.1.0", @@ -101,17 +101,17 @@ "hoek": "^4.1.0", "idb-pull-blob-store": "~0.5.1", "ipfs-api": "^12.1.7", - "ipfs-bitswap": "~0.9.4", + "ipfs-bitswap": "~0.9.5", "ipfs-block": "~0.5.5", "ipfs-block-service": "~0.8.3", "ipfs-multipart": "~0.1.0", "ipfs-repo": "~0.11.3", - "ipfs-unixfs": "~0.1.10", + "ipfs-unixfs": "~0.1.11", "ipfs-unixfs-engine": "~0.17.0", - "ipld-resolver": "~0.9.0", + "ipld-resolver": "~0.10.0", "isstream": "^0.1.2", "joi": "^10.2.2", - "libp2p-floodsub": "~0.7.3", + "libp2p-floodsub": "~0.7.4", "libp2p-ipfs-browser": "~0.19.0", "libp2p-ipfs-nodejs": "~0.19.0", "lodash.flatmap": "^4.5.0", @@ -123,7 +123,7 @@ "mafmt": "^2.1.6", "mkdirp": "^0.5.1", "multiaddr": "^2.2.1", - "multihashes": "~0.3.3", + "multihashes": "~0.4.3", "path-exists": "^3.0.0", "peer-book": "~0.3.1", "peer-id": "~0.8.2", @@ -142,8 +142,8 @@ "tar-stream": "^1.5.2", "temp": "^0.8.3", "through2": "^2.0.3", - "update-notifier": "^2.0.0", - "yargs": "^6.6.0" + "update-notifier": "^2.1.0", + "yargs": "^7.0.2" }, "contributors": [ "Andrew de Andrade ", @@ -178,4 +178,4 @@ "npmcdn-to-unpkg-bot ", "ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ " ] -} \ No newline at end of file +} From 2cec2a4f542c422002244f5a87675061044dcd3e Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 13 Mar 2017 14:52:39 +0000 Subject: [PATCH 6/8] docs: add video to the example --- examples/dag/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/dag/README.md b/examples/dag/README.md index 58b93b1aee..97f5ad317b 100644 --- a/examples/dag/README.md +++ b/examples/dag/README.md @@ -9,3 +9,9 @@ In this set of examples, you can find snippets of code to: - [resolve through graphs of different kind](./get-path-accross-formats.js) - [explore a graph with the .tree](./tree.js) - [traverse through a slice of the ethereum blockchain](./eth.js) + +### Video of the demos + +You can find a video with a walkthrough of this examples on Youtube: + +- [IPFS DAG API Preview](https://youtu.be/drULwJ_ZDRQ?t=1m29s) From 32111c03e29806ba89c07204c571234482b350d1 Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 13 Mar 2017 15:35:22 +0000 Subject: [PATCH 7/8] fix: object input-enc flag --- package.json | 2 +- src/cli/commands/object/put.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 74884eb9d1..bb2981a301 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "temp": "^0.8.3", "through2": "^2.0.3", "update-notifier": "^2.1.0", - "yargs": "^7.0.2" + "yargs": "^6.6.0" }, "contributors": [ "Andrew de Andrade ", diff --git a/src/cli/commands/object/put.js b/src/cli/commands/object/put.js index 91e20c372b..1e6a6c38a1 100644 --- a/src/cli/commands/object/put.js +++ b/src/cli/commands/object/put.js @@ -29,7 +29,7 @@ module.exports = { describe: 'Stores input as a DAG object, outputs its key', builder: { - inputenc: { + 'input-enc': { type: 'string', default: 'json' } @@ -38,7 +38,7 @@ module.exports = { handler (argv) { if (argv.data) { const buf = fs.readFileSync(argv.data) - putNode(buf, argv.inputenc) + putNode(buf, argv.inputEnc) return } @@ -47,7 +47,7 @@ module.exports = { throw err } - putNode(input, argv.inputenc) + putNode(input, argv.inputEnc) })) } } From e879e5d1eda33388a847e741e300b886b920627a Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 13 Mar 2017 16:02:54 +0000 Subject: [PATCH 8/8] cr --- src/core/components/dag.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/core/components/dag.js b/src/core/components/dag.js index effbd7f459..1bf52b8abb 100644 --- a/src/core/components/dag.js +++ b/src/core/components/dag.js @@ -71,12 +71,7 @@ module.exports = function dag (self) { pull( self._ipldResolver.treeStream(cid, path, options), - pull.collect((err, results) => { - if (err) { - return callback(err) - } - callback(null, results) - }) + pull.collect(callback) ) }) }