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

Commit 362c685

Browse files
committed
fix: return correct chunks of streams, fixes #229
1 parent 75b4291 commit 362c685

File tree

3 files changed

+92
-42
lines changed

3 files changed

+92
-42
lines changed

src/exporter/extract-data-from-block.js

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
'use strict'
22

3-
module.exports = function extractDataFromBlock (block, streamPosition, begin, end) {
3+
module.exports = function extractDataFromBlock (block, blockStart, requestedStart, requestedEnd) {
44
const blockLength = block.length
5+
const blockEnd = blockStart + blockLength
56

6-
if (begin >= streamPosition + blockLength) {
7-
// If begin is after the start of the block, return an empty block
8-
// This can happen when internal nodes contain data
7+
if (requestedStart >= blockEnd || requestedEnd < blockStart) {
8+
// If we are looking for a byte range that is starts after the start of the block,
9+
// return an empty block. This can happen when internal nodes contain data
910
return Buffer.alloc(0)
1011
}
1112

12-
if (end - streamPosition < blockLength) {
13+
if (requestedEnd >= blockStart && requestedEnd < blockEnd) {
1314
// If the end byte is in the current block, truncate the block to the end byte
14-
block = block.slice(0, end - streamPosition)
15+
block = block.slice(0, requestedEnd - blockStart)
1516
}
1617

17-
if (begin > streamPosition && begin < (streamPosition + blockLength)) {
18+
if (requestedStart >= blockStart && requestedStart < blockEnd) {
1819
// If the start byte is in the current block, skip to the start byte
19-
block = block.slice(begin - streamPosition)
20+
block = block.slice(requestedStart - blockStart)
2021
}
2122

2223
return block

src/exporter/file.js

+56-34
Original file line numberDiff line numberDiff line change
@@ -77,36 +77,25 @@ function streamBytes (dag, node, fileSize, offset, length) {
7777

7878
const end = offset + length
7979

80-
function getData ({ node, start }) {
81-
try {
82-
if (Buffer.isBuffer(node)) {
83-
// this is a raw node
84-
return extractDataFromBlock(node, start, offset, end)
85-
}
86-
87-
const file = UnixFS.unmarshal(node.data)
88-
89-
if (!file.data) {
90-
if (file.blockSizes.length) {
91-
return
92-
}
93-
94-
return Buffer.alloc(0)
95-
}
96-
97-
return extractDataFromBlock(file.data, start, offset, end)
98-
} catch (error) {
99-
throw new Error(`Failed to unmarshal node - ${error.message}`)
100-
}
101-
}
80+
return pull(
81+
traverse.depthFirst({
82+
node,
83+
start: 0,
84+
end: fileSize
85+
}, getChildren(dag, offset, end)),
86+
pull.map(extractData(offset, end)),
87+
pull.filter(Boolean)
88+
)
89+
}
10290

91+
function getChildren (dag, offset, end) {
10392
// as we step through the children, keep track of where we are in the stream
10493
// so we can filter out nodes we're not interested in
10594
let streamPosition = 0
10695

107-
function visitor ({ node }) {
96+
return function visitor ({ node }) {
10897
if (Buffer.isBuffer(node)) {
109-
// this is a raw node
98+
// this is a leaf node, can't traverse any further
11099
return pull.empty()
111100
}
112101

@@ -131,7 +120,8 @@ function streamBytes (dag, node, fileSize, offset, length) {
131120
const child = {
132121
link: link,
133122
start: streamPosition,
134-
end: streamPosition + file.blockSizes[index]
123+
end: streamPosition + file.blockSizes[index],
124+
size: file.blockSizes[index]
135125
}
136126

137127
streamPosition = child.end
@@ -161,14 +151,46 @@ function streamBytes (dag, node, fileSize, offset, length) {
161151
})
162152
)
163153
}
154+
}
164155

165-
return pull(
166-
traverse.depthFirst({
167-
node,
168-
start: 0,
169-
end: fileSize
170-
}, visitor),
171-
pull.map(getData),
172-
pull.filter(Boolean)
173-
)
156+
function extractData (requestedStart, requestedEnd) {
157+
let streamPosition = -1
158+
159+
return function getData ({ node, start, end }) {
160+
let block
161+
162+
if (Buffer.isBuffer(node)) {
163+
block = node
164+
} else {
165+
try {
166+
const file = UnixFS.unmarshal(node.data)
167+
168+
if (!file.data) {
169+
if (file.blockSizes.length) {
170+
return
171+
}
172+
173+
return Buffer.alloc(0)
174+
}
175+
176+
block = file.data
177+
} catch (error) {
178+
throw new Error(`Failed to unmarshal node - ${error.message}`)
179+
}
180+
}
181+
182+
if (block && block.length) {
183+
if (streamPosition === -1) {
184+
streamPosition = start
185+
}
186+
187+
const output = extractDataFromBlock(block, streamPosition, requestedStart, requestedEnd)
188+
189+
streamPosition += block.length
190+
191+
return output
192+
}
193+
194+
return Buffer.alloc(0)
195+
}
174196
}

test/exporter.js

+27
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,33 @@ module.exports = (repo) => {
323323
)
324324
})
325325

326+
it('exports the right chunks of files when offsets are specified', function (done) {
327+
this.timeout(30 * 1000)
328+
const offset = 3
329+
const data = Buffer.alloc(300 * 1024)
330+
331+
addAndReadTestFile({
332+
file: data,
333+
offset: 0
334+
}, (err, fileWithNoOffset) => {
335+
expect(err).to.not.exist()
336+
337+
addAndReadTestFile({
338+
file: data,
339+
offset
340+
}, (err, fileWithOffset) => {
341+
expect(err).to.not.exist()
342+
343+
expect(fileWithNoOffset.length).to.equal(data.length)
344+
expect(fileWithNoOffset.length - fileWithOffset.length).to.equal(offset)
345+
expect(fileWithOffset.length).to.equal(data.length - offset)
346+
expect(fileWithNoOffset.length).to.equal(fileWithOffset.length + offset)
347+
348+
done()
349+
})
350+
})
351+
})
352+
326353
it('exports a zero length chunk of a large file', function (done) {
327354
this.timeout(30 * 1000)
328355

0 commit comments

Comments
 (0)