From 1ee486483cf070edd9910b3ff5cfaa9d5b516eaa Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Thu, 1 Oct 2020 09:42:23 -0700 Subject: [PATCH 01/19] feat: integrate htttp-client progress reporting --- docs/core-api/FILES.md | 4 ++-- packages/interface-ipfs-core/package.json | 2 +- packages/interface-ipfs-core/src/add.js | 4 ++-- packages/ipfs-core-utils/package.json | 2 +- packages/ipfs-http-client/package.json | 2 +- packages/ipfs-http-client/src/add-all.js | 20 +++++++++++++++----- packages/ipfs/package.json | 2 +- 7 files changed, 23 insertions(+), 13 deletions(-) diff --git a/docs/core-api/FILES.md b/docs/core-api/FILES.md index 5898c9aba2..b2e755e989 100644 --- a/docs/core-api/FILES.md +++ b/docs/core-api/FILES.md @@ -167,7 +167,7 @@ An optional object which may have the following keys: | hashAlg | `String` | `'sha2-256'` | multihash hashing algorithm to use | | onlyHash | `boolean` | `false` | If true, will not add blocks to the blockstore | | pin | `boolean` | `true` | pin this object when adding | -| progress | function | `undefined` | a function that will be called with the byte length of chunks as a file is added to ipfs | +| progress | function | `undefined` | a function that will be called with the byte length of chunks as a file is added to ipfs (Please note that for http client it would include bytes for all of the request body not just file(s) content) | | rawLeaves | `boolean` | `false` | if true, DAG leaves will contain raw file data and not be wrapped in a protobuf | | trickle | `boolean` | `false` | if true will use the [trickle DAG](https://godoc.org/github.com/ipsn/go-ipfs/gxlibs/github.com/ipfs/go-unixfs/importer/trickle) format for DAG generation | | wrapWithDirectory | `boolean` | `false` | Adds a wrapping node around the content | @@ -248,7 +248,7 @@ An optional object which may have the following keys: | hashAlg | `String` | `'sha2-256'` | multihash hashing algorithm to use | | onlyHash | `boolean` | `false` | If true, will not add blocks to the blockstore | | pin | `boolean` | `true` | pin this object when adding | -| progress | function | `undefined` | a function that will be called with the byte length of chunks as a file is added to ipfs | +| progress | function | `undefined` | a function that will be called with the byte length of chunks as a file is added to ipfs (Please note that for http client it would include bytes for all of the request body not just file(s) content) | | rawLeaves | `boolean` | `false` | if true, DAG leaves will contain raw file data and not be wrapped in a protobuf | | shardSplitThreshold | `Number` | `1000` | Directories with more than this number of files will be created as HAMT-sharded directories | | trickle | `boolean` | `false` | if true will use the [trickle DAG](https://godoc.org/github.com/ipsn/go-ipfs/gxlibs/github.com/ipfs/go-unixfs/importer/trickle) format for DAG generation | diff --git a/packages/interface-ipfs-core/package.json b/packages/interface-ipfs-core/package.json index c60420883c..e56eee7a87 100644 --- a/packages/interface-ipfs-core/package.json +++ b/packages/interface-ipfs-core/package.json @@ -40,7 +40,7 @@ "dirty-chai": "^2.0.1", "ipfs-unixfs": "^2.0.2", "ipfs-unixfs-importer": "^3.0.2", - "ipfs-utils": "^3.0.0", + "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", "ipld-block": "^0.10.0", "ipld-dag-cbor": "^0.17.0", "ipld-dag-pb": "^0.20.0", diff --git a/packages/interface-ipfs-core/src/add.js b/packages/interface-ipfs-core/src/add.js index 7724a22e40..3eefb61182 100644 --- a/packages/interface-ipfs-core/src/add.js +++ b/packages/interface-ipfs-core/src/add.js @@ -110,7 +110,7 @@ module.exports = (common, options) => { expect(file.cid.toString()).to.equal(fixtures.bigFile.cid) expect(file.path).to.equal(fixtures.bigFile.cid) expect(progCalled).to.be.true() - expect(accumProgress).to.equal(fixtures.bigFile.data.length) + expect(accumProgress).to.greaterThan(fixtures.bigFile.data.length) }) it('should add an empty file with progress enabled', async () => { @@ -126,7 +126,7 @@ module.exports = (common, options) => { expect(file.cid.toString()).to.equal(fixtures.emptyFile.cid) expect(file.path).to.equal(fixtures.emptyFile.cid) expect(progCalled).to.be.true() - expect(accumProgress).to.equal(fixtures.emptyFile.data.length) + expect(accumProgress).to.greaterThan(fixtures.emptyFile.data.length) }) it('should add an empty file without progress enabled', async () => { diff --git a/packages/ipfs-core-utils/package.json b/packages/ipfs-core-utils/package.json index 03f3f5f3e9..d9894b39f7 100644 --- a/packages/ipfs-core-utils/package.json +++ b/packages/ipfs-core-utils/package.json @@ -32,7 +32,7 @@ "browser-readablestream-to-it": "0.0.2", "cids": "^1.0.0", "err-code": "^2.0.0", - "ipfs-utils": "^3.0.0", + "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", "it-all": "^1.0.1", "it-map": "^1.0.2", "it-peekable": "0.0.1", diff --git a/packages/ipfs-http-client/package.json b/packages/ipfs-http-client/package.json index 0a8cc1d4d5..4210c48d9e 100644 --- a/packages/ipfs-http-client/package.json +++ b/packages/ipfs-http-client/package.json @@ -47,7 +47,7 @@ "debug": "^4.1.0", "form-data": "^3.0.0", "ipfs-core-utils": "^0.4.0", - "ipfs-utils": "^3.0.0", + "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", "ipld-block": "^0.10.0", "ipld-dag-cbor": "^0.17.0", "ipld-dag-pb": "^0.20.0", diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index b110010d44..284d89b986 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -11,10 +11,13 @@ const AbortController = require('abort-controller').default module.exports = configure((api) => { // eslint-disable-next-line valid-jsdoc /** - * @type {import('../../ipfs/src/core/components/add-all').AddAll} + * @type {import('../../ipfs/src/core/components/add-all').AddAll<>} */ async function * addAll (input, options = {}) { - const progressFn = options.progress + const onUploadProgress = typeof options.progress === 'function' + ? ({loaded}) => options.progress(loaded) + : null + // allow aborting requests on body errors const controller = new AbortController() @@ -24,9 +27,12 @@ module.exports = configure((api) => { searchParams: toUrlSearchParams({ 'stream-channels': true, ...options, - progress: Boolean(progressFn) + // We use `onUploadProgress` instead because in browser response won't + // stream until body is uploaded, at which point it's usless. + progress: false }), timeout: options.timeout, + onUploadProgress, signal, ...( await multipartRequest(input, controller, options.headers) @@ -38,8 +44,6 @@ module.exports = configure((api) => { if (file.hash !== undefined) { yield toCoreInterface(file) - } else if (progressFn) { - progressFn(file.bytes || 0) } } } @@ -74,3 +78,9 @@ function toCoreInterface ({ name, hash, size, mode, mtime, mtimeNsecs }) { // @ts-ignore return output } + +/** + * @typedef {import('./index').HttpOptions} HttpOptions + * @typedef {Object} HttpAddOptions + * @property {} + */ diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json index c2f1b1792f..6c0eda3e92 100644 --- a/packages/ipfs/package.json +++ b/packages/ipfs/package.json @@ -99,7 +99,7 @@ "ipfs-unixfs": "^2.0.2", "ipfs-unixfs-exporter": "^3.0.2", "ipfs-unixfs-importer": "^3.0.2", - "ipfs-utils": "^3.0.0", + "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", "ipld": "^0.27.1", "ipld-bitcoin": "^0.4.0", "ipld-block": "^0.10.0", From 8d3421ff488bc856f0b526600e312421f5277af7 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Thu, 1 Oct 2020 17:08:03 -0700 Subject: [PATCH 02/19] fix: lint errors --- packages/ipfs-http-client/src/add-all.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index 284d89b986..9548dba66f 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -15,9 +15,8 @@ module.exports = configure((api) => { */ async function * addAll (input, options = {}) { const onUploadProgress = typeof options.progress === 'function' - ? ({loaded}) => options.progress(loaded) + ? ({ loaded }) => options.progress(loaded) : null - // allow aborting requests on body errors const controller = new AbortController() From dd3a2e7fe73a15cd8babf0936a66a17a2437f7bf Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Thu, 1 Oct 2020 23:59:56 -0700 Subject: [PATCH 03/19] fix: broken test in some runtimse --- packages/interface-ipfs-core/src/add.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/interface-ipfs-core/src/add.js b/packages/interface-ipfs-core/src/add.js index 028bcc4e82..a6fb376fb9 100644 --- a/packages/interface-ipfs-core/src/add.js +++ b/packages/interface-ipfs-core/src/add.js @@ -111,7 +111,7 @@ module.exports = (common, options) => { expect(file.cid.toString()).to.equal(fixtures.bigFile.cid) expect(file.path).to.equal(fixtures.bigFile.cid) expect(progCalled).to.be.true() - expect(accumProgress).to.greaterThan(fixtures.bigFile.data.length) + expect(accumProgress).to.be.at.least(fixtures.bigFile.data.length) }) it('should add an empty file with progress enabled', async () => { @@ -127,7 +127,7 @@ module.exports = (common, options) => { expect(file.cid.toString()).to.equal(fixtures.emptyFile.cid) expect(file.path).to.equal(fixtures.emptyFile.cid) expect(progCalled).to.be.true() - expect(accumProgress).to.greaterThan(fixtures.emptyFile.data.length) + expect(accumProgress).to.be.at.least(fixtures.emptyFile.data.length) }) it('should add an empty file without progress enabled', async () => { From bedb3591fdb491d2863281f40912d329765294fb Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Mon, 5 Oct 2020 08:58:06 -0700 Subject: [PATCH 04/19] chore: bump go-ipfs dep --- examples/browser-ipns-publish/package.json | 2 +- examples/http-client-browser-pubsub/package.json | 2 +- examples/http-client-name-api/package.json | 2 +- packages/ipfs-http-client/package.json | 2 +- packages/ipfs/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/browser-ipns-publish/package.json b/examples/browser-ipns-publish/package.json index 2fcf55a1dc..4f658740e2 100644 --- a/examples/browser-ipns-publish/package.json +++ b/examples/browser-ipns-publish/package.json @@ -28,7 +28,7 @@ "delay": "^4.4.0", "execa": "^4.0.0", "ipfsd-ctl": "^7.0.0", - "go-ipfs": "^0.6.0", + "go-ipfs": "^0.7.0", "parcel-bundler": "^1.12.4", "path": "^0.12.7", "test-ipfs-example": "^2.0.3" diff --git a/examples/http-client-browser-pubsub/package.json b/examples/http-client-browser-pubsub/package.json index c309ad0f83..bfce5cd871 100644 --- a/examples/http-client-browser-pubsub/package.json +++ b/examples/http-client-browser-pubsub/package.json @@ -19,7 +19,7 @@ ], "devDependencies": { "execa": "^4.0.0", - "go-ipfs": "^0.6.0", + "go-ipfs": "^0.7.0", "ipfs": "^0.50.1", "ipfsd-ctl": "^7.0.0", "parcel-bundler": "^1.12.4", diff --git a/examples/http-client-name-api/package.json b/examples/http-client-name-api/package.json index 923408256f..d91522926a 100644 --- a/examples/http-client-name-api/package.json +++ b/examples/http-client-name-api/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "execa": "^4.0.0", - "go-ipfs": "^0.6.0", + "go-ipfs": "^0.7.0", "ipfsd-ctl": "^7.0.0", "parcel-bundler": "^1.12.4", "test-ipfs-example": "^2.0.3" diff --git a/packages/ipfs-http-client/package.json b/packages/ipfs-http-client/package.json index 46d5de6638..ddcd12d9ec 100644 --- a/packages/ipfs-http-client/package.json +++ b/packages/ipfs-http-client/package.json @@ -73,7 +73,7 @@ "devDependencies": { "aegir": "^26.0.0", "cross-env": "^7.0.0", - "go-ipfs": "^0.6.0", + "go-ipfs": "^0.7.0", "interface-ipfs-core": "^0.140.0", "ipfsd-ctl": "^7.0.0", "it-all": "^1.0.4", diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json index 16ad82b950..20f1dbf5b6 100644 --- a/packages/ipfs/package.json +++ b/packages/ipfs/package.json @@ -48,7 +48,7 @@ "cross-env": "^7.0.0", "delay": "^4.4.0", "form-data": "^3.0.0", - "go-ipfs": "^0.6.0", + "go-ipfs": "^0.7.0", "interface-ipfs-core": "^0.140.0", "ipfs-http-client": "^47.0.1", "ipfs-interop": "^3.0.0", From 4918c0bd93e96304ea179ad41c8fb1d49ca93801 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 7 Oct 2020 12:32:25 -0700 Subject: [PATCH 05/19] feat: interpolate progress from upload progress --- examples/browser-ipns-publish/package.json | 2 +- packages/interface-ipfs-core/src/add.js | 8 +-- packages/ipfs-cli/package.json | 2 +- packages/ipfs-core/package.json | 2 +- packages/ipfs-http-client/src/add-all.js | 54 +++++++++++++++---- .../src/lib/multipart-request.browser.js | 4 ++ .../src/lib/multipart-request.js | 2 + 7 files changed, 57 insertions(+), 17 deletions(-) diff --git a/examples/browser-ipns-publish/package.json b/examples/browser-ipns-publish/package.json index 4f658740e2..f4b6b37b7b 100644 --- a/examples/browser-ipns-publish/package.json +++ b/examples/browser-ipns-publish/package.json @@ -15,7 +15,7 @@ "human-crypto-keys": "^0.1.4", "ipfs": "^0.50.1", "ipfs-http-client": "^47.0.0", - "ipfs-utils": "^3.0.0", + "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", "ipns": "^0.8.0", "it-last": "^1.0.4", "p-retry": "^4.2.0", diff --git a/packages/interface-ipfs-core/src/add.js b/packages/interface-ipfs-core/src/add.js index a6fb376fb9..461131b52e 100644 --- a/packages/interface-ipfs-core/src/add.js +++ b/packages/interface-ipfs-core/src/add.js @@ -103,7 +103,7 @@ module.exports = (common, options) => { let accumProgress = 0 function handler (p) { progCalled = true - accumProgress = p + accumProgress += p } const file = await ipfs.add(fixtures.bigFile.data, { progress: handler }) @@ -111,7 +111,7 @@ module.exports = (common, options) => { expect(file.cid.toString()).to.equal(fixtures.bigFile.cid) expect(file.path).to.equal(fixtures.bigFile.cid) expect(progCalled).to.be.true() - expect(accumProgress).to.be.at.least(fixtures.bigFile.data.length) + expect(accumProgress).to.equal(fixtures.bigFile.data.length) }) it('should add an empty file with progress enabled', async () => { @@ -119,7 +119,7 @@ module.exports = (common, options) => { let accumProgress = 0 function handler (p) { progCalled = true - accumProgress = p + accumProgress += p } const file = await ipfs.add(fixtures.emptyFile.data, { progress: handler }) @@ -127,7 +127,7 @@ module.exports = (common, options) => { expect(file.cid.toString()).to.equal(fixtures.emptyFile.cid) expect(file.path).to.equal(fixtures.emptyFile.cid) expect(progCalled).to.be.true() - expect(accumProgress).to.be.at.least(fixtures.emptyFile.data.length) + expect(accumProgress).to.equal(fixtures.emptyFile.data.length) }) it('should add an empty file without progress enabled', async () => { diff --git a/packages/ipfs-cli/package.json b/packages/ipfs-cli/package.json index 2069dc6cc6..3b067172f5 100644 --- a/packages/ipfs-cli/package.json +++ b/packages/ipfs-cli/package.json @@ -44,7 +44,7 @@ "ipfs-http-gateway": "0.0.1", "ipfs-http-server": "0.0.1", "ipfs-repo": "^6.0.3", - "ipfs-utils": "^3.0.0", + "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", "ipld-dag-cbor": "^0.17.0", "ipld-dag-pb": "^0.20.0", "it-all": "^1.0.4", diff --git a/packages/ipfs-core/package.json b/packages/ipfs-core/package.json index 248379b7c5..d3031c3b51 100644 --- a/packages/ipfs-core/package.json +++ b/packages/ipfs-core/package.json @@ -69,7 +69,7 @@ "ipfs-unixfs": "^2.0.3", "ipfs-unixfs-exporter": "^3.0.4", "ipfs-unixfs-importer": "^3.0.4", - "ipfs-utils": "^3.0.0", + "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", "ipld": "^0.27.1", "ipld-bitcoin": "^0.4.0", "ipld-block": "^0.10.1", diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index a73cbf8750..aea3ab9be8 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -13,28 +13,32 @@ module.exports = configure((api) => { * @type {import('../../ipfs/src/core/components/add-all').AddAll<>} */ async function * addAll (input, options = {}) { - const onUploadProgress = typeof options.progress === 'function' - ? ({ loaded }) => options.progress(loaded) - : null - // allow aborting requests on body errors const controller = new AbortController() const signal = anySignal([controller.signal, options.signal]) + const { headers, body, total, lengthComputable } = + await multipartRequest(input, controller, options.headers) + + // In browser response body only starts streaming once upload is + // complete, at which point all the progress updates are invalid. If + // length of the content is computable we can interpla te progress from + // `{ total, loaded}` passed to `onUploadProgress` and `multipart.total` + // in which case we disable progress updates to be written out. + const [progressFn, onUploadProgress] = typeof options.progress === 'function' + ? createProgressHandler(lengthComputable, total, options.progress) + : [null, null] const res = await api.post('add', { searchParams: toUrlSearchParams({ 'stream-channels': true, ...options, - // We use `onUploadProgress` instead because in browser response won't - // stream until body is uploaded, at which point it's usless. - progress: false + progress: Boolean(progressFn) }), timeout: options.timeout, onUploadProgress, signal, - ...( - await multipartRequest(input, controller, options.headers) - ) + headers, + body }) for await (let file of res.ndjson()) { @@ -42,12 +46,42 @@ module.exports = configure((api) => { if (file.hash !== undefined) { yield toCoreInterface(file) + } else if (progressFn) { + progressFn(file.bytes || 0) } } } return addAll }) +/** + * Returns simple progress callback when content length isn't computable or a + * progress event handler that inerpolates progress from upload progress events. + * + * @param {boolean} lengthComputable + * @param {number} total + * @param {(n:number) => void} progress + */ +const createProgressHandler = (lengthComputable, total, progress) => + lengthComputable ? [null, createOnUploadPrgress(total, progress)] : [progress, null] + +/** + * Creates a progress handler that interpolates progress from upload progress + * events and total size of the content that is added. + * + * @param {number} size - actual content size + * @param {(n:number) => void} progress + * @returns {(event:{total:number, loaded: number}) => progress} + */ +const createOnUploadPrgress = (size, progress) => { + let uploaded = 0 + return ({ loaded, total }) => { + const currentUpload = Math.floor(loaded / total * size) + progress(currentUpload - uploaded) + uploaded = currentUpload + } +} + /** * @typedef {import('../../ipfs/src/core/components/add-all').UnixFSEntry} UnixFSEntry */ diff --git a/packages/ipfs-http-client/src/lib/multipart-request.browser.js b/packages/ipfs-http-client/src/lib/multipart-request.browser.js index 550c85ba30..f3ea7644f3 100644 --- a/packages/ipfs-http-client/src/lib/multipart-request.browser.js +++ b/packages/ipfs-http-client/src/lib/multipart-request.browser.js @@ -8,6 +8,7 @@ const { File, FormData } = require('ipfs-utils/src/globalthis') async function multipartRequest (source = '', abortController, headers = {}) { const formData = new FormData() let index = 0 + let total = 0 for await (const { content, path, mode, mtime } of normaliseInput(source)) { let fileSuffix = '' @@ -42,6 +43,7 @@ async function multipartRequest (source = '', abortController, headers = {}) { if (content) { formData.set(fieldName, content, encodeURIComponent(path)) + total += content.size } else { formData.set(fieldName, new File([''], encodeURIComponent(path), { type: 'application/x-directory' })) } @@ -50,6 +52,8 @@ async function multipartRequest (source = '', abortController, headers = {}) { } return { + lengthComputable: true, + total, headers, body: formData } diff --git a/packages/ipfs-http-client/src/lib/multipart-request.js b/packages/ipfs-http-client/src/lib/multipart-request.js index ba712e02ef..391e9ffb79 100644 --- a/packages/ipfs-http-client/src/lib/multipart-request.js +++ b/packages/ipfs-http-client/src/lib/multipart-request.js @@ -65,6 +65,8 @@ async function multipartRequest (source = '', abortController, headers = {}, bou } return { + lengthComputable: false, + total: -1, headers: merge(headers, { 'Content-Type': `multipart/form-data; boundary=${boundary}` }), From 4f0ea0bc1efc157c394ae40df60abef8b6556440 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 7 Oct 2020 13:50:57 -0700 Subject: [PATCH 06/19] chore: rever test changes --- packages/interface-ipfs-core/src/add.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/interface-ipfs-core/src/add.js b/packages/interface-ipfs-core/src/add.js index 461131b52e..2c9dc08f98 100644 --- a/packages/interface-ipfs-core/src/add.js +++ b/packages/interface-ipfs-core/src/add.js @@ -103,7 +103,7 @@ module.exports = (common, options) => { let accumProgress = 0 function handler (p) { progCalled = true - accumProgress += p + accumProgress = p } const file = await ipfs.add(fixtures.bigFile.data, { progress: handler }) @@ -119,7 +119,7 @@ module.exports = (common, options) => { let accumProgress = 0 function handler (p) { progCalled = true - accumProgress += p + accumProgress = p } const file = await ipfs.add(fixtures.emptyFile.data, { progress: handler }) From 4c89952a7d578d090dd0f9fad5aba1af6af5b9df Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 7 Oct 2020 13:52:20 -0700 Subject: [PATCH 07/19] fix: progress reporting to be accumlative --- packages/ipfs-http-client/src/add-all.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index aea3ab9be8..d3849b7c40 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -73,14 +73,8 @@ const createProgressHandler = (lengthComputable, total, progress) => * @param {(n:number) => void} progress * @returns {(event:{total:number, loaded: number}) => progress} */ -const createOnUploadPrgress = (size, progress) => { - let uploaded = 0 - return ({ loaded, total }) => { - const currentUpload = Math.floor(loaded / total * size) - progress(currentUpload - uploaded) - uploaded = currentUpload - } -} +const createOnUploadPrgress = (size, progress) => ({ loaded, total }) => + progress(Math.floor(loaded / total * size)) /** * @typedef {import('../../ipfs/src/core/components/add-all').UnixFSEntry} UnixFSEntry From 11c65d73d0b58fa77a2be6eaa0e87b424152d28b Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 7 Oct 2020 16:00:59 -0700 Subject: [PATCH 08/19] fix: use browser code paths in electron-renderrer --- .../normalise-input/normalise-content.js | 77 ++---------------- .../normalise-input/normalise-content.node.js | 74 +++++++++++++++++ .../src/lib/multipart-request.js | 80 ++----------------- .../src/lib/multipart-request.node.js | 77 ++++++++++++++++++ 4 files changed, 163 insertions(+), 145 deletions(-) create mode 100644 packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js create mode 100644 packages/ipfs-http-client/src/lib/multipart-request.node.js diff --git a/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js b/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js index 1e726ca49a..e4a644a393 100644 --- a/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js +++ b/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js @@ -1,74 +1,9 @@ 'use strict' -const errCode = require('err-code') -const uint8ArrayFromString = require('uint8arrays/from-string') -const browserStreamToIt = require('browser-readablestream-to-it') -const blobToIt = require('blob-to-it') -const itPeekable = require('it-peekable') -const all = require('it-all') -const map = require('it-map') -const { - isBytes, - isBlob -} = require('./utils') - -async function * toAsyncIterable (input) { - // Bytes | String - if (isBytes(input) || typeof input === 'string' || input instanceof String) { - yield toBuffer(input) - return - } - - // Blob - if (isBlob(input)) { - yield * blobToIt(input) - return - } - - // Browser stream - if (typeof input.getReader === 'function') { - input = browserStreamToIt(input) - } - - // (Async)Iterator - if (input[Symbol.iterator] || input[Symbol.asyncIterator]) { - const peekable = itPeekable(input) - const { value, done } = await peekable.peek() - - if (done) { - // make sure empty iterators result in empty files - yield * peekable - return - } - - peekable.push(value) - - // (Async)Iterable - if (Number.isInteger(value)) { - yield toBuffer(await all(peekable)) - return - } - - // (Async)Iterable - if (isBytes(value) || typeof value === 'string' || value instanceof String) { - yield * map(peekable, chunk => toBuffer(chunk)) - return - } - } - - throw errCode(new Error(`Unexpected input: ${input}`), 'ERR_UNEXPECTED_INPUT') +// In electron-renderer we use native fetch and should encode content using +// native Blobs. +if (typeof Blob === 'function') { + module.exports = require('./normalise-content.browser') +} else { + module.exports = require('./normalise-content.node') } - -function toBuffer (chunk) { - if (isBytes(chunk)) { - return chunk - } - - if (Array.isArray(chunk)) { - return Uint8Array.from(chunk) - } - - return uint8ArrayFromString(chunk) -} - -module.exports = toAsyncIterable diff --git a/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js b/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js new file mode 100644 index 0000000000..1e726ca49a --- /dev/null +++ b/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js @@ -0,0 +1,74 @@ +'use strict' + +const errCode = require('err-code') +const uint8ArrayFromString = require('uint8arrays/from-string') +const browserStreamToIt = require('browser-readablestream-to-it') +const blobToIt = require('blob-to-it') +const itPeekable = require('it-peekable') +const all = require('it-all') +const map = require('it-map') +const { + isBytes, + isBlob +} = require('./utils') + +async function * toAsyncIterable (input) { + // Bytes | String + if (isBytes(input) || typeof input === 'string' || input instanceof String) { + yield toBuffer(input) + return + } + + // Blob + if (isBlob(input)) { + yield * blobToIt(input) + return + } + + // Browser stream + if (typeof input.getReader === 'function') { + input = browserStreamToIt(input) + } + + // (Async)Iterator + if (input[Symbol.iterator] || input[Symbol.asyncIterator]) { + const peekable = itPeekable(input) + const { value, done } = await peekable.peek() + + if (done) { + // make sure empty iterators result in empty files + yield * peekable + return + } + + peekable.push(value) + + // (Async)Iterable + if (Number.isInteger(value)) { + yield toBuffer(await all(peekable)) + return + } + + // (Async)Iterable + if (isBytes(value) || typeof value === 'string' || value instanceof String) { + yield * map(peekable, chunk => toBuffer(chunk)) + return + } + } + + throw errCode(new Error(`Unexpected input: ${input}`), 'ERR_UNEXPECTED_INPUT') +} + +function toBuffer (chunk) { + if (isBytes(chunk)) { + return chunk + } + + if (Array.isArray(chunk)) { + return Uint8Array.from(chunk) + } + + return uint8ArrayFromString(chunk) +} + +module.exports = toAsyncIterable diff --git a/packages/ipfs-http-client/src/lib/multipart-request.js b/packages/ipfs-http-client/src/lib/multipart-request.js index 391e9ffb79..35cbbdc1f4 100644 --- a/packages/ipfs-http-client/src/lib/multipart-request.js +++ b/packages/ipfs-http-client/src/lib/multipart-request.js @@ -1,77 +1,9 @@ 'use strict' -const normaliseInput = require('ipfs-core-utils/src/files/normalise-input') -const { nanoid } = require('nanoid') -const modeToString = require('../lib/mode-to-string') -const mtimeToObject = require('../lib/mtime-to-object') -const merge = require('merge-options').bind({ ignoreUndefined: true }) -const toStream = require('it-to-stream') - -async function multipartRequest (source = '', abortController, headers = {}, boundary = `-----------------------------${nanoid()}`) { - async function * streamFiles (source) { - try { - let index = 0 - - for await (const { content, path, mode, mtime } of normaliseInput(source)) { - let fileSuffix = '' - const type = content ? 'file' : 'dir' - - if (index > 0) { - yield '\r\n' - - fileSuffix = `-${index}` - } - - let fieldName = type + fileSuffix - const qs = [] - - if (mode !== null && mode !== undefined) { - qs.push(`mode=${modeToString(mode)}`) - } - - if (mtime != null) { - const { - secs, nsecs - } = mtimeToObject(mtime) - - qs.push(`mtime=${secs}`) - - if (nsecs != null) { - qs.push(`mtime-nsecs=${nsecs}`) - } - } - - if (qs.length) { - fieldName = `${fieldName}?${qs.join('&')}` - } - - yield `--${boundary}\r\n` - yield `Content-Disposition: form-data; name="${fieldName}"; filename="${encodeURIComponent(path)}"\r\n` - yield `Content-Type: ${content ? 'application/octet-stream' : 'application/x-directory'}\r\n` - yield '\r\n' - - if (content) { - yield * content - } - - index++ - } - } catch (err) { - // workaround for https://github.com/node-fetch/node-fetch/issues/753 - abortController.abort(err) - } finally { - yield `\r\n--${boundary}--\r\n` - } - } - - return { - lengthComputable: false, - total: -1, - headers: merge(headers, { - 'Content-Type': `multipart/form-data; boundary=${boundary}` - }), - body: await toStream(streamFiles(source)) - } +// In electron-renderer we use native fetch and should encode body using native +// form data. +if (typeof fetch === 'function') { + module.exports = require('./multipart-request.browser') +} else { + module.exports = require('./multipart-request.node') } - -module.exports = multipartRequest diff --git a/packages/ipfs-http-client/src/lib/multipart-request.node.js b/packages/ipfs-http-client/src/lib/multipart-request.node.js new file mode 100644 index 0000000000..18bb65ec91 --- /dev/null +++ b/packages/ipfs-http-client/src/lib/multipart-request.node.js @@ -0,0 +1,77 @@ +'use strict' + +const normaliseInput = require('ipfs-core-utils/src/files/normalise-input') +const { nanoid } = require('nanoid') +const modeToString = require('./mode-to-string') +const mtimeToObject = require('./mtime-to-object') +const merge = require('merge-options').bind({ ignoreUndefined: true }) +const toStream = require('it-to-stream') + +async function multipartRequest (source = '', abortController, headers = {}, boundary = `-----------------------------${nanoid()}`) { + async function * streamFiles (source) { + try { + let index = 0 + + for await (const { content, path, mode, mtime } of normaliseInput(source)) { + let fileSuffix = '' + const type = content ? 'file' : 'dir' + + if (index > 0) { + yield '\r\n' + + fileSuffix = `-${index}` + } + + let fieldName = type + fileSuffix + const qs = [] + + if (mode !== null && mode !== undefined) { + qs.push(`mode=${modeToString(mode)}`) + } + + if (mtime != null) { + const { + secs, nsecs + } = mtimeToObject(mtime) + + qs.push(`mtime=${secs}`) + + if (nsecs != null) { + qs.push(`mtime-nsecs=${nsecs}`) + } + } + + if (qs.length) { + fieldName = `${fieldName}?${qs.join('&')}` + } + + yield `--${boundary}\r\n` + yield `Content-Disposition: form-data; name="${fieldName}"; filename="${encodeURIComponent(path)}"\r\n` + yield `Content-Type: ${content ? 'application/octet-stream' : 'application/x-directory'}\r\n` + yield '\r\n' + + if (content) { + yield * content + } + + index++ + } + } catch (err) { + // workaround for https://github.com/node-fetch/node-fetch/issues/753 + abortController.abort(err) + } finally { + yield `\r\n--${boundary}--\r\n` + } + } + + return { + lengthComputable: false, + total: -1, + headers: merge(headers, { + 'Content-Type': `multipart/form-data; boundary=${boundary}` + }), + body: await toStream(streamFiles(source)) + } +} + +module.exports = multipartRequest From 8ddcc419039c2e6e563fd3436db01f61ca9cf5e1 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 7 Oct 2020 16:51:55 -0700 Subject: [PATCH 09/19] fix: code branching for electron-renderer --- .../normalise-input/normalise-content.js | 77 +++++++++++++++++-- .../normalise-input/normalise-content.node.js | 74 ------------------ .../src/lib/multipart-request.browser.js | 4 +- 3 files changed, 74 insertions(+), 81 deletions(-) delete mode 100644 packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js diff --git a/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js b/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js index e4a644a393..1e726ca49a 100644 --- a/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js +++ b/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.js @@ -1,9 +1,74 @@ 'use strict' -// In electron-renderer we use native fetch and should encode content using -// native Blobs. -if (typeof Blob === 'function') { - module.exports = require('./normalise-content.browser') -} else { - module.exports = require('./normalise-content.node') +const errCode = require('err-code') +const uint8ArrayFromString = require('uint8arrays/from-string') +const browserStreamToIt = require('browser-readablestream-to-it') +const blobToIt = require('blob-to-it') +const itPeekable = require('it-peekable') +const all = require('it-all') +const map = require('it-map') +const { + isBytes, + isBlob +} = require('./utils') + +async function * toAsyncIterable (input) { + // Bytes | String + if (isBytes(input) || typeof input === 'string' || input instanceof String) { + yield toBuffer(input) + return + } + + // Blob + if (isBlob(input)) { + yield * blobToIt(input) + return + } + + // Browser stream + if (typeof input.getReader === 'function') { + input = browserStreamToIt(input) + } + + // (Async)Iterator + if (input[Symbol.iterator] || input[Symbol.asyncIterator]) { + const peekable = itPeekable(input) + const { value, done } = await peekable.peek() + + if (done) { + // make sure empty iterators result in empty files + yield * peekable + return + } + + peekable.push(value) + + // (Async)Iterable + if (Number.isInteger(value)) { + yield toBuffer(await all(peekable)) + return + } + + // (Async)Iterable + if (isBytes(value) || typeof value === 'string' || value instanceof String) { + yield * map(peekable, chunk => toBuffer(chunk)) + return + } + } + + throw errCode(new Error(`Unexpected input: ${input}`), 'ERR_UNEXPECTED_INPUT') } + +function toBuffer (chunk) { + if (isBytes(chunk)) { + return chunk + } + + if (Array.isArray(chunk)) { + return Uint8Array.from(chunk) + } + + return uint8ArrayFromString(chunk) +} + +module.exports = toAsyncIterable diff --git a/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js b/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js deleted file mode 100644 index 1e726ca49a..0000000000 --- a/packages/ipfs-core-utils/src/files/normalise-input/normalise-content.node.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict' - -const errCode = require('err-code') -const uint8ArrayFromString = require('uint8arrays/from-string') -const browserStreamToIt = require('browser-readablestream-to-it') -const blobToIt = require('blob-to-it') -const itPeekable = require('it-peekable') -const all = require('it-all') -const map = require('it-map') -const { - isBytes, - isBlob -} = require('./utils') - -async function * toAsyncIterable (input) { - // Bytes | String - if (isBytes(input) || typeof input === 'string' || input instanceof String) { - yield toBuffer(input) - return - } - - // Blob - if (isBlob(input)) { - yield * blobToIt(input) - return - } - - // Browser stream - if (typeof input.getReader === 'function') { - input = browserStreamToIt(input) - } - - // (Async)Iterator - if (input[Symbol.iterator] || input[Symbol.asyncIterator]) { - const peekable = itPeekable(input) - const { value, done } = await peekable.peek() - - if (done) { - // make sure empty iterators result in empty files - yield * peekable - return - } - - peekable.push(value) - - // (Async)Iterable - if (Number.isInteger(value)) { - yield toBuffer(await all(peekable)) - return - } - - // (Async)Iterable - if (isBytes(value) || typeof value === 'string' || value instanceof String) { - yield * map(peekable, chunk => toBuffer(chunk)) - return - } - } - - throw errCode(new Error(`Unexpected input: ${input}`), 'ERR_UNEXPECTED_INPUT') -} - -function toBuffer (chunk) { - if (isBytes(chunk)) { - return chunk - } - - if (Array.isArray(chunk)) { - return Uint8Array.from(chunk) - } - - return uint8ArrayFromString(chunk) -} - -module.exports = toAsyncIterable diff --git a/packages/ipfs-http-client/src/lib/multipart-request.browser.js b/packages/ipfs-http-client/src/lib/multipart-request.browser.js index f3ea7644f3..4cda9a9a09 100644 --- a/packages/ipfs-http-client/src/lib/multipart-request.browser.js +++ b/packages/ipfs-http-client/src/lib/multipart-request.browser.js @@ -1,6 +1,8 @@ 'use strict' -const normaliseInput = require('ipfs-core-utils/src/files/normalise-input') +// Import browser version otherwise electron-renderer will end up with node +// version and fail. +const normaliseInput = require('ipfs-core-utils/src/files/normalise-input/index.browser') const modeToString = require('./mode-to-string') const mtimeToObject = require('./mtime-to-object') const { File, FormData } = require('ipfs-utils/src/globalthis') From 8983ebfe1797ea5efc2b22143f74e8c0bb59f3c2 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Wed, 7 Oct 2020 20:38:43 -0700 Subject: [PATCH 10/19] fix: allow requests from electron renderer --- packages/ipfs-http-server/src/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/ipfs-http-server/src/index.js b/packages/ipfs-http-server/src/index.js index af446891b8..76bab79e92 100644 --- a/packages/ipfs-http-server/src/index.js +++ b/packages/ipfs-http-server/src/index.js @@ -159,6 +159,12 @@ class HttpApi { return h.continue } + // The fetch API in the Electron Renderer process sends no referer or + // origin but should be allowed + if (userAgent.includes('Electron')) { + return h.continue + } + // Disallow otherwise. // // This means the request probably came from a browser and thus, it From fb4b147161ed42a9cab80398467c442096c86143 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Fri, 13 Nov 2020 01:37:25 -0800 Subject: [PATCH 11/19] fix: emit compatible progress events --- packages/ipfs-http-client/package.json | 2 +- packages/ipfs-http-client/src/add-all.js | 46 ++++++++++++------- .../src/lib/multipart-request.browser.js | 15 +++--- .../src/lib/multipart-request.node.js | 17 +++++-- 4 files changed, 51 insertions(+), 29 deletions(-) diff --git a/packages/ipfs-http-client/package.json b/packages/ipfs-http-client/package.json index 1f50f2e028..4dc036d18b 100644 --- a/packages/ipfs-http-client/package.json +++ b/packages/ipfs-http-client/package.json @@ -55,8 +55,8 @@ "cids": "^1.0.0", "debug": "^4.1.1", "form-data": "^3.0.0", + "ipfs-core-utils": "^0.5.1", "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", - "ipfs-utils": "^4.0.0", "ipld-block": "^0.11.0", "ipld-dag-cbor": "^0.17.0", "ipld-dag-pb": "^0.20.0", diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index ac338938e1..f0c13493e8 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -16,7 +16,7 @@ module.exports = configure((api) => { // allow aborting requests on body errors const controller = new AbortController() const signal = anySignal([controller.signal, options.signal]) - const { headers, body, total, lengthComputable } = + const { headers, body, total, parts } = await multipartRequest(source, controller, options.headers) // In browser response body only starts streaming once upload is @@ -25,7 +25,7 @@ module.exports = configure((api) => { // `{ total, loaded}` passed to `onUploadProgress` and `multipart.total` // in which case we disable progress updates to be written out. const [progressFn, onUploadProgress] = typeof options.progress === 'function' - ? createProgressHandler(lengthComputable, total, options.progress) + ? createProgressHandler(total, parts, options.progress) : [null, null] const res = await api.post('add', { @@ -58,27 +58,42 @@ module.exports = configure((api) => { * Returns simple progress callback when content length isn't computable or a * progress event handler that inerpolates progress from upload progress events. * - * @param {boolean} lengthComputable * @param {number} total - * @param {(n:number) => void} progress + * @param {{name:string, start:number, end:number}[]|null} parts + * @param {(n:number, name:string) => void} progress */ -const createProgressHandler = (lengthComputable, total, progress) => - lengthComputable ? [null, createOnUploadPrgress(total, progress)] : [progress, null] +const createProgressHandler = (total, parts, progress) => + parts ? [null, createOnUploadPrgress(total, parts, progress)] : [progress, null] /** * Creates a progress handler that interpolates progress from upload progress * events and total size of the content that is added. * * @param {number} size - actual content size - * @param {(n:number) => void} progress - * @returns {(event:{total:number, loaded: number}) => progress} - */ -const createOnUploadPrgress = (size, progress) => ({ loaded, total }) => - progress(Math.floor(loaded / total * size)) - -/** - * @typedef {import('../../ipfs/src/core/components/add-all').UnixFSEntry} UnixFSEntry + * @param {{name:string, start:number, end:number}[]} parts + * @param {(n:number, name:string) => void} progress + * @returns {(event:{total:number, loaded: number}) => void} */ +const createOnUploadPrgress = (size, parts, progress) => { + let index = 0 + return ({ loaded, total }) => { + // Derive position from the current progress. + const position = Math.floor(loaded / total * size) + while (true) { + const { start, end, name } = parts[index] + // If within current part range reporst progress and break the loop + if (position < end) { + progress(position - start, name) + break + // If passed current part range report final byte for the chunk and + // move to next one. + } else { + progress(end - start, name) + index += 1 + } + } + } +} /** * @param {any} input @@ -108,7 +123,4 @@ function toCoreInterface ({ name, hash, size, mode, mtime, mtimeNsecs }) { /** * @typedef {import('ipfs-core/src/components/add-all/index').UnixFSEntry} UnixFSEntry - * @typedef {import('./index').HttpOptions} HttpOptions - * @typedef {Object} HttpAddOptions - * @property {} */ diff --git a/packages/ipfs-http-client/src/lib/multipart-request.browser.js b/packages/ipfs-http-client/src/lib/multipart-request.browser.js index 4cda9a9a09..8ffcb87489 100644 --- a/packages/ipfs-http-client/src/lib/multipart-request.browser.js +++ b/packages/ipfs-http-client/src/lib/multipart-request.browser.js @@ -8,6 +8,7 @@ const mtimeToObject = require('./mtime-to-object') const { File, FormData } = require('ipfs-utils/src/globalthis') async function multipartRequest (source = '', abortController, headers = {}) { + const parts = [] const formData = new FormData() let index = 0 let total = 0 @@ -27,10 +28,9 @@ async function multipartRequest (source = '', abortController, headers = {}) { qs.push(`mode=${modeToString(mode)}`) } - if (mtime != null) { - const { - secs, nsecs - } = mtimeToObject(mtime) + const time = mtimeToObject(mtime) + if (time != null) { + const { secs, nsecs } = time qs.push(`mtime=${secs}`) @@ -45,17 +45,20 @@ async function multipartRequest (source = '', abortController, headers = {}) { if (content) { formData.set(fieldName, content, encodeURIComponent(path)) - total += content.size + const end = total + content.size + parts.push({ name: path, start: total, end }) + total = end } else { formData.set(fieldName, new File([''], encodeURIComponent(path), { type: 'application/x-directory' })) + parts.push({ name: path, start: total, end: total }) } index++ } return { - lengthComputable: true, total, + parts, headers, body: formData } diff --git a/packages/ipfs-http-client/src/lib/multipart-request.node.js b/packages/ipfs-http-client/src/lib/multipart-request.node.js index 18bb65ec91..d707f4f2b4 100644 --- a/packages/ipfs-http-client/src/lib/multipart-request.node.js +++ b/packages/ipfs-http-client/src/lib/multipart-request.node.js @@ -7,6 +7,13 @@ const mtimeToObject = require('./mtime-to-object') const merge = require('merge-options').bind({ ignoreUndefined: true }) const toStream = require('it-to-stream') +/** + * + * @param {Object} source + * @param {AbortController} abortController + * @param {Headers|Record} [headers] + * @param {string} [boundary] + */ async function multipartRequest (source = '', abortController, headers = {}, boundary = `-----------------------------${nanoid()}`) { async function * streamFiles (source) { try { @@ -29,10 +36,9 @@ async function multipartRequest (source = '', abortController, headers = {}, bou qs.push(`mode=${modeToString(mode)}`) } - if (mtime != null) { - const { - secs, nsecs - } = mtimeToObject(mtime) + const time = mtimeToObject(mtime) + if (time != null) { + const { secs, nsecs } = time qs.push(`mtime=${secs}`) @@ -58,6 +64,7 @@ async function multipartRequest (source = '', abortController, headers = {}, bou } } catch (err) { // workaround for https://github.com/node-fetch/node-fetch/issues/753 + // @ts-ignore - abort does not expect an arguments abortController.abort(err) } finally { yield `\r\n--${boundary}--\r\n` @@ -65,7 +72,7 @@ async function multipartRequest (source = '', abortController, headers = {}, bou } return { - lengthComputable: false, + parts: null, total: -1, headers: merge(headers, { 'Content-Type': `multipart/form-data; boundary=${boundary}` From b16dcef035f201a9b23bd9b4424221a5eb54f82f Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Fri, 13 Nov 2020 13:10:29 -0800 Subject: [PATCH 12/19] fix: break loop when all parts are done --- packages/ipfs-http-client/src/add-all.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index f0c13493e8..5f1c252916 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -76,10 +76,11 @@ const createProgressHandler = (total, parts, progress) => */ const createOnUploadPrgress = (size, parts, progress) => { let index = 0 + const count = parts.length return ({ loaded, total }) => { // Derive position from the current progress. const position = Math.floor(loaded / total * size) - while (true) { + while (index < count) { const { start, end, name } = parts[index] // If within current part range reporst progress and break the loop if (position < end) { From 4d9dfddc522c5f2e84dd28e182aebad67115e326 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Fri, 13 Nov 2020 13:24:55 -0800 Subject: [PATCH 13/19] fix: omit dirs from progress updates --- packages/ipfs-http-client/src/lib/multipart-request.browser.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ipfs-http-client/src/lib/multipart-request.browser.js b/packages/ipfs-http-client/src/lib/multipart-request.browser.js index 8ffcb87489..417282a7d8 100644 --- a/packages/ipfs-http-client/src/lib/multipart-request.browser.js +++ b/packages/ipfs-http-client/src/lib/multipart-request.browser.js @@ -50,7 +50,6 @@ async function multipartRequest (source = '', abortController, headers = {}) { total = end } else { formData.set(fieldName, new File([''], encodeURIComponent(path), { type: 'application/x-directory' })) - parts.push({ name: path, start: total, end: total }) } index++ From 470f36badc13853f4eaf24fbc80c975574526a52 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Mon, 16 Nov 2020 08:13:28 +0000 Subject: [PATCH 14/19] chore: remove gh branch --- examples/browser-ipns-publish/package.json | 2 +- packages/interface-ipfs-core/package.json | 2 +- packages/ipfs-cli/package.json | 2 +- packages/ipfs-core-utils/package.json | 2 +- packages/ipfs-core/package.json | 2 +- packages/ipfs-http-client/package.json | 2 +- packages/ipfs/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/browser-ipns-publish/package.json b/examples/browser-ipns-publish/package.json index 69eef11198..94bbedc32b 100644 --- a/examples/browser-ipns-publish/package.json +++ b/examples/browser-ipns-publish/package.json @@ -15,7 +15,7 @@ "human-crypto-keys": "^0.1.4", "ipfs": "^0.52.0", "ipfs-http-client": "^48.1.0", - "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", + "ipfs-utils": "^5.0.0", "ipns": "^0.8.0", "it-last": "^1.0.4", "p-retry": "^4.2.0", diff --git a/packages/interface-ipfs-core/package.json b/packages/interface-ipfs-core/package.json index 73fbdca1ef..24bfed422a 100644 --- a/packages/interface-ipfs-core/package.json +++ b/packages/interface-ipfs-core/package.json @@ -40,7 +40,7 @@ "err-code": "^2.0.3", "ipfs-unixfs": "^2.0.3", "ipfs-unixfs-importer": "^4.0.0", - "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", + "ipfs-utils": "^5.0.0", "ipld-block": "^0.11.0", "ipld-dag-cbor": "^0.17.0", "ipld-dag-pb": "^0.20.0", diff --git a/packages/ipfs-cli/package.json b/packages/ipfs-cli/package.json index 22773eb71e..3a06326d1d 100644 --- a/packages/ipfs-cli/package.json +++ b/packages/ipfs-cli/package.json @@ -44,7 +44,7 @@ "ipfs-http-gateway": "^0.1.1", "ipfs-http-server": "^0.1.1", "ipfs-repo": "^7.0.0", - "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", + "ipfs-utils": "^5.0.0", "ipld-dag-cbor": "^0.17.0", "ipld-dag-pb": "^0.20.0", "it-all": "^1.0.4", diff --git a/packages/ipfs-core-utils/package.json b/packages/ipfs-core-utils/package.json index 489dbf73a0..eff2a42c73 100644 --- a/packages/ipfs-core-utils/package.json +++ b/packages/ipfs-core-utils/package.json @@ -42,7 +42,7 @@ "browser-readablestream-to-it": "^1.0.1", "cids": "^1.0.0", "err-code": "^2.0.3", - "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", + "ipfs-utils": "^5.0.0", "it-all": "^1.0.4", "it-map": "^1.0.4", "it-peekable": "^1.0.1", diff --git a/packages/ipfs-core/package.json b/packages/ipfs-core/package.json index 6ab1b49578..b7078a907b 100644 --- a/packages/ipfs-core/package.json +++ b/packages/ipfs-core/package.json @@ -76,7 +76,7 @@ "ipfs-unixfs": "^2.0.3", "ipfs-unixfs-exporter": "^3.0.4", "ipfs-unixfs-importer": "^4.0.0", - "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", + "ipfs-utils": "^5.0.0", "ipld": "^0.28.0", "ipld-block": "^0.11.0", "ipld-dag-cbor": "^0.17.0", diff --git a/packages/ipfs-http-client/package.json b/packages/ipfs-http-client/package.json index 4dc036d18b..3eda31b08e 100644 --- a/packages/ipfs-http-client/package.json +++ b/packages/ipfs-http-client/package.json @@ -56,7 +56,7 @@ "debug": "^4.1.1", "form-data": "^3.0.0", "ipfs-core-utils": "^0.5.1", - "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", + "ipfs-utils": "^5.0.0", "ipld-block": "^0.11.0", "ipld-dag-cbor": "^0.17.0", "ipld-dag-pb": "^0.20.0", diff --git a/packages/ipfs/package.json b/packages/ipfs/package.json index 2a0673a150..2817c42234 100644 --- a/packages/ipfs/package.json +++ b/packages/ipfs/package.json @@ -54,7 +54,7 @@ "interface-ipfs-core": "^0.142.0", "ipfs-http-client": "^48.1.0", "ipfs-interop": "^3.0.0", - "ipfs-utils": "git://github.com/ipfs/js-ipfs-utils#xhr-2", + "ipfs-utils": "^5.0.0", "ipfsd-ctl": "^7.0.2", "iso-random-stream": "^1.1.1", "iso-url": "^1.0.0", From 7753cc43cde9cbac777e64e24246c9ecbfdb3069 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Mon, 16 Nov 2020 08:14:10 +0000 Subject: [PATCH 15/19] chore: fix typo --- packages/ipfs-http-client/src/add-all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index 5f1c252916..8345999565 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -21,7 +21,7 @@ module.exports = configure((api) => { // In browser response body only starts streaming once upload is // complete, at which point all the progress updates are invalid. If - // length of the content is computable we can interpla te progress from + // length of the content is computable we can interpret progress from // `{ total, loaded}` passed to `onUploadProgress` and `multipart.total` // in which case we disable progress updates to be written out. const [progressFn, onUploadProgress] = typeof options.progress === 'function' From 299b7ead5e3e5d60a9aeddf639d6328652c595a1 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Mon, 16 Nov 2020 08:14:46 +0000 Subject: [PATCH 16/19] chore: remove duplicate code --- packages/ipfs-http-server/src/index.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/ipfs-http-server/src/index.js b/packages/ipfs-http-server/src/index.js index 76141e5311..5439be23d2 100644 --- a/packages/ipfs-http-server/src/index.js +++ b/packages/ipfs-http-server/src/index.js @@ -168,12 +168,6 @@ class HttpApi { return h.continue } - // The fetch API in the Electron Renderer process sends no referer or - // origin but should be allowed - if (userAgent.includes('Electron')) { - return h.continue - } - // Disallow otherwise. // // This means the request probably came from a browser and thus, it From e0930559419f68b0b67351a92ccfdaf037b06f97 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Mon, 16 Nov 2020 08:17:47 +0000 Subject: [PATCH 17/19] chore: more typos --- packages/ipfs-http-client/src/add-all.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ipfs-http-client/src/add-all.js b/packages/ipfs-http-client/src/add-all.js index 8345999565..49be9c7530 100644 --- a/packages/ipfs-http-client/src/add-all.js +++ b/packages/ipfs-http-client/src/add-all.js @@ -56,7 +56,7 @@ module.exports = configure((api) => { /** * Returns simple progress callback when content length isn't computable or a - * progress event handler that inerpolates progress from upload progress events. + * progress event handler that calculates progress from upload progress events. * * @param {number} total * @param {{name:string, start:number, end:number}[]|null} parts @@ -82,7 +82,7 @@ const createOnUploadPrgress = (size, parts, progress) => { const position = Math.floor(loaded / total * size) while (index < count) { const { start, end, name } = parts[index] - // If within current part range reporst progress and break the loop + // If within current part range report progress and break the loop if (position < end) { progress(position - start, name) break From ebe618df0b612583e174a9f4ec5c03f6c3005684 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Mon, 16 Nov 2020 08:19:01 +0000 Subject: [PATCH 18/19] chore: tiny bundle size increase --- packages/ipfs-core/.aegir.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ipfs-core/.aegir.js b/packages/ipfs-core/.aegir.js index 0b34b43f69..05bce3d747 100644 --- a/packages/ipfs-core/.aegir.js +++ b/packages/ipfs-core/.aegir.js @@ -15,7 +15,7 @@ let sigServerB let ipfsdServer module.exports = { - bundlesize: { maxSize: '523kB' }, + bundlesize: { maxSize: '524kB' }, karma: { files: [{ pattern: 'node_modules/interface-ipfs-core/test/fixtures/**/*', From f913450e4c72d9c68a4b6b10feefec5cce059f13 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Mon, 16 Nov 2020 08:19:28 +0000 Subject: [PATCH 19/19] chore: typos --- packages/ipfs-core/.aegir.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ipfs-core/.aegir.js b/packages/ipfs-core/.aegir.js index 05bce3d747..4439a67a88 100644 --- a/packages/ipfs-core/.aegir.js +++ b/packages/ipfs-core/.aegir.js @@ -9,7 +9,7 @@ const path = require('path') let preloadNode let echoServer = new EchoServer() -// the second signalling server is needed for the inferface test 'should list peers only once even if they have multiple addresses' +// the second signalling server is needed for the interface test 'should list peers only once even if they have multiple addresses' let sigServerA let sigServerB let ipfsdServer