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

Commit 71ce1d5

Browse files
committed
fix: emit compatible progress events
1 parent e3d1629 commit 71ce1d5

File tree

3 files changed

+50
-28
lines changed

3 files changed

+50
-28
lines changed

packages/ipfs-http-client/src/add-all.js

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = configure((api) => {
1616
// allow aborting requests on body errors
1717
const controller = new AbortController()
1818
const signal = anySignal([controller.signal, options.signal])
19-
const { headers, body, total, lengthComputable } =
19+
const { headers, body, total, parts } =
2020
await multipartRequest(source, controller, options.headers)
2121

2222
// In browser response body only starts streaming once upload is
@@ -25,7 +25,7 @@ module.exports = configure((api) => {
2525
// `{ total, loaded}` passed to `onUploadProgress` and `multipart.total`
2626
// in which case we disable progress updates to be written out.
2727
const [progressFn, onUploadProgress] = typeof options.progress === 'function'
28-
? createProgressHandler(lengthComputable, total, options.progress)
28+
? createProgressHandler(total, parts, options.progress)
2929
: [null, null]
3030

3131
const res = await api.post('add', {
@@ -58,27 +58,42 @@ module.exports = configure((api) => {
5858
* Returns simple progress callback when content length isn't computable or a
5959
* progress event handler that inerpolates progress from upload progress events.
6060
*
61-
* @param {boolean} lengthComputable
6261
* @param {number} total
63-
* @param {(n:number) => void} progress
62+
* @param {{name:string, start:number, end:number}[]|null} parts
63+
* @param {(n:number, name:string) => void} progress
6464
*/
65-
const createProgressHandler = (lengthComputable, total, progress) =>
66-
lengthComputable ? [null, createOnUploadPrgress(total, progress)] : [progress, null]
65+
const createProgressHandler = (total, parts, progress) =>
66+
parts ? [null, createOnUploadPrgress(total, parts, progress)] : [progress, null]
6767

6868
/**
6969
* Creates a progress handler that interpolates progress from upload progress
7070
* events and total size of the content that is added.
7171
*
7272
* @param {number} size - actual content size
73-
* @param {(n:number) => void} progress
74-
* @returns {(event:{total:number, loaded: number}) => progress}
75-
*/
76-
const createOnUploadPrgress = (size, progress) => ({ loaded, total }) =>
77-
progress(Math.floor(loaded / total * size))
78-
79-
/**
80-
* @typedef {import('../../ipfs/src/core/components/add-all').UnixFSEntry} UnixFSEntry
73+
* @param {{name:string, start:number, end:number}[]} parts
74+
* @param {(n:number, name:string) => void} progress
75+
* @returns {(event:{total:number, loaded: number}) => void}
8176
*/
77+
const createOnUploadPrgress = (size, parts, progress) => {
78+
let index = 0
79+
return ({ loaded, total }) => {
80+
// Derive position from the current progress.
81+
const position = Math.floor(loaded / total * size)
82+
while (true) {
83+
const { start, end, name } = parts[index]
84+
// If within current part range reporst progress and break the loop
85+
if (position < end) {
86+
progress(position - start, name)
87+
break
88+
// If passed current part range report final byte for the chunk and
89+
// move to next one.
90+
} else {
91+
progress(end - start, name)
92+
index += 1
93+
}
94+
}
95+
}
96+
}
8297

8398
/**
8499
* @param {any} input
@@ -108,7 +123,4 @@ function toCoreInterface ({ name, hash, size, mode, mtime, mtimeNsecs }) {
108123

109124
/**
110125
* @typedef {import('ipfs-core/src/components/add-all/index').UnixFSEntry} UnixFSEntry
111-
* @typedef {import('./index').HttpOptions} HttpOptions
112-
* @typedef {Object} HttpAddOptions
113-
* @property {}
114126
*/

packages/ipfs-http-client/src/lib/multipart-request.browser.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const mtimeToObject = require('./mtime-to-object')
88
const { File, FormData } = require('ipfs-utils/src/globalthis')
99

1010
async function multipartRequest (source = '', abortController, headers = {}) {
11+
const parts = []
1112
const formData = new FormData()
1213
let index = 0
1314
let total = 0
@@ -27,10 +28,9 @@ async function multipartRequest (source = '', abortController, headers = {}) {
2728
qs.push(`mode=${modeToString(mode)}`)
2829
}
2930

30-
if (mtime != null) {
31-
const {
32-
secs, nsecs
33-
} = mtimeToObject(mtime)
31+
const time = mtimeToObject(mtime)
32+
if (time != null) {
33+
const { secs, nsecs } = time
3434

3535
qs.push(`mtime=${secs}`)
3636

@@ -45,17 +45,20 @@ async function multipartRequest (source = '', abortController, headers = {}) {
4545

4646
if (content) {
4747
formData.set(fieldName, content, encodeURIComponent(path))
48-
total += content.size
48+
const end = total + content.size
49+
parts.push({ name: path, start: total, end })
50+
total = end
4951
} else {
5052
formData.set(fieldName, new File([''], encodeURIComponent(path), { type: 'application/x-directory' }))
53+
parts.push({ name: path, start: total, end: total })
5154
}
5255

5356
index++
5457
}
5558

5659
return {
57-
lengthComputable: true,
5860
total,
61+
parts,
5962
headers,
6063
body: formData
6164
}

packages/ipfs-http-client/src/lib/multipart-request.node.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ const mtimeToObject = require('./mtime-to-object')
77
const merge = require('merge-options').bind({ ignoreUndefined: true })
88
const toStream = require('it-to-stream')
99

10+
/**
11+
*
12+
* @param {Object} source
13+
* @param {AbortController} abortController
14+
* @param {Headers|Record<string, string>} [headers]
15+
* @param {string} [boundary]
16+
*/
1017
async function multipartRequest (source = '', abortController, headers = {}, boundary = `-----------------------------${nanoid()}`) {
1118
async function * streamFiles (source) {
1219
try {
@@ -29,10 +36,9 @@ async function multipartRequest (source = '', abortController, headers = {}, bou
2936
qs.push(`mode=${modeToString(mode)}`)
3037
}
3138

32-
if (mtime != null) {
33-
const {
34-
secs, nsecs
35-
} = mtimeToObject(mtime)
39+
const time = mtimeToObject(mtime)
40+
if (time != null) {
41+
const { secs, nsecs } = time
3642

3743
qs.push(`mtime=${secs}`)
3844

@@ -58,14 +64,15 @@ async function multipartRequest (source = '', abortController, headers = {}, bou
5864
}
5965
} catch (err) {
6066
// workaround for https://github.com/node-fetch/node-fetch/issues/753
67+
// @ts-ignore - abort does not expect an arguments
6168
abortController.abort(err)
6269
} finally {
6370
yield `\r\n--${boundary}--\r\n`
6471
}
6572
}
6673

6774
return {
68-
lengthComputable: false,
75+
parts: null,
6976
total: -1,
7077
headers: merge(headers, {
7178
'Content-Type': `multipart/form-data; boundary=${boundary}`

0 commit comments

Comments
 (0)