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

feat: CBOR TAG #38

Merged
merged 3 commits into from
Jan 31, 2017
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
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,16 @@
"borc": "^2.0.2",
"bs58": "^4.0.0",
"cids": "^0.4.0",
"is-circular": "^1.0.1",
"multihashes": "^0.3.2",
"multihashing-async": "^0.4.0",
"traverse": "^0.6.6"
},
"devDependencies": {
"aegir": "^9.4.0",
"chai": "^3.5.0",
"deep-freeze": "0.0.1",
"garbage": "0.0.0",
"ipfs-block": "^0.5.4",
"pre-commit": "^1.2.2"
},
Expand All @@ -59,4 +62,4 @@
"npmcdn-to-unpkg-bot <npmcdn-to-unpkg-bot@users.noreply.github.com>",
"wanderer <mjbecze@gmail.com>"
]
}
}
83 changes: 67 additions & 16 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,90 @@ const multihashing = require('multihashing-async')
const CID = require('cids')
const waterfall = require('async/waterfall')
const setImmediate = require('async/setImmediate')
const isCircular = require('is-circular')

const resolver = require('./resolver')

// https://github.com/ipfs/go-ipfs/issues/3570#issuecomment-273931692
const CID_CBOR_TAG = 42

function tagCID (cid) {
return new cbor.Tagged(CID_CBOR_TAG, cid)
}

const decoder = new cbor.Decoder({
tags: {
[CID_CBOR_TAG]: (val) => ({'/': val})
}
})

function replaceCIDbyTAG (dagNode) {
if (isCircular(dagNode)) {
throw new Error('The object passed has circular references')
}

function transform (obj) {
if (!obj || Buffer.isBuffer(obj) || typeof obj === 'string') {
return obj
}

if (Array.isArray(obj)) {
return obj.map(transform)
}

const keys = Object.keys(obj)

// only `{'/': 'link'}` are valid
if (keys.length === 1 && keys[0] === '/') {
// Multiaddr encoding
// if (typeof link === 'string' && isMultiaddr(link)) {
// link = new Multiaddr(link).buffer
// }

return tagCID(obj['/'])
} else if (keys.length > 0) {
// Recursive transform
let out = {}
keys.forEach((key) => {
if (typeof obj[key] === 'object') {
out[key] = transform(obj[key])
} else {
out[key] = obj[key]
}
})
return out
} else {
return obj
}
}

return transform(dagNode)
}

exports = module.exports

exports.serialize = (dagNode, callback) => {
let serialized

try {
serialized = cbor.encode(dagNode)
const dagNodeTagged = replaceCIDbyTAG(dagNode)
serialized = cbor.encode(dagNodeTagged)
} catch (err) {
// return is important, otherwise in case of error the execution would continue
return setImmediate(() => {
callback(err)
})
return setImmediate(() => callback(err))
}
setImmediate(() => {
callback(null, serialized)
})
setImmediate(() => callback(null, serialized))
}

exports.deserialize = (data, callback) => {
let res
let deserialized

try {
res = cbor.decodeFirst(data)
deserialized = decoder.decodeFirst(data)
} catch (err) {
return setImmediate(() => {
callback(err)
})
return setImmediate(() => callback(err))
}

setImmediate(() => {
callback(null, res)
})
setImmediate(() => callback(null, deserialized))
}

exports.cid = (dagNode, callback) => {
Expand Down
43 changes: 42 additions & 1 deletion test/util.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,35 @@
'use strict'

const expect = require('chai').expect
const deepFreeze = require('deep-freeze')
const garbage = require('garbage')
const map = require('async/map')
const dagCBOR = require('../src')

describe('util', () => {
const obj = {
someKey: 'someValue',
link: { '/': 'aaaaa' }
link: { '/': 'aaaaa' },
links: [{'/': 1}, {'/': 2}],
nested: {
hello: 'world',
link: { '/': 'mylink' }
}
}

it('.serialize and .deserialize', (done) => {
// freeze, to ensure we don't change the source objecdt
deepFreeze(obj)
dagCBOR.util.serialize(obj, (err, serialized) => {
expect(err).to.not.exist
expect(Buffer.isBuffer(serialized)).to.be.true

// Check for the tag 42
// d8 = tag, 2a = 42
expect(
serialized.toString('hex').match(/d82a/g)
).to.have.length(4)

dagCBOR.util.deserialize(serialized, (err, deserialized) => {
expect(err).to.not.exist
expect(obj).to.eql(deserialized)
Expand Down Expand Up @@ -42,4 +58,29 @@ describe('util', () => {
done()
})
})

it('serialize and deserialize - garbage', (done) => {
const inputs = []
for (let i = 0; i < 1000; i++) {
inputs.push({in: garbage(100)})
}

map(inputs, (input, cb) => {
dagCBOR.util.serialize(input, cb)
}, (err, encoded) => {
if (err) {
return done(err)
}
map(encoded, (enc, cb) => {
dagCBOR.util.deserialize(enc, cb)
}, (err, out) => {
if (err) {
return done(err)
}

expect(inputs).to.be.eql(out)
done()
})
})
})
})