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

Commit b064c80

Browse files
committed
migrate importer to async IPLD format interface
1 parent 9a28998 commit b064c80

13 files changed

+272
-192
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ IPFS unixFS Engine
2525
- [Contribute](#contribute)
2626
- [License](#license)
2727

28+
## BEWARE BEWARE BEWARE there might be 🐉
29+
30+
This module has passed through several iterations and still is far from a nice and easy understandable codebase. Currently missing features:
31+
32+
- tar importer
33+
- trickle dag exporter
34+
- sharding
35+
2836
## Install
2937

3038
With [npm](https://npmjs.org/) installed, run

package.json

+12-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "ipfs-unixfs-engine",
33
"version": "0.11.4",
44
"description": "JavaScript implementation of the unixfs Engine used by IPFS",
5-
"main": "src/index.js",
5+
"main": "lib/index.js",
66
"jsnext:main": "src/index.js",
77
"scripts": {
88
"lint": "aegir-lint",
@@ -34,31 +34,33 @@
3434
},
3535
"homepage": "https://github.com/ipfs/js-ipfs-unixfs-engineg#readme",
3636
"devDependencies": {
37-
"aegir": "^8.0.1",
37+
"aegir": "^8.1.2",
3838
"buffer-loader": "0.0.1",
3939
"chai": "^3.5.0",
40-
"fs-pull-blob-store": "^0.3.0",
40+
"fs-pull-blob-store": "^0.4.1",
4141
"idb-pull-blob-store": "^0.5.1",
42-
"ipfs-block-service": "^0.5.0",
43-
"ipfs-repo": "^0.9.0",
42+
"ipfs-block-service": "^0.6.0",
43+
"ipfs-repo": "^0.10.0",
4444
"ncp": "^2.0.0",
4545
"pre-commit": "^1.1.3",
46-
"pull-zip": "^2.0.0",
46+
"pull-zip": "^2.0.1",
4747
"raw-loader": "^0.5.1",
4848
"rimraf": "^2.5.4",
4949
"run-series": "^1.1.4"
5050
},
5151
"dependencies": {
52-
"ipld-dag-pb": "^0.0.1",
52+
"cids": "^0.2.0",
5353
"ipfs-unixfs": "^0.1.4",
54-
"is-ipfs": "^0.2.0",
54+
"ipld-dag-pb": "^0.1.3",
55+
"ipld-resolver": "^0.1.1",
56+
"is-ipfs": "^0.2.1",
5557
"multihashes": "^0.2.2",
5658
"pull-block": "^1.0.2",
57-
"pull-paramap": "^1.1.6",
59+
"pull-paramap": "^1.2.0",
5860
"pull-pushable": "^2.0.1",
5961
"pull-stream": "^3.4.5",
6062
"pull-traverse": "^1.0.3",
61-
"pull-write": "^1.1.0",
63+
"pull-write": "^1.1.1",
6264
"run-parallel": "^1.1.6"
6365
},
6466
"contributors": [

src/chunker-fixed-size.js

-7
This file was deleted.

src/chunker/fixed-size.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict'
2+
3+
const pullBlock = require('pull-block')
4+
5+
module.exports = (size) => {
6+
return pullBlock(size, { zeroPadding: false })
7+
}
File renamed without changes.
File renamed without changes.

src/exporter.js renamed to src/exporter/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ const traverse = require('pull-traverse')
44
const pull = require('pull-stream')
55
const CID = require('cids')
66

7-
const util = require('./util')
7+
const util = require('./../util')
88
const switchType = util.switchType
99
const cleanMultihash = util.cleanMultihash
1010

11-
const dirExporter = require('./exporters/dir')
12-
const fileExporter = require('./exporters/file')
11+
const dirExporter = require('./dir')
12+
const fileExporter = require('./file')
1313

1414
module.exports = (hash, ipldResolver, options) => {
1515
hash = cleanMultihash(hash)

src/importer/flush-tree.js

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
'use strict'
2+
3+
const mh = require('multihashes')
4+
const UnixFS = require('ipfs-unixfs')
5+
const CID = require('cids')
6+
const dagPB = require('ipld-dag-pb')
7+
const mapValues = require('async/mapValues')
8+
const parallel = require('async/parallel')
9+
10+
const DAGLink = dagPB.DAGLink
11+
const DAGNode = dagPB.DAGNode
12+
13+
module.exports = (files, ipldResolver, source, callback) => {
14+
// 1) convert files to a tree
15+
const fileTree = createTree(files)
16+
17+
if (Object.keys(fileTree).length === 0) {
18+
return callback()// no dirs to be created
19+
}
20+
21+
// 2) create sizeIndex
22+
const sizeIndex = createSizeIndex(files)
23+
24+
// 3) bottom up flushing
25+
traverse(fileTree, sizeIndex, null, ipldResolver, source, callback)
26+
}
27+
28+
/*
29+
* createTree
30+
*
31+
* received an array of files with the format:
32+
* {
33+
* path: // full path
34+
* multihash: // multihash of the dagNode
35+
* size: // cumulative size
36+
* }
37+
*
38+
* returns a JSON object that represents a tree where branches are the paths
39+
* and the leaves are objects with file names and respective multihashes, such
40+
* as:
41+
* {
42+
* foo: {
43+
* bar: {
44+
* baz.txt: <multihash>
45+
* }
46+
* }
47+
* }
48+
*/
49+
function createTree (files) {
50+
const fileTree = {}
51+
52+
files.forEach((file) => {
53+
let splitted = file.path.split('/')
54+
if (splitted.length === 1) {
55+
return // adding just one file
56+
}
57+
if (splitted[0] === '') {
58+
splitted = splitted.slice(1)
59+
}
60+
var tmpTree = fileTree
61+
62+
for (var i = 0; i < splitted.length; i++) {
63+
if (!tmpTree[splitted[i]]) {
64+
tmpTree[splitted[i]] = {}
65+
}
66+
if (i === splitted.length - 1) {
67+
tmpTree[splitted[i]] = file.multihash
68+
} else {
69+
tmpTree = tmpTree[splitted[i]]
70+
}
71+
}
72+
})
73+
74+
return fileTree
75+
}
76+
77+
/*
78+
* create a size index that goes like:
79+
* { <multihash>: <size> }
80+
*/
81+
function createSizeIndex (files) {
82+
const sizeIndex = {}
83+
84+
files.forEach((file) => {
85+
sizeIndex[mh.toB58String(file.multihash)] = file.size
86+
})
87+
88+
return sizeIndex
89+
}
90+
91+
/*
92+
* expand the branches recursively (depth first), flush them first
93+
* and then traverse through the bottoum up, flushing everynode
94+
*
95+
* Algorithm tl;dr;
96+
* create a dirNode
97+
* Object.keys
98+
* If the value is an Object
99+
* create a dir Node
100+
* Object.keys
101+
* Once finished, add the result as a link to the dir node
102+
* If the value is not an object
103+
* add as a link to the dirNode
104+
*/
105+
function traverse (tree, sizeIndex, path, ipldResolver, source, done) {
106+
mapValues(tree, (node, key, cb) => {
107+
if (isLeaf(node)) {
108+
return cb(null, node)
109+
}
110+
111+
traverse(node, sizeIndex, path ? `${path}/${key}` : key, ipldResolver, source, cb)
112+
}, (err, tree) => {
113+
if (err) {
114+
return done(err)
115+
}
116+
117+
// at this stage, all keys are multihashes
118+
// create a dir node
119+
// add all the multihashes as links
120+
// return this new node multihash
121+
122+
const keys = Object.keys(tree)
123+
124+
const ufsDir = new UnixFS('directory')
125+
const node = new DAGNode(ufsDir.marshal())
126+
127+
keys.forEach((key) => {
128+
const b58mh = mh.toB58String(tree[key])
129+
const link = new DAGLink(key, sizeIndex[b58mh], tree[key])
130+
node.addRawLink(link)
131+
})
132+
133+
parallel([
134+
(cb) => node.multihash(cb),
135+
(cb) => node.size(cb)
136+
], (err, res) => {
137+
if (err) {
138+
return done(err)
139+
}
140+
141+
const multihash = res[0]
142+
const size = res[1]
143+
144+
sizeIndex[mh.toB58String(multihash)] = size
145+
ipldResolver.put({
146+
node: node,
147+
cid: new CID(multihash)
148+
}, (err) => {
149+
if (err) {
150+
source.push(new Error('failed to store dirNode'))
151+
} else if (path) {
152+
source.push({
153+
path: path,
154+
multihash: multihash,
155+
size: size
156+
})
157+
}
158+
159+
done(null, multihash)
160+
})
161+
})
162+
})
163+
}
164+
165+
function isLeaf (value) {
166+
return !(typeof value === 'object' && !Buffer.isBuffer(value))
167+
}

0 commit comments

Comments
 (0)