1
1
'use strict'
2
2
3
- const util = require ( './util' )
4
3
const protobuf = require ( 'protocol-buffers' )
5
4
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
+ }
7
17
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 = { }
9
21
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
+ }
11
39
12
- exports = module . exports = {
13
- DAGLink : DAGLink ,
14
- DAGNode : DAGNode
40
+ return pbn
15
41
}
16
42
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
20
47
21
- this . data = data
22
- this . links = links || [ ]
48
+ this . data = data
49
+ this . links = [ ]
23
50
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
+ }
26
65
}
27
66
28
67
// copy - returns a clone of the DAGNode
29
- this . copy = ( ) => {
30
- var clone = new DAGNode ( )
68
+ copy ( ) {
69
+ const clone = new DAGNode ( )
31
70
if ( this . data && this . data . length > 0 ) {
32
- var buf = new Buffer ( this . data . length )
71
+ const buf = new Buffer ( this . data . length )
33
72
this . data . copy ( buf )
34
73
clone . data = buf
35
74
}
36
75
37
76
if ( this . links . length > 0 ) {
38
- clone . links = links . slice ( )
77
+ clone . links = this . links . slice ( )
39
78
}
40
79
41
80
return clone
42
81
}
43
82
44
83
// addNodeLink - adds a DAGLink to this node that points to node by a name
45
- this . addNodeLink = ( name , node ) => {
84
+ addNodeLink ( name , node ) {
46
85
if ( typeof name !== 'string' ) {
47
86
return
48
87
}
49
- var link = this . makeLink ( node )
88
+ const link = this . makeLink ( node )
50
89
51
90
link . name = name
52
91
this . addRawLink ( link )
53
92
}
54
93
55
94
// addRawLink adds a Link to this node from a DAGLink
56
- this . addRawLink = ( link ) => {
57
- encoded = null
95
+ addRawLink ( link ) {
96
+ this . _encoded = null
58
97
this . links . push ( new DAGLink ( link . name , link . size , link . hash ) )
59
98
stable . inplace ( this . links , linkSort )
60
99
}
61
100
62
101
// UpdateNodeLink return a copy of the node with the link name set to point to
63
102
// that. If a link of the same name existed, it is replaced.
64
103
// 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 ( )
67
106
newnode . removeNodeLink ( name )
68
107
newnode . addNodeLink ( name , node )
69
108
return newnode
70
109
}
71
110
72
111
// 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
75
114
this . links = this . links . filter ( ( link ) => {
76
115
if ( link . name === name ) {
77
116
return false
@@ -80,9 +119,10 @@ function DAGNode (data, links) {
80
119
}
81
120
} )
82
121
}
122
+
83
123
// 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
86
126
this . links = this . links . filter ( ( link ) => {
87
127
if ( link . hash . equals ( multihash ) ) {
88
128
return false
@@ -92,130 +132,71 @@ function DAGNode (data, links) {
92
132
} )
93
133
}
94
134
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
-
107
135
// makeLink returns a DAGLink node from a DAGNode
108
136
// 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 ( ) )
113
139
}
114
140
115
141
// multihash - returns the multihash value of this DAGNode
116
- this . multihash = ( ) => {
142
+ multihash ( ) {
117
143
this . encoded ( )
118
- return cached
144
+ return this . _cached
119
145
}
120
146
121
147
// Size returns the total size of the data addressed by node,
122
148
// including the total sizes of references.
123
- this . size = ( ) => {
124
- var buf = this . encoded ( )
149
+ size ( ) {
150
+ const buf = this . encoded ( )
125
151
if ( ! buf ) {
126
152
return 0
127
153
}
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 )
133
156
}
134
157
135
158
// Encoded returns the encoded raw data version of a Node instance.
136
159
// 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 ( )
140
163
141
- if ( encoded ) {
142
- cached = util . hash ( encoded )
164
+ if ( this . _encoded ) {
165
+ this . _cached = util . hash ( this . _encoded )
143
166
}
144
167
}
145
- return encoded
168
+ return this . _encoded
146
169
}
147
170
148
171
// 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 ) )
153
174
}
154
175
155
176
// unMarshal - decodes a protobuf into a DAGNode
156
177
// 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
+
165
184
stable . inplace ( this . links , linkSort )
166
185
this . data = pbn . Data || new Buffer ( 0 )
167
186
return this
168
187
}
169
188
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 ( ) {
199
190
return {
200
191
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 ( ) ) ,
203
194
Size : this . size ( )
204
195
}
205
196
}
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
213
197
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 ( ) } >`
220
201
}
221
202
}
0 commit comments