Skip to content
This repository was archived by the owner on Aug 12, 2020. It is now read-only.

Commit 31f5e00

Browse files
committed
new badass importer
1 parent 59cf00b commit 31f5e00

File tree

9 files changed

+873
-538
lines changed

9 files changed

+873
-538
lines changed

.gitignore

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
21
.DS_Store
3-
tests/repo-tests*
2+
test/repo-tests*
43

54
# Logs
65
logs
@@ -31,4 +30,4 @@ build/Release
3130
node_modules
3231

3332
dist
34-
lib
33+
lib

:w

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
'use strict'
2+
3+
const debug = require('debug')
4+
const log = debug('importer')
5+
log.err = debug('importer:error')
6+
const fsc = require('./chunker-fixed-size')
7+
const through2 = require('through2')
8+
const merkleDAG = require('ipfs-merkle-dag')
9+
const UnixFS = require('ipfs-unixfs')
10+
const EE2 = require('EventEmitter2').EventEmitter2
11+
const util = require('util')
12+
const bs58 = require('bs58')
13+
14+
exports = module.exports = Importer
15+
16+
const CHUNK_SIZE = 262144
17+
18+
util.inherits(Importer, EE2)
19+
20+
function Importer (dagService, options) {
21+
if (!(this instanceof Importer)) {
22+
return new Importer(dagService)
23+
}
24+
25+
if (!dagService) {
26+
return new Error('must specify a dagService')
27+
}
28+
29+
const files = []
30+
var counter = 0
31+
32+
this.add = (fl) => {
33+
counter++
34+
if (!fl.stream) {
35+
// 1. create the empty dir dag node
36+
// 2. write it to the dag store
37+
// 3. add to the files array {path: <>, hash: <>}
38+
// 4. emit the path + hash
39+
const d = new UnixFS('directory')
40+
const n = new merkleDAG.DAGNode()
41+
n.data = d.marshal()
42+
dagService.add(n, (err) => {
43+
if (err) {
44+
return this.emit('err', 'Failed to store' + fl.path)
45+
}
46+
const el = {
47+
path: fl.path,
48+
multihash: n.multihash(),
49+
size: n.size(),
50+
dataSize: d.fileSize()
51+
}
52+
53+
files.push(el)
54+
this.emit('file', el)
55+
})
56+
return
57+
}
58+
59+
const leaves = []
60+
61+
fl.stream
62+
.pipe(fsc(CHUNK_SIZE))
63+
.pipe(through2((chunk, enc, cb) => {
64+
// 1. create the unixfs merkledag node
65+
// 2. add its hash and size to the leafs array
66+
67+
// TODO - Support really large files
68+
// a) check if we already reach max chunks if yes
69+
// a.1) create a parent node for all of the current leaves
70+
// b.2) clean up the leaves array and add just the parent node
71+
72+
const l = new UnixFS('file', chunk)
73+
const n = new merkleDAG.DAGNode(l.marshal())
74+
75+
dagService.add(n, function (err) {
76+
if (err) {
77+
return this.emit('err', 'Failed to store chunk of' + fl.path)
78+
}
79+
80+
leaves.push({
81+
Hash: n.multihash(),
82+
Size: n.size(),
83+
leafSize: l.fileSize(),
84+
Name: ''
85+
})
86+
87+
cb()
88+
})
89+
}, (cb) => {
90+
if (leaves.length === 1) {
91+
// 1. add to the files array {path: <>, hash: <>}
92+
// 2. emit the path + hash
93+
94+
const el = {
95+
path: fl.path,
96+
multihash: leaves[0].Hash,
97+
size: leaves[0].Size,
98+
dataSize: leaves[0].leafSize
99+
}
100+
101+
files.push(el)
102+
this.emit('file', el)
103+
return done(cb)
104+
}
105+
// 1. create a parent node and add all the leafs
106+
// 2. add to the files array {path: <>, hash: <>}
107+
// 3. emit the path + hash of the parent node
108+
109+
const f = new UnixFS('file')
110+
const n = new merkleDAG.DAGNode()
111+
112+
leaves.forEach((leaf) => {
113+
f.addBlockSize(leaf.leafSize)
114+
const l = new merkleDAG.DAGLink(leaf.Name, leaf.Size, leaf.Hash)
115+
n.addRawLink(l)
116+
})
117+
118+
n.data = f.marshal()
119+
dagService.add(n, (err) => {
120+
if (err) {
121+
this.emit('err', 'Failed to store' + fl.path)
122+
return cb()
123+
}
124+
125+
const el = {
126+
path: fl.path,
127+
multihash: n.multihash(),
128+
size: n.size(),
129+
dataSize: f.fileSize()
130+
}
131+
132+
files.push(el)
133+
this.emit('file', el)
134+
return done(cb)
135+
})
136+
}))
137+
function done (cb) {
138+
counter--
139+
cb()
140+
}
141+
}
142+
143+
this.finish = () => {
144+
// TODO
145+
// 1) convert files to a tree
146+
// 2)
147+
// 3) traverse the tree (by expanding on leaves recursively) and replacing the leafs by the hashes of their dirs
148+
149+
// if (files.length === 1) {
150+
// // The file was already emitted, nothing to do here
151+
// return
152+
// }
153+
154+
if (counter > 0) {
155+
return setTimeout(this.finish, 200)
156+
}
157+
158+
// file struct
159+
// {
160+
// path: // full path
161+
// multihash: // multihash of the dagNode
162+
// size: // cumulative size
163+
// dataSize: // dagNode size
164+
// }
165+
166+
// 1) convert files to a tree
167+
// for each path, split, add to a json tree and in the end the name of the
168+
// file points to an object that is has a key multihash and respective value
169+
// { foo: { bar: { baz.txt: <multihash> }}}
170+
// the stop condition is if the value is not an object
171+
const fileTree = {}
172+
173+
files.forEach((file) => {
174+
let splitted = file.path.split('/')
175+
if (splitted.length === 1) {
176+
return // adding just one file
177+
// fileTree[file.path] = bs58.encode(file.multihash).toString()
178+
}
179+
splitted = splitted.slice(1)
180+
var tmpTree = fileTree
181+
182+
for (var i = 0; i < splitted.length; i++) {
183+
if (!tmpTree[splitted[i]]) {
184+
tmpTree[splitted[i]] = {}
185+
}
186+
tmpTree = tmpTree[splitted[i]]
187+
}
188+
189+
tmpTree = file.multihash
190+
})
191+
192+
if (Object.keys(fileTree).length === 0) {
193+
// no dirs to be created
194+
return
195+
}
196+
197+
console.log('-> fileTree:', fileTree)
198+
199+
// 2) create a index for multihash: { size, dataSize } so
200+
// that we can fetch these when creating the merkle dag nodes
201+
202+
const mhIndex = {}
203+
204+
files.forEach((file) => {
205+
mhIndex[bs58.encode(file.multihash)] = {
206+
size: file.size,
207+
dataSize: file.dataSize
208+
}
209+
})
210+
211+
// 3) expand leaves recursively
212+
// create a dirNode
213+
// Object.keys
214+
// If the value is an Object
215+
// create a dir Node
216+
// Object.keys
217+
// Once finished, add the result as a link to the dir node
218+
// If the value is not an object
219+
// add as a link to the dirNode
220+
221+
function traverse (tree) {
222+
const keys = Object.keys(tmpTree)
223+
let tmpTree = tree
224+
keys.map((key) => {
225+
if (typeof tmpTree[key] === 'object') {
226+
tmpTree[key] = traverse(tmpTree[key]).bind(this)
227+
}
228+
})
229+
230+
// at this stage, all keys are multihashes
231+
// create a dir node
232+
// add all the multihashes as links
233+
// return this new node multihash
234+
235+
const d = new UnixFS('directory')
236+
const n = new merkleDAG.DAGNode()
237+
238+
keys.forEach((key) => {
239+
const b58mh = bs58.encode(tmpTree[key])
240+
const l = new merkleDAG.DAGLink(
241+
key, mhIndex[b58mh].size, tmpTree[key])
242+
n.addRawLink(l)
243+
})
244+
245+
n.data = d.marshal()
246+
dagService.add(n, (err) => {
247+
if (err) {
248+
this.emit('err', 'failed to store dirNode')
249+
}
250+
})
251+
252+
const el = {
253+
path: 'fill this in',
254+
multihash: n.multihash(),
255+
size: n.size(),
256+
dataSize: '' // f.fileSize()
257+
}
258+
259+
this.emit('file', el)
260+
return n.multihash()
261+
}
262+
263+
/* const rootHash = */ traverse(fileTree).bind(this)
264+
265+
// TODO
266+
// Since we never shoot for adding multiple directions at the root level, the following might not be necessary, reserving it for later:
267+
//
268+
// if at the first level, there was only one key (most cases)
269+
// do nothing, if there was many, emit a rootHash with '/'
270+
// emit root hash as well (as '/')
271+
}
272+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"async": "^1.5.2",
5656
"block-stream2": "^1.1.0",
5757
"debug": "^2.2.0",
58+
"eventemitter2": "^1.0.0",
5859
"ipfs-blocks": "^0.2.0",
5960
"ipfs-merkle-dag": "^0.4.0",
6061
"ipfs-unixfs": "^0.1.0",
@@ -68,4 +69,4 @@
6869
"greenkeeperio-bot <[email protected]>",
6970
"nginnever <[email protected]>"
7071
]
71-
}
72+
}

0 commit comments

Comments
 (0)