Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
fix: make addLink() synchronous
Browse files Browse the repository at this point in the history
BREAKING CHANGE: It's no longer possible to pass a `DAGNode` into `addLink()`.

Intead of passing in a `DAGNode` into `addLink()`, convert that node into
a `DAGLink` via `toDAGLink()`.

Example:

Prior to this change:

    const node = new DAGNode('some data')
    const node2 = new DAGNode('use that as link')
    await DAGNode.addLink(node, node2)

Now:

    const node = new DAGNode('some data')
    const node2 = new DAGNode('use that as link')
    DAGNode.addLink(node, await node2.toDAGLink())

Closes #128.
  • Loading branch information
vmx committed Jul 19, 2019
1 parent 029174d commit 7f1a00a
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 48 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- [`node.size`](#nodesize)
- [`node.toJSON()`](#nodetojson)
- [`node.toString()`](#nodetostring)
- [`node.toDAGLink(options)`](#nodetodaglinkoptions)
- [DAGLink functions](#daglink-functions)
- [DAGLink constructor](#daglink-constructor)
- [DAGLink instance methods and properties](#daglink-instance-methods-and-properties)
Expand Down Expand Up @@ -93,7 +94,7 @@ const link = {
Tsize: 42
}

await DAGNode.addLink(node, link)
DAGNode.addLink(node, link)
console.log('with link', node.toJSON())

DAGNode.rmLink(nodeA, 'I am a link')
Expand Down Expand Up @@ -154,7 +155,7 @@ const link = {
Hash: <cid> // can be a String CID, CID buffer or CID object
}

await DAGNode.addLink(node, link)
DAGNode.addLink(node, link)
```

#### rmLink(node, nameOrCid)
Expand Down Expand Up @@ -187,6 +188,19 @@ Size of the node, in bytes

#### `node.toString()`

#### `node.toDAGLink()`

- `options` - (optional) type: Object. Currently the only option is `name` to specify a named link.

Converts a `DAGNode` into a `DAGLink`.

```JavaScript
const node = new DAGNode('some data')
const link = node.toDAGLink()
// Named link
const link = node.toDAGLink({ name: 'name-of-the-link' })
```


### DAGLink functions

Expand Down
13 changes: 4 additions & 9 deletions src/dag-node/addLink.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
'use strict'

const sortLinks = require('./sortLinks')
const toDAGLink = require('./toDagLink')
const DAGLink = require('../dag-link')
const DAGNode = require('./index')

// Intentionally keeping the `async` to signal that it may return a promise
// eslint-disable-next-line require-await
const asDAGLink = async (link) => {
const asDAGLink = (link) => {
if (DAGLink.isDAGLink(link)) {
// It's a DAGLink instance
// no need to do anything
return link
}

if (DAGNode.isDAGNode(link)) {
// It's a DAGNode instance
// convert to link
return toDAGLink(link, {})
throw new Error('Link must be a DAGLink or DAGLink-like. Convert the DAGNode into a DAGLink via `node.toDAGLink()`.')
}

// It's a Object with name, multihash/hash/cid and size
return new DAGLink(link.Name || link.name, link.Tsize || link.size, link.Hash || link.multihash || link.hash || link.cid)
}

const addLink = async (node, link) => {
const dagLink = await asDAGLink(link)
const addLink = (node, link) => {
const dagLink = asDAGLink(link)
node._links.push(dagLink)
node._links = sortLinks(node._links)
}
Expand Down
6 changes: 6 additions & 0 deletions src/dag-node/dagNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const sortLinks = require('./sortLinks')
const visibility = require('../visibility')
const DAGLink = require('../dag-link/dagLink')
const { serializeDAGNode } = require('../serialize.js')
const toDAGLink = require('./toDagLink')

class DAGNode {
constructor (data, links = [], serializedSize = 0) {
Expand Down Expand Up @@ -57,6 +58,11 @@ class DAGNode {
return `DAGNode <data: "${this.Data.toString('base64')}", links: ${this.Links.length}, size: ${this.size}>`
}

// @returns {Promise.<DAGLink>}
toDAGLink (options) {
return toDAGLink(this, options)
}

get size () {
if (this._size === undefined) {
this._size = this._links.reduce((sum, l) => sum + l.Tsize, this._serializedSize)
Expand Down
9 changes: 5 additions & 4 deletions src/dag-node/toDagLink.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
'use strict'

const DAGLink = require('./../dag-link/dagLink')
const { cid, serialize } = require('../util')
const DAGLink = require('../dag-link/dagLink')
const { serializeDAGNode } = require('../serialize')
const genCid = require('../genCid')

/*
* toDAGLink converts a DAGNode to a DAGLink
*/
const toDAGLink = async (node, options = {}) => {
const serialized = serialize(node)
const nodeCid = await cid(serialized)
const serialized = serializeDAGNode(node)
const nodeCid = await genCid.cid(serialized)
return new DAGLink(options.name || '', serialized.length, nodeCid)
}

Expand Down
32 changes: 32 additions & 0 deletions src/genCid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict'

const CID = require('cids')
const multicodec = require('multicodec')
const multihashing = require('multihashing-async')

exports = module.exports

exports.codec = multicodec.DAG_PB
exports.defaultHashAlg = multicodec.SHA2_256

/**
* Calculate the CID of the binary blob.
*
* @param {Object} binaryBlob - Encoded IPLD Node
* @param {Object} [userOptions] - Options to create the CID
* @param {number} [userOptions.cidVersion=1] - CID version number
* @param {string} [UserOptions.hashAlg] - Defaults to the defaultHashAlg of the format
* @returns {Promise.<CID>}
*/
const cid = async (binaryBlob, userOptions) => {
const defaultOptions = { cidVersion: 1, hashAlg: exports.defaultHashAlg }
const options = Object.assign(defaultOptions, userOptions)

const multihash = await multihashing(binaryBlob, options.hashAlg)
const codecName = multicodec.print[exports.codec]
const cid = new CID(options.cidVersion, codecName, multihash)

return cid
}

exports.cid = cid
19 changes: 5 additions & 14 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
'use strict'

const CID = require('cids')
const protons = require('protons')
const proto = protons(require('./dag.proto'))
const DAGLink = require('./dag-link/dagLink')
const DAGNode = require('./dag-node/dagNode')
const multicodec = require('multicodec')
const multihashing = require('multihashing-async')
const { serializeDAGNode, serializeDAGNodeLike } = require('./serialize')
const genCid = require('./genCid')

exports = module.exports

exports.codec = multicodec.DAG_PB
exports.defaultHashAlg = multicodec.SHA2_256
exports.codec = genCid.codec
exports.defaultHashAlg = genCid.defaultHashAlg

/**
* Calculate the CID of the binary blob.
Expand All @@ -23,15 +21,8 @@ exports.defaultHashAlg = multicodec.SHA2_256
* @param {string} [UserOptions.hashAlg] - Defaults to the defaultHashAlg of the format
* @returns {Promise.<CID>}
*/
const cid = async (binaryBlob, userOptions) => {
const defaultOptions = { cidVersion: 1, hashAlg: exports.defaultHashAlg }
const options = Object.assign(defaultOptions, userOptions)

const multihash = await multihashing(binaryBlob, options.hashAlg)
const codecName = multicodec.print[exports.codec]
const cid = new CID(options.cidVersion, codecName, multihash)

return cid
const cid = (binaryBlob, userOptions) => {
return genCid.cid(binaryBlob, userOptions)
}

/**
Expand Down
35 changes: 16 additions & 19 deletions test/dag-node-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ chai.use(dirtyChai)
const dagPB = require('../src')
const DAGLink = dagPB.DAGLink
const DAGNode = dagPB.DAGNode
const toDAGLink = require('../src/dag-node/toDagLink')
const isNode = require('detect-node')
const multihash = require('multihashes')
const multicodec = require('multicodec')
Expand Down Expand Up @@ -126,7 +125,7 @@ module.exports = (repo) => {
it('addLink by DAGNode', async () => {
const node1 = new DAGNode(Buffer.from('1'))
const node2 = new DAGNode(Buffer.from('2'))
await DAGNode.addLink(node1, node2)
DAGNode.addLink(node1, await node2.toDAGLink())
expect(node1.Links.length).to.equal(1)
expect(node1.Links[0].Tsize).to.eql(node2.size)
expect(node1.Links[0].Name).to.be.eql('')
Expand All @@ -135,8 +134,8 @@ module.exports = (repo) => {
it('addLink by DAGLink', async () => {
const node1 = new DAGNode(Buffer.from('1'))
const node2 = new DAGNode(Buffer.from('2'))
const link = await toDAGLink(node2)
await DAGNode.addLink(node1, link)
const link = await node2.toDAGLink()
DAGNode.addLink(node1, link)
expect(node1.Links.length).to.equal(1)
expect(node1.Links[0].Tsize).to.eql(node2.size)
expect(node1.Links[0].Name).to.be.eql('')
Expand All @@ -145,9 +144,9 @@ module.exports = (repo) => {
it('addLink by object', async () => {
const node1 = new DAGNode(Buffer.from('1'))
const node2 = new DAGNode(Buffer.from('2'))
const link = await toDAGLink(node2)
const link = await node2.toDAGLink()
const linkObject = link.toJSON()
await DAGNode.addLink(node1, linkObject)
DAGNode.addLink(node1, linkObject)
expect(node1.Links.length).to.equal(1)
expect(node1.Links[0].Tsize).to.eql(node2.size)
expect(node1.Links[0].Name).to.be.eql('')
Expand All @@ -156,9 +155,9 @@ module.exports = (repo) => {
it('addLink by name', async () => {
const node1 = new DAGNode(Buffer.from('1'))
const node2 = new DAGNode(Buffer.from('2'))
const link = await toDAGLink(node2, { name: 'banana' })
const link = await node2.toDAGLink({ name: 'banana' })
expect(node1.Links.length).to.equal(0)
await DAGNode.addLink(node1, link)
DAGNode.addLink(node1, link)
expect(node1.Links.length).to.equal(1)
expect(node1.Links[0].Tsize).to.eql(node2.size)
expect(node1.Links[0].Name).to.eql('banana')
Expand All @@ -169,29 +168,27 @@ module.exports = (repo) => {
expect(node1.Links.length).to.equal(0)

const node2 = new DAGNode(Buffer.from('2'))
await DAGNode.addLink(node1, node2)
DAGNode.addLink(node1, await node2.toDAGLink())
expect(node1.Links.length).to.equal(1)

const node3 = new DAGNode(Buffer.from('3'))
await DAGNode.addLink(node1, node3)
DAGNode.addLink(node1, await node3.toDAGLink())
expect(node1.Links.length).to.equal(2)
})

it('addLink by DAGNode.Links', async () => {
const linkName = 'link-name'
const remote = new DAGNode(Buffer.from('2'))
const source = new DAGNode(Buffer.from('1'))
await DAGNode.addLink(
DAGNode.addLink(
source,
await toDAGLink(remote, {
name: linkName
})
await remote.toDAGLink({ name: linkName })
)

expect(source.Links.length).to.equal(1)

const target = new DAGNode(null, [], 0)
await DAGNode.addLink(target, source.Links[0])
DAGNode.addLink(target, source.Links[0])

expect(target.Links.length).to.equal(1)
expect(target.Links[0].Tsize).to.eql(remote.size)
Expand All @@ -204,9 +201,9 @@ module.exports = (repo) => {
const withoutLink = node1.toJSON()

const node2 = new DAGNode(Buffer.from('2'))
const link = await toDAGLink(node2, { name: 'banana' })
const link = await node2.toDAGLink({ name: 'banana' })

await DAGNode.addLink(node1, link)
DAGNode.addLink(node1, link)
expect(node1.Links.length).to.eql(1)
DAGNode.rmLink(node1, 'banana')
expect(node1.Links.length).to.eql(0)
Expand All @@ -219,9 +216,9 @@ module.exports = (repo) => {
const withoutLink = node1.toJSON()

const node2 = new DAGNode(Buffer.from('2'))
const link = await toDAGLink(node2, { name: 'banana' })
const link = await node2.toDAGLink({ name: 'banana' })

await DAGNode.addLink(node1, link)
DAGNode.addLink(node1, link)
expect(node1.Links.length).to.eql(1)
DAGNode.rmLink(node1, node1.Links[0].Hash)
expect(node1.Links.length).to.eql(0)
Expand Down

0 comments on commit 7f1a00a

Please sign in to comment.