Skip to content
This repository has been archived by the owner on Mar 10, 2020. It is now read-only.

feat: support DAG API #534

Merged
merged 8 commits into from
Apr 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
52 changes: 52 additions & 0 deletions src/dag/get.js
Original file line number Diff line number Diff line change
@@ -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)
})
}
12 changes: 12 additions & 0 deletions src/dag/index.js
Original file line number Diff line number Diff line change
@@ -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)
}
}
69 changes: 69 additions & 0 deletions src/dag/put.js
Original file line number Diff line number Diff line change
@@ -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)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about all the other types?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use js-ipld here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Later. This PR is on for almost a year.

The plan surely is to use js-ipld. But that's not straight forward as js-ipld currently only works with local repositories and not with remote ones (that's what I wanted to mention in the JS Dev call but couldn't remember).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.

I'd import git here too as it's the one other (well) supported codec on go-ipfs side (and would be really handy to have for https://github.com/ipfs-shipyard/IGiS which can't use window.ipfs from api now)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it OK if I I open an issue for it and do it in a separate PR? That' also something newcomers can work on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR won't let users resolve through multiple IPLD formats.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@diasdavid Sounds like a test for that is missing in interface-ipfs-core then.

It will work once js-ipld is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of this thread: everything mentioned here is solved if js-ipld is used. Hence I propose merging this change as is currently is and open a new issue (I'll do that) to use js-ipld instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good my IPLD captain! 🚢

}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


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)
}
})
}
})
}
1 change: 1 addition & 0 deletions src/utils/load-commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
34 changes: 34 additions & 0 deletions test/interface/dag.spec.js
Original file line number Diff line number Diff line change
@@ -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)