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

Commit bbb403c

Browse files
committed
chore: handle graphs with data on internal and leaf nodes
1 parent e0d0beb commit bbb403c

File tree

2 files changed

+113
-7
lines changed

2 files changed

+113
-7
lines changed

src/exporter/file.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ function streamBytes (dag, node, fileSize, offset, length) {
6060
}
6161

6262
const end = offset + length
63-
let streamPosition = 0
6463

6564
function getData ({ node, start }) {
6665
try {
@@ -70,18 +69,24 @@ function streamBytes (dag, node, fileSize, offset, length) {
7069
return Buffer.alloc(0)
7170
}
7271

73-
const block = extractDataFromBlock(file.data, start, offset, end)
74-
75-
streamPosition += block.length
76-
77-
return block
72+
return extractDataFromBlock(file.data, start, offset, end)
7873
} catch (error) {
7974
throw new Error(`Failed to unmarshal node - ${error.message}`)
8075
}
8176
}
8277

78+
// as we step through the children, keep track of where we are in the stream
79+
// so we can filter out nodes we're not interested in
80+
let streamPosition = 0
81+
8382
function visitor ({ node }) {
8483
const file = UnixFS.unmarshal(node.data)
84+
const nodeHasData = Boolean(file.data && file.data.length)
85+
86+
// handle case where data is present on leaf nodes and internal nodes
87+
if (nodeHasData && node.links.length) {
88+
streamPosition += file.data.length
89+
}
8590

8691
// work out which child nodes contain the requested data
8792
const filteredLinks = node.links
@@ -96,7 +101,7 @@ function streamBytes (dag, node, fileSize, offset, length) {
96101

97102
return child
98103
})
99-
.filter((child, index) => {
104+
.filter((child) => {
100105
return (offset >= child.start && offset < child.end) || // child has offset byte
101106
(end > child.start && end <= child.end) || // child has end byte
102107
(offset < child.start && end > child.end) // child is between offset and end bytes

test/exporter.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ const CID = require('cids')
1414
const loadFixture = require('aegir/fixtures')
1515
const doUntil = require('async/doUntil')
1616
const waterfall = require('async/waterfall')
17+
const parallel = require('async/parallel')
1718
const series = require('async/series')
1819
const fs = require('fs')
1920
const path = require('path')
2021
const push = require('pull-pushable')
2122
const toPull = require('stream-to-pull-stream')
2223
const toStream = require('pull-stream-to-stream')
24+
const {
25+
DAGNode,
26+
DAGLink
27+
} = require('ipld-dag-pb')
2328

2429
const unixFSEngine = require('./../src')
2530
const exporter = unixFSEngine.exporter
@@ -635,6 +640,79 @@ module.exports = (repo) => {
635640
})
636641
)
637642
})
643+
644+
it('exports file with data on internal and leaf nodes', function (done) {
645+
waterfall([
646+
(cb) => createAndPersistNode(ipld, 'raw', [0x04, 0x05, 0x06, 0x07], [], cb),
647+
(leaf, cb) => createAndPersistNode(ipld, 'file', [0x00, 0x01, 0x02, 0x03], [
648+
leaf
649+
], cb),
650+
(file, cb) => {
651+
pull(
652+
exporter(file.multihash, ipld),
653+
pull.asyncMap((file, cb) => readFile(file, cb)),
654+
pull.through(buffer => {
655+
expect(buffer).to.deep.equal(Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]))
656+
}),
657+
pull.collect(cb)
658+
)
659+
}
660+
], done)
661+
})
662+
663+
it('exports file with data on some internal and leaf nodes', function (done) {
664+
// create a file node with three children:
665+
// where:
666+
// i = internal node without data
667+
// d = internal node with data
668+
// l = leaf node with data
669+
// i
670+
// / | \
671+
// l d i
672+
// | \
673+
// l l
674+
waterfall([
675+
(cb) => {
676+
// create leaves
677+
parallel([
678+
(next) => createAndPersistNode(ipld, 'raw', [0x00, 0x01, 0x02, 0x03], [], next),
679+
(next) => createAndPersistNode(ipld, 'raw', [0x08, 0x09, 0x10, 0x11], [], next),
680+
(next) => createAndPersistNode(ipld, 'raw', [0x12, 0x13, 0x14, 0x15], [], next)
681+
], cb)
682+
},
683+
(leaves, cb) => {
684+
parallel([
685+
(next) => createAndPersistNode(ipld, 'raw', [0x04, 0x05, 0x06, 0x07], [leaves[1]], next),
686+
(next) => createAndPersistNode(ipld, 'raw', null, [leaves[2]], next)
687+
], (error, internalNodes) => {
688+
if (error) {
689+
return cb(error)
690+
}
691+
692+
createAndPersistNode(ipld, 'file', null, [
693+
leaves[0],
694+
internalNodes[0],
695+
internalNodes[1]
696+
], cb)
697+
})
698+
},
699+
(file, cb) => {
700+
pull(
701+
exporter(file.multihash, ipld),
702+
pull.asyncMap((file, cb) => readFile(file, cb)),
703+
pull.through(buffer => {
704+
expect(buffer).to.deep.equal(
705+
Buffer.from([
706+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
707+
0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
708+
])
709+
)
710+
}),
711+
pull.collect(cb)
712+
)
713+
}
714+
], done)
715+
})
638716
})
639717
}
640718

@@ -670,3 +748,26 @@ function readFile (file, done) {
670748
})
671749
)
672750
}
751+
752+
function createAndPersistNode (ipld, type, data, children, callback) {
753+
const file = new UnixFS(type, data ? Buffer.from(data) : undefined)
754+
const links = []
755+
756+
children.forEach(child => {
757+
const leaf = UnixFS.unmarshal(child.data)
758+
759+
file.addBlockSize(leaf.fileSize())
760+
761+
links.push(new DAGLink('', child.size, child.multihash))
762+
})
763+
764+
DAGNode.create(file.marshal(), links, (error, node) => {
765+
if (error) {
766+
return callback(error)
767+
}
768+
769+
ipld.put(node, {
770+
cid: new CID(node.multihash)
771+
}, (error) => callback(error, node))
772+
})
773+
}

0 commit comments

Comments
 (0)