UNPKG

ipfs

Version:

JavaScript implementation of the IPFS specification

218 lines (181 loc) 5.91 kB
'use strict' const promisify = require('promisify-es6') const CID = require('cids') const pull = require('pull-stream') const iterToPull = require('async-iterator-to-pull-stream') const mapAsync = require('async/map') const setImmediate = require('async/setImmediate') const flattenDeep = require('just-flatten-it') const errCode = require('err-code') const multicodec = require('multicodec') module.exports = function dag (self) { return { put: promisify((dagNode, options, callback) => { if (typeof options === 'function') { callback = options options = {} } options = options || {} if (options.cid && (options.format || options.hashAlg)) { return callback(new Error('Can\'t put dag node. Please provide either `cid` OR `format` and `hashAlg` options.')) } else if (((options.format && !options.hashAlg) || (!options.format && options.hashAlg))) { return callback(new Error('Can\'t put dag node. Please provide `format` AND `hashAlg` options.')) } const optionDefaults = { format: multicodec.DAG_CBOR, hashAlg: multicodec.SHA2_256 } // The IPLD expects the format and hashAlg as constants if (options.format && typeof options.format === 'string') { const constantName = options.format.toUpperCase().replace(/-/g, '_') options.format = multicodec[constantName] } if (options.hashAlg && typeof options.hashAlg === 'string') { const constantName = options.hashAlg.toUpperCase().replace(/-/g, '_') options.hashAlg = multicodec[constantName] } options = options.cid ? options : Object.assign({}, optionDefaults, options) // js-ipld defaults to verion 1 CIDs. Hence set version 0 explicitly for // dag-pb nodes if (options.version === undefined) { if (options.format === multicodec.DAG_PB && options.hashAlg === multicodec.SHA2_256) { options.version = 0 } else { options.version = 1 } } self._ipld.put(dagNode, options.format, { hashAlg: options.hashAlg, cidVersion: options.version }).then( (cid) => { if (options.preload !== false) { self._preload(cid) } return callback(null, cid) }, (error) => callback(error) ) }), get: promisify((cid, path, options, callback) => { if (typeof path === 'function') { callback = path path = undefined } if (typeof options === 'function') { callback = options // Allow options in path position if (typeof path !== 'string') { options = path path = undefined } else { options = {} } } options = options || {} if (typeof cid === 'string') { const split = cid.split('/') try { cid = new CID(split[0]) } catch (err) { return setImmediate(() => callback(errCode(err, 'ERR_INVALID_CID'))) } split.shift() if (split.length > 0) { path = split.join('/') } else { path = '/' } } else if (Buffer.isBuffer(cid)) { try { cid = new CID(cid) } catch (err) { return setImmediate(() => callback(errCode(err, 'ERR_INVALID_CID'))) } } if (options.preload !== false) { self._preload(cid) } if (path === undefined || path === '/') { self._ipld.get(cid).then( (value) => { callback(null, { value, remainderPath: '' }) }, (error) => callback(error) ) } else { const result = self._ipld.resolve(cid, path) const promisedValue = options.localResolve ? result.first() : result.last() promisedValue.then( (value) => callback(null, value), (error) => callback(error) ) } }), tree: promisify((cid, path, options, callback) => { if (typeof path === 'object') { callback = options options = path path = undefined } 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('/') try { cid = new CID(split[0]) } catch (err) { return setImmediate(() => callback(errCode(err, 'ERR_INVALID_CID'))) } split.shift() if (split.length > 0) { path = split.join('/') } else { path = undefined } } if (options.preload !== false) { self._preload(cid) } pull( iterToPull(self._ipld.tree(cid, path, options)), pull.collect(callback) ) }), // TODO - use IPLD selectors once they are implemented _getRecursive: promisify((multihash, options, callback) => { // gets flat array of all DAGNodes in tree given by multihash if (typeof options === 'function') { callback = options options = {} } options = options || {} let cid try { cid = new CID(multihash) } catch (err) { return setImmediate(() => callback(errCode(err, 'ERR_INVALID_CID'))) } self.dag.get(cid, '', options, (err, res) => { if (err) { return callback(err) } mapAsync(res.value.Links, (link, cb) => { self.dag._getRecursive(link.Hash, options, cb) }, (err, nodes) => { // console.log('nodes:', nodes) if (err) return callback(err) callback(null, flattenDeep([res.value, nodes])) }) }) }) } }