Skip to content

Commit e29877c

Browse files
committed
Merge pull request #35 from dignifiedquire/fix-links
fix(dag-node): ensure links are always DAGLinks
2 parents 2cb6a44 + 0e4361f commit e29877c

14 files changed

+680
-554
lines changed

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,25 @@
3636
},
3737
"dependencies": {
3838
"bs58": "^3.0.0",
39-
"detect-node": "^2.0.3",
4039
"ipfs-block": "^0.3.0",
4140
"is-ipfs": "^0.2.0",
41+
"multihashes": "^0.2.2",
4242
"multihashing": "^0.2.0",
4343
"protocol-buffers": "^3.1.4",
4444
"stable": "^0.1.5"
4545
},
4646
"devDependencies": {
4747
"aegir": "^3.0.1",
48-
"async": "^1.5.2",
4948
"buffer-loader": "0.0.1",
5049
"chai": "^3.5.0",
5150
"fs-blob-store": "^5.2.1",
5251
"idb-plus-blob-store": "^1.0.0",
53-
"ipfs-block-service": "^0.3.0",
54-
"ipfs-repo": "^0.7.4",
52+
"ipfs-block-service": "^0.4.0",
53+
"ipfs-repo": "^0.8.0",
5554
"lodash": "^4.6.1",
5655
"ncp": "^2.0.0",
5756
"pre-commit": "^1.1.2",
58-
"rimraf": "^2.5.0"
57+
"rimraf": "^2.5.0",
58+
"run-series": "^1.1.4"
5959
}
60-
}
60+
}

src/dag-link.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict'
2+
3+
const mh = require('multihashes')
4+
5+
// Link represents an IPFS Merkle DAG Link between Nodes.
6+
module.exports = class DAGLink {
7+
constructor (name, size, hash) {
8+
this.name = name
9+
this.size = size
10+
11+
if (typeof hash === 'string') {
12+
this.hash = mh.fromB58String(hash)
13+
} else if (Buffer.isBuffer(hash)) {
14+
this.hash = hash
15+
}
16+
}
17+
18+
toJSON () {
19+
return {
20+
Name: this.name,
21+
Size: this.size,
22+
Hash: mh.toB58String(this.hash)
23+
}
24+
}
25+
26+
toString () {
27+
const hash = mh.toB58String(this.hash)
28+
return `DAGLink <${hash} - name: "${this.name}", size: ${this.size}>`
29+
}
30+
}

src/dag-node.js

Lines changed: 96 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,116 @@
11
'use strict'
22

3-
const util = require('./util')
43
const protobuf = require('protocol-buffers')
54
const stable = require('stable')
6-
const bs58 = require('bs58')
5+
const fs = require('fs')
6+
const path = require('path')
7+
const mh = require('multihashes')
8+
9+
const util = require('./util')
10+
const DAGLink = require('./dag-link')
11+
12+
const proto = protobuf(fs.readFileSync(path.join(__dirname, 'merkledag.proto')))
13+
14+
function linkSort (a, b) {
15+
return (new Buffer(a.name, 'ascii').compare(new Buffer(b.name, 'ascii')))
16+
}
717

