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

Commit 9616aed

Browse files
author
Alan Shaw
authored
refactor: fetch add (#1087)
License: MIT Signed-off-by: Alan Shaw <alan.shaw@protocol.ai>
1 parent 4271c7a commit 9616aed

22 files changed

+260
-312
lines changed

.aegir.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const createServer = require('ipfsd-ctl').createServer
55
const server = createServer()
66

77
module.exports = {
8-
bundlesize: { maxSize: '237kB' },
8+
bundlesize: { maxSize: '240kB' },
99
webpack: {
1010
resolve: {
1111
mainFields: ['browser', 'main']

package.json

+11-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
"glob": false,
1919
"fs": false,
2020
"stream": "readable-stream",
21-
"ky-universal": "ky/umd"
21+
"ky-universal": "ky/umd",
22+
"./src/add/form-data.js": "./src/add/form-data.browser.js",
23+
"./src/add-from-fs/index.js": "./src/add-from-fs/index.browser.js"
2224
},
2325
"repository": "github:ipfs/js-ipfs-http-client",
2426
"scripts": {
@@ -40,6 +42,8 @@
4042
"dependencies": {
4143
"abort-controller": "^3.0.0",
4244
"async": "^2.6.1",
45+
"async-iterator-all": "^1.0.0",
46+
"async-iterator-to-pull-stream": "^1.3.0",
4347
"bignumber.js": "^9.0.0",
4448
"bl": "^3.0.0",
4549
"bs58": "^4.0.1",
@@ -52,9 +56,10 @@
5256
"err-code": "^2.0.0",
5357
"explain-error": "^1.0.4",
5458
"flatmap": "0.0.3",
59+
"fs-extra": "^8.1.0",
5560
"glob": "^7.1.3",
5661
"ipfs-block": "~0.8.1",
57-
"ipfs-utils": "~0.0.3",
62+
"ipfs-utils": "^0.1.0",
5863
"ipld-dag-cbor": "~0.15.0",
5964
"ipld-dag-pb": "~0.17.3",
6065
"ipld-raw": "^4.0.0",
@@ -63,6 +68,8 @@
6368
"is-stream": "^2.0.0",
6469
"iso-stream-http": "~0.1.2",
6570
"iso-url": "~0.4.6",
71+
"it-glob": "0.0.4",
72+
"it-to-stream": "^0.1.1",
6673
"iterable-ndjson": "^1.1.0",
6774
"just-kebab-case": "^1.1.0",
6875
"just-map-keys": "^1.1.0",
@@ -82,6 +89,7 @@
8289
"promisify-es6": "^1.0.3",
8390
"pull-defer": "~0.2.3",
8491
"pull-stream": "^3.6.9",
92+
"pull-stream-to-async-iterator": "^1.0.2",
8593
"pull-to-stream": "~0.1.1",
8694
"pump": "^3.0.0",
8795
"qs": "^6.5.2",
@@ -98,7 +106,7 @@
98106
"cross-env": "^5.2.0",
99107
"dirty-chai": "^2.0.1",
100108
"go-ipfs-dep": "^0.4.22",
101-
"interface-ipfs-core": "^0.111.0",
109+
"interface-ipfs-core": "^0.112.0",
102110
"ipfsd-ctl": "~0.45.0",
103111
"nock": "^10.0.2",
104112
"stream-equal": "^1.1.1"

src/add-from-fs/index.browser.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
'use strict'
2+
3+
module.exports = () => () => { throw new Error('unavailable in the browser') }

src/add-from-fs/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict'
2+
3+
const configure = require('../lib/configure')
4+
const globSource = require('ipfs-utils/src/files/glob-source')
5+
6+
module.exports = configure(({ ky }) => {
7+
const add = require('../add')({ ky })
8+
return (path, options) => add(globSource(path, options), options)
9+
})

src/add-from-url.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict'
2+
3+
const kyDefault = require('ky-universal').default
4+
const configure = require('./lib/configure')
5+
const toIterable = require('./lib/stream-to-iterable')
6+
7+
module.exports = configure(({ ky }) => {
8+
const add = require('./add')({ ky })
9+
10+
return (url, options) => (async function * () {
11+
options = options || {}
12+
13+
const { body } = await kyDefault.get(url)
14+
15+
const input = {
16+
path: decodeURIComponent(new URL(url).pathname.split('/').pop() || ''),
17+
content: toIterable(body)
18+
}
19+
20+
yield * add(input, options)
21+
})()
22+
})

src/add/form-data.browser.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict'
2+
/* eslint-env browser */
3+
4+
const { Buffer } = require('buffer')
5+
const normaliseInput = require('ipfs-utils/src/files/normalise-input')
6+
7+
exports.toFormData = async input => {
8+
const files = normaliseInput(input)
9+
const formData = new FormData()
10+
let i = 0
11+
12+
for await (const file of files) {
13+
if (file.content) {
14+
// In the browser there's _currently_ no streaming upload, buffer up our
15+
// async iterator chunks and append a big Blob :(
16+
// One day, this will be browser streams
17+
const bufs = []
18+
for await (const chunk of file.content) {
19+
bufs.push(Buffer.isBuffer(chunk) ? chunk.buffer : chunk)
20+
}
21+
22+
formData.append(`file-${i}`, new Blob(bufs, { type: 'application/octet-stream' }), file.path)
23+
} else {
24+
formData.append(`dir-${i}`, new Blob([], { type: 'application/x-directory' }), file.path)
25+
}
26+
27+
i++
28+
}
29+
30+
return formData
31+
}

src/add/form-data.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict'
2+
3+
const FormData = require('form-data')
4+
const { Buffer } = require('buffer')
5+
const toStream = require('it-to-stream')
6+
const normaliseInput = require('ipfs-utils/src/files/normalise-input')
7+
8+
exports.toFormData = async input => {
9+
const files = normaliseInput(input)
10+
const formData = new FormData()
11+
let i = 0
12+
13+
for await (const file of files) {
14+
if (file.content) {
15+
// In Node.js, FormData can be passed a stream so no need to buffer
16+
formData.append(
17+
`file-${i}`,
18+
// FIXME: add a `path` property to the stream so `form-data` doesn't set
19+
// a Content-Length header that is only the sum of the size of the
20+
// header/footer when knownLength option (below) is null.
21+
Object.assign(
22+
toStream.readable(file.content),
23+
{ path: file.path || `file-${i}` }
24+
),
25+
{
26+
filepath: encodeURIComponent(file.path),
27+
contentType: 'application/octet-stream',
28+
knownLength: file.content.length // Send Content-Length header if known
29+
}
30+
)
31+
} else {
32+
formData.append(`dir-${i}`, Buffer.alloc(0), {
33+
filepath: encodeURIComponent(file.path),
34+
contentType: 'application/x-directory'
35+
})
36+
}
37+
38+
i++
39+
}
40+
41+
return formData
42+
}

src/add/index.js

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use strict'
2+
3+
const ndjson = require('iterable-ndjson')
4+
const configure = require('../lib/configure')
5+
const toIterable = require('../lib/stream-to-iterable')
6+
const { toFormData } = require('./form-data')
7+
const toCamel = require('../lib/object-to-camel')
8+
9+
module.exports = configure(({ ky }) => {
10+
return (input, options) => (async function * () {
11+
options = options || {}
12+
13+
const searchParams = new URLSearchParams(options.searchParams)
14+
15+
searchParams.set('stream-channels', true)
16+
if (options.chunker) searchParams.set('chunker', options.chunker)
17+
if (options.cidVersion) searchParams.set('cid-version', options.cidVersion)
18+
if (options.cidBase) searchParams.set('cid-base', options.cidBase)
19+
if (options.enableShardingExperiment != null) searchParams.set('enable-sharding-experiment', options.enableShardingExperiment)
20+
if (options.hashAlg) searchParams.set('hash', options.hashAlg)
21+
if (options.onlyHash != null) searchParams.set('only-hash', options.onlyHash)
22+
if (options.pin != null) searchParams.set('pin', options.pin)
23+
if (options.progress) searchParams.set('progress', true)
24+
if (options.quiet != null) searchParams.set('quiet', options.quiet)
25+
if (options.quieter != null) searchParams.set('quieter', options.quieter)
26+
if (options.rawLeaves != null) searchParams.set('raw-leaves', options.rawLeaves)
27+
if (options.shardSplitThreshold) searchParams.set('shard-split-threshold', options.shardSplitThreshold)
28+
if (options.silent) searchParams.set('silent', options.silent)
29+
if (options.trickle != null) searchParams.set('trickle', options.trickle)
30+
if (options.wrapWithDirectory != null) searchParams.set('wrap-with-directory', options.wrapWithDirectory)
31+
32+
const res = await ky.post('add', {
33+
timeout: options.timeout,
34+
signal: options.signal,
35+
headers: options.headers,
36+
searchParams,
37+
body: await toFormData(input)
38+
})
39+
40+
for await (let file of ndjson(toIterable(res.body))) {
41+
file = toCamel(file)
42+
// console.log(file)
43+
if (options.progress && file.bytes) {
44+
options.progress(file.bytes)
45+
} else {
46+
yield toCoreInterface(file)
47+
}
48+
}
49+
})()
50+
})
51+
52+
function toCoreInterface ({ name, hash, size }) {
53+
return { path: name, hash, size: parseInt(size) }
54+
}

src/files-mfs/write.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const promisify = require('promisify-es6')
44
const concatStream = require('concat-stream')
55
const once = require('once')
6-
const FileResultStreamConverter = require('../utils/file-result-stream-converter')
76
const SendFilesStream = require('../utils/send-files-stream')
87

98
module.exports = (send) => {
@@ -29,8 +28,7 @@ module.exports = (send) => {
2928

3029
const options = {
3130
args: pathDst,
32-
qs: opts,
33-
converter: FileResultStreamConverter
31+
qs: opts
3432
}
3533

3634
const stream = sendFilesStream({ qs: options })

src/files-regular/add-async-iterator.js

-23
This file was deleted.

src/files-regular/add-from-fs.js

-40
This file was deleted.

src/files-regular/add-from-url.js

-70
This file was deleted.

0 commit comments

Comments
 (0)