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

Commit 4eb42f4

Browse files
committed
feat: track progress events
1 parent c749c36 commit 4eb42f4

File tree

6 files changed

+66
-19
lines changed

6 files changed

+66
-19
lines changed

examples/upload-file-via-browser/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"devDependencies": {
1414
"babel-core": "^5.4.7",
1515
"babel-loader": "^5.1.2",
16-
"ipfs-api": "^12.1.7",
16+
"ipfs-api": "../../",
1717
"json-loader": "^0.5.4",
1818
"react": "^15.4.2",
1919
"react-dom": "^15.4.2",

examples/upload-file-via-browser/src/App.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class App extends React.Component {
2929
saveToIpfs (reader) {
3030
let ipfsId
3131
const buffer = Buffer.from(reader.result)
32-
this.ipfsApi.add(buffer)
32+
this.ipfsApi.add(buffer, { progress: (prog) => console.log(`received: ${prog}`) })
3333
.then((response) => {
3434
console.log(response)
3535
ipfsId = response[0].hash

src/files/add.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const isStream = require('is-stream')
44
const promisify = require('promisify-es6')
55
const DAGNodeStream = require('../utils/dagnode-stream')
6+
const ProgressStream = require('../utils/progress-stream')
67

78
module.exports = (send) => {
89
return promisify((files, opts, callback) => {
@@ -14,8 +15,8 @@ module.exports = (send) => {
1415
opts = opts || {}
1516

1617
const ok = Buffer.isBuffer(files) ||
17-
isStream.readable(files) ||
18-
Array.isArray(files)
18+
isStream.readable(files) ||
19+
Array.isArray(files)
1920

2021
if (!ok) {
2122
return callback(new Error('"files" must be a buffer, readable stream, or array of objects'))
@@ -41,10 +42,12 @@ module.exports = (send) => {
4142
qs.hash = opts.hashAlg
4243
}
4344

44-
const request = { path: 'add', files: files, qs: opts, progress: opts.progress }
45+
const request = { path: 'add', files: files, qs: qs, progress: opts.progress }
4546

4647
// Transform the response stream to DAGNode values
47-
const transform = (res, callback) => DAGNodeStream.streamToValue(send, res, callback)
48+
const transform = (res, callback) => DAGNodeStream.streamToValue(send,
49+
ProgressStream.fromStream(opts.progress, res),
50+
callback)
4851
send.andTransform(request, transform, callback)
4952
})
5053
}

src/utils/progress-stream.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict'
2+
3+
const Transform = require('readable-stream').Transform
4+
5+
/*
6+
A transform stream to track progress events on file upload
7+
8+
When the progress flag is passed to the HTTP api, the stream
9+
emits progress events like such:
10+
11+
{
12+
Name string
13+
Hash string `json:",omitempty"`
14+
Bytes int64 `json:",omitempty"`
15+
Size string `json:",omitempty"`
16+
}
17+
18+
This class will take care of detecting such
19+
events and calling the associated track method
20+
with the bytes sent so far as parameter. It will
21+
also skip them from the stream, emitting only
22+
when the final object has been uploaded and we
23+
got a hash.
24+
*/
25+
class ProgressStream extends Transform {
26+
constructor (opts) {
27+
opts = Object.assign(opts || {}, { objectMode: true })
28+
super(opts)
29+
this._track = opts.track || (() => {})
30+
this._res = []
31+
}
32+
33+
static fromStream (track, stream) {
34+
const prog = new ProgressStream({ track })
35+
return stream.pipe(prog)
36+
}
37+
38+
_transform (chunk, encoding, callback) {
39+
if (chunk &&
40+
typeof chunk.Bytes !== 'undefined' &&
41+
typeof chunk.Hash === 'undefined') {
42+
this._track(chunk.Bytes)
43+
return callback()
44+
}
45+
46+
callback(null, chunk)
47+
}
48+
}
49+
50+
module.exports = ProgressStream

src/utils/request-api.js

+4-12
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const getFilesStream = require('./get-files-stream')
1010
const streamToValue = require('./stream-to-value')
1111
const streamToJsonValue = require('./stream-to-json-value')
1212
const request = require('./request')
13-
const Transform = require('readable-stream').Transform
1413

1514
// -- Internal
1615

@@ -82,6 +81,9 @@ function requestAPI (config, options, callback) {
8281
if (options.files && !Array.isArray(options.files)) {
8382
options.files = [options.files]
8483
}
84+
if (options.progress) {
85+
options.qs.progress = true
86+
}
8587

8688
if (options.qs.r) {
8789
options.qs.recursive = options.qs.r
@@ -161,17 +163,7 @@ function requestAPI (config, options, callback) {
161163
})
162164

163165
if (options.files) {
164-
if (options.progress && typeof options.progress === 'function') {
165-
const progressStream = new Transform({
166-
transform: (chunk, encoding, cb) => {
167-
options.progress(chunk.byteLength)
168-
cb(null, chunk)
169-
}
170-
})
171-
stream.pipe(progressStream).pipe(req)
172-
} else {
173-
stream.pipe(req)
174-
}
166+
stream.pipe(req)
175167
} else {
176168
req.end()
177169
}

test/files.spec.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,12 @@ describe('.files (the MFS API part)', function () {
107107
})
108108

109109
it.only('files.add with progress options', (done) => {
110-
ipfs.files.add(testfile, {progress: false}, (err, res) => {
110+
let progress = 0
111+
ipfs.files.add(testfile, { progress: (p) => { progress = p } }, (err, res) => {
111112
expect(err).to.not.exist()
112113

113114
expect(res).to.have.length(1)
115+
expect(progress).to.be.greaterThan(0)
114116
done()
115117
})
116118
})

0 commit comments

Comments
 (0)