8-
var schema = 'message PBLink {optional bytes Hash = 1; optional string Name = 2;optional uint64 Tsize = 3;} message PBNode {repeated PBLink Links = 2; optional bytes Data = 1;}'
18+
// Helper method to get a protobuf object equivalent
19+
function toProtoBuf (node) {
20+
const pbn = {}
921

10-
var mdagpb = protobuf(schema)
22+
if (node.data && node.data.length > 0) {
23+
pbn.Data = node.data
24+
} else {
25+
pbn.Data = null // new Buffer(0)
26+
}
27+
28+
if (node.links.length > 0) {
29+
pbn.Links = node.links.map((link) => {
30+
return {
31+
Hash: link.hash,
32+
Name: link.name,
33+
Tsize: link.size
34+
}
35+
})
36+
} else {
37+
pbn.Links = null
38+
}
1139

12-
exports = module.exports = {
13-
DAGLink: DAGLink,
14-
DAGNode: DAGNode
40+
return pbn
1541
}
1642

17-
function DAGNode (data, links) {
18-
var cached
19-
var encoded
43+
module.exports = class DAGNode {
44+
constructor (data, links) {
45+
this._cached = null
46+
this._encoded = null
2047

21-
this.data = data
22-
this.links = links || []
48+
this.data = data
49+
this.links = []
2350

24-
function linkSort (a, b) {
25-
return (new Buffer(a.name, 'ascii').compare(new Buffer(b.name, 'ascii')))
51+
// ensure links are instances of DAGLink
52+
if (links) {
53+
links.forEach((l) => {
54+
if (l.name && typeof l.toJSON === 'function') {
55+
this.links.push(l)
56+
} else {
57+
this.links.push(
58+
new DAGLink(l.Name, l.Size, l.Hash)
59+
)
60+
}
61+
})
62+
63+
stable.inplace(this.links, linkSort)
64+
}
2665
}
2766

2867
// copy - returns a clone of the DAGNode
29-
this.copy = () => {
30-
var clone = new DAGNode()
68+
copy () {
69+
const clone = new DAGNode()
3170
if (this.data && this.data.length > 0) {
32-
var buf = new Buffer(this.data.length)
71+
const buf = new Buffer(this.data.length)
3372
this.data.copy(buf)
3473
clone.data = buf
3574
}
3675

3776
if (this.links.length > 0) {
38-
clone.links = links.slice()
77+
clone.links = this.links.slice()
3978
}
4079

4180
return clone
4281
}
4382

4483
// addNodeLink - adds a DAGLink to this node that points to node by a name
45-
this.addNodeLink = (name, node) => {
84+
addNodeLink (name, node) {
4685
if (typeof name !== 'string') {
4786
return
4887
}
49-
var link = this.makeLink(node)
88+
const link = this.makeLink(node)
5089

5190
link.name = name
5291
this.addRawLink(link)
5392
}
5493

5594
// addRawLink adds a Link to this node from a DAGLink
56-
this.addRawLink = (link) => {
57-
encoded = null
95+
addRawLink (link) {
96+
this._encoded = null
5897
this.links.push(new DAGLink(link.name, link.size, link.hash))
5998
stable.inplace(this.links, linkSort)
6099
}
61100

62101
// UpdateNodeLink return a copy of the node with the link name set to point to
63102
// that. If a link of the same name existed, it is replaced.
64103
// TODO this would make more sense as an utility
65-
this.updateNodeLink = (name, node) => {
66-
var newnode = this.copy()
104+
updateNodeLink (name, node) {
105+
const newnode = this.copy()
67106
newnode.removeNodeLink(name)
68107
newnode.addNodeLink(name, node)
69108
return newnode
70109
}
71110

72111
// removeNodeLink removes a Link from this node based on name
73-
this.removeNodeLink = (name) => {
74-
encoded = null // uncache
112+
removeNodeLink (name) {
113+
this._encoded = null // uncache
75114
this.links = this.links.filter((link) => {
76115
if (link.name === name) {
77116
return false
@@ -80,9 +119,10 @@ function DAGNode (data, links) {
80119
}
81120
})
82121
}
122+
83123
// removeNodeLink removes a Link from this node based on a multihash
84-
this.removeNodeLinkByHash = (multihash) => {
85-
encoded = null // uncache
124+
removeNodeLinkByHash (multihash) {
125+
this._encoded = null // uncache
86126
this.links = this.links.filter((link) => {
87127
if (link.hash.equals(multihash)) {
88128
return false
@@ -92,130 +132,71 @@ function DAGNode (data, links) {
92132
})
93133
}
94134

95-
// removeNodeLink removes a Link from this node based on name
96-
this.removeNodeLink = (name) => {
97-
encoded = null // uncache
98-
this.links = this.links.filter((link) => {
99-
if (link.name === name) {
100-
return false
101-
} else {
102-
return true
103-
}
104-
})
105-
}
106-
107135
// makeLink returns a DAGLink node from a DAGNode
108136
// TODO: this would make more sense as an utility
109-
this.makeLink = (node) => {
110-
var size = node.size()
111-
var mh = node.multihash()
112-
return new DAGLink(null, size, mh)
137+
makeLink (node) {
138+
return new DAGLink(null, node.size(), node.multihash())
113139
}
114140

115141
// multihash - returns the multihash value of this DAGNode
116-
this.multihash = () => {
142+
multihash () {
117143
this.encoded()
118-
return cached
144+
return this._cached
119145
}
120146

121147
// Size returns the total size of the data addressed by node,
122148
// including the total sizes of references.
123-
this.size = () => {
124-
var buf = this.encoded()
149+
size () {
150+
const buf = this.encoded()
125151
if (!buf) {
126152
return 0
127153
}
128-
var size = buf.length
129-
for (var i = 0; i < this.links.length; i++) {
130-
size += this.links[i].size
131-
}
132-
return size
154+
155+
return this.links.reduce((sum, l) => sum + l.size, buf.length)
133156
}
134157

135158
// Encoded returns the encoded raw data version of a Node instance.
136159
// It may use a cached encoded version, unless the force flag is given.
137-
this.encoded = (force) => {
138-
if (force || !encoded) {
139-
encoded = this.marshal()
160+
encoded (force) {
161+
if (force || !this._encoded) {
162+
this._encoded = this.marshal()
140163

141-
if (encoded) {
142-
cached = util.hash(encoded)
164+
if (this._encoded) {
165+
this._cached = util.hash(this._encoded)
143166
}
144167
}
145-
return encoded
168+
return this._encoded
146169
}
147170

148171
// marshal - encodes the DAGNode into a probuf
149-
this.marshal = () => {
150-
var pbn = toProtoBuf(this)
151-
var data = mdagpb.PBNode.encode(pbn)
152-
return data
172+
marshal () {
173+
return proto.PBNode.encode(toProtoBuf(this))
153174
}
154175

155176
// unMarshal - decodes a protobuf into a DAGNode
156177
// TODO: this would make more sense as an utility
157-
this.unMarshal = function (data) {
158-
var pbn = mdagpb.PBNode.decode(data)
159-
this.links = []
160-
for (var i = 0; i < pbn.Links.length; i++) {
161-
var link = pbn.Links[i]
162-
var lnk = new DAGLink(link.Name, link.Tsize, link.Hash)
163-
this.links.push(lnk)
164-
}
178+
unMarshal (data) {
179+
const pbn = proto.PBNode.decode(data)
180+
this.links = pbn.Links.map((link) => {
181+
return new DAGLink(link.Name, link.Tsize, link.Hash)
182+
})
183+
165184
stable.inplace(this.links, linkSort)
166185
this.data = pbn.Data || new Buffer(0)
167186
return this
168187
}
169188

170-
// Helper method to get a protobuf object equivalent
171-
function toProtoBuf (node) {
172-
var pbn = {}
173-
174-
if (node.data && node.data.length > 0) {
175-
pbn.Data = node.data
176-
} else {
177-
pbn.Data = null // new Buffer(0)
178-
}
179-
180-
if (node.links.length > 0) {
181-
pbn.Links = []
182-
183-
for (var i = 0; i < node.links.length; i++) {
184-
var link = node.links[i]
185-
pbn.Links.push({
186-
Hash: link.hash,
187-
Name: link.name,
188-
Tsize: link.size
189-
})
190-
}
191-
} else {
192-
pbn.Links = null
193-
}
194-
195-
return pbn
196-
}
197-
198-
this.toJSON = () => {
189+
toJSON () {
199190
return {
200191
Data: this.data,
201-
Links: this.links.map((l) => { return l.toJSON() }),
202-
Hash: bs58.encode(this.multihash()).toString(),
192+
Links: this.links.map((l) => l.toJSON()),
193+
Hash: mh.toB58String(this.multihash()),
203194
Size: this.size()
204195
}
205196
}
206-
}
207-
208-
// Link represents an IPFS Merkle DAG Link between Nodes.
209-
function DAGLink (name, size, hash) {
210-
this.name = name
211-
this.size = size
212-
this.hash = hash
213197

214-
this.toJSON = () => {
215-
return {
216-
Name: this.name,
217-
Size: this.size,
218-
Hash: bs58.encode(this.hash).toString()
219-
}
198+
toString () {
199+
const hash = mh.toB58String(this.multihash())
200+
return `DAGNode <${hash} - data: "${this.data.toString()}", links: ${this.links.length}, size: ${this.size()}>`
220201
}
221202
}

0 commit comments

Comments
 (0)