diff --git a/package.json b/package.json index 0fabfe21c..9e86be21d 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "glob": "^7.1.2", "ipfs-block": "~0.6.1", "ipfs-unixfs": "~0.1.14", + "ipld-dag-cbor": "^0.12.0", "ipld-dag-pb": "~0.13.1", "is-ipfs": "^0.3.2", "is-stream": "^1.1.0", diff --git a/src/dag/get.js b/src/dag/get.js new file mode 100644 index 000000000..ead6a732c --- /dev/null +++ b/src/dag/get.js @@ -0,0 +1,52 @@ +'use strict' + +const dagPB = require('ipld-dag-pb') +const dagCBOR = require('ipld-dag-cbor') +const promisify = require('promisify-es6') +const CID = require('cids') +const waterfall = require('async/waterfall') +const block = require('../block') + +module.exports = (send) => { + return promisify((cid, path, options, callback) => { + if (typeof path === 'function') { + callback = path + path = undefined + } + + if (typeof options === 'function') { + callback = options + options = {} + } + + options = options || {} + path = path || '' + + if (CID.isCID(cid)) { + cid = cid.toBaseEncodedString() + } + + waterfall([ + cb => { + send({ + path: 'dag/resolve', + args: cid + '/' + path, + qs: options + }, cb) + }, + (resolved, cb) => { + block(send).get(new CID(resolved['Cid']['/']), (err, ipfsBlock) => { + cb(err, ipfsBlock, resolved['RemPath']) + }) + }, + (ipfsBlock, path, cb) => { + if (ipfsBlock.cid.codec === 'dag-cbor') { + dagCBOR.resolver.resolve(ipfsBlock.data, path, cb) + } + if (ipfsBlock.cid.codec === 'dag-pb') { + dagPB.resolver.resolve(ipfsBlock.data, path, cb) + } + } + ], callback) + }) +} diff --git a/src/dag/index.js b/src/dag/index.js new file mode 100644 index 000000000..bb6b1333c --- /dev/null +++ b/src/dag/index.js @@ -0,0 +1,12 @@ +'use strict' + +const moduleConfig = require('../utils/module-config') + +module.exports = (arg) => { + const send = moduleConfig(arg) + + return { + get: require('./get')(send), + put: require('./put')(send) + } +} diff --git a/src/dag/put.js b/src/dag/put.js new file mode 100644 index 000000000..541c0d512 --- /dev/null +++ b/src/dag/put.js @@ -0,0 +1,69 @@ +'use strict' + +const dagPB = require('ipld-dag-pb') +const dagCBOR = require('ipld-dag-cbor') +const promisify = require('promisify-es6') +const CID = require('cids') +const multihash = require('multihashes') +const SendOneFile = require('../utils/send-one-file') + +function noop () {} + +module.exports = (send) => { + const sendOneFile = SendOneFile(send, 'dag/put') + + return promisify((dagNode, options, callback) => { + if (typeof options === 'function') { + return setImmediate(() => callback(new Error('no options were passed'))) + } + + callback = callback || noop + + let hashAlg = options.hash || 'sha2-256' + let format + let inputEnc + + if (options.cid && CID.isCID(options.cid)) { + format = options.cid.codec + hashAlg = multihash.decode(options.cid.multihash).name + prepare() + } else if (options.format) { + format = options.format + prepare() + } else { + callback(new Error('Invalid arguments')) + } + + function prepare () { + inputEnc = 'raw' + + if (format === 'dag-cbor') { + dagCBOR.util.serialize(dagNode, finalize) + } + if (format === 'dag-pb') { + dagPB.util.serialize(dagNode, finalize) + } + } + + function finalize (err, serialized) { + if (err) { return callback(err) } + const sendOptions = { + qs: { + hash: hashAlg, + format: format, + 'input-enc': inputEnc + } + } + sendOneFile(serialized, sendOptions, (err, result) => { + if (err) { + return callback(err) + } + if (result['Cid']) { + return callback(null, new CID(result['Cid']['/'])) + } else { + return callback(result) + } + }) + } + }) +} diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index e86982e18..2a19a7b6d 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -21,6 +21,7 @@ function requireCommands () { bootstrap: require('../bootstrap'), commands: require('../commands'), config: require('../config'), + dag: require('../dag'), dht: require('../dht'), diag: require('../diag'), id: require('../id'), diff --git a/test/interface/dag.spec.js b/test/interface/dag.spec.js new file mode 100644 index 000000000..6c68680e7 --- /dev/null +++ b/test/interface/dag.spec.js @@ -0,0 +1,34 @@ +/* eslint-env mocha */ + +'use strict' + +const test = require('interface-ipfs-core') +const parallel = require('async/parallel') + +const IPFSApi = require('../../src') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create() + +const nodes = [] +const common = { + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, IPFSApi(_ipfsd.apiAddr)) + }) + } + }) + }, + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + } +} + +test.dag(common)