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

Commit 6be5906

Browse files
authored
fix: mfs blob import for files larger than 262144b (#4251)
Turn the `Blob`/`File` object into a `ReadableStream` then turn that into an `AsyncIterator<Uint8Array>` the same as the other input types. Fixes #3601 Fixes #3576
1 parent b722041 commit 6be5906

File tree

4 files changed

+27
-50
lines changed

4 files changed

+27
-50
lines changed

packages/interface-ipfs-core/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@
112112
"pako": "^2.0.4",
113113
"readable-stream": "^4.0.0",
114114
"sinon": "^14.0.0",
115-
"uint8arrays": "^4.0.2"
115+
"uint8arrays": "^4.0.2",
116+
"wherearewe": "^2.0.1"
116117
},
117118
"browser": {
118119
"fs": false,

packages/interface-ipfs-core/src/files/stat.js

+22
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { identity } from 'multiformats/hashes/identity'
1111
import { randomBytes } from 'iso-random-stream'
1212
import isShardAtPath from '../utils/is-shard-at-path.js'
1313
import * as raw from 'multiformats/codecs/raw'
14+
import { isBrowser } from 'wherearewe'
1415

1516
/**
1617
* @typedef {import('ipfsd-ctl').Factory} Factory
@@ -103,6 +104,27 @@ export function testStat (factory, options) {
103104
})
104105
})
105106

107+
it('should stat a large browser File', async function () {
108+
if (!isBrowser) {
109+
this.skip()
110+
}
111+
112+
const filePath = `/stat-${Math.random()}/large-file-${Math.random()}.txt`
113+
const blob = new Blob([largeFile])
114+
115+
await ipfs.files.write(filePath, blob, {
116+
create: true,
117+
parents: true
118+
})
119+
120+
await expect(ipfs.files.stat(filePath)).to.eventually.include({
121+
size: largeFile.length,
122+
cumulativeSize: 490800,
123+
blocks: 2,
124+
type: 'file'
125+
})
126+
})
127+
106128
it('stats a raw node', async () => {
107129
const filePath = `/stat-${Math.random()}/large-file-${Math.random()}.txt`
108130

packages/ipfs-core/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"any-signal": "^3.0.0",
103103
"array-shuffle": "^3.0.0",
104104
"blockstore-core": "^2.0.1",
105+
"browser-readablestream-to-it": "^2.0.0",
105106
"dag-jose": "^3.0.1",
106107
"datastore-core": "^8.0.1",
107108
"datastore-pubsub": "^6.0.0",

packages/ipfs-core/src/components/files/utils/to-async-iterator.js

+2-49
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import errCode from 'err-code'
22
import { logger } from '@libp2p/logger'
3-
import {
4-
MFS_MAX_CHUNK_SIZE
5-
} from '../../../utils.js'
63
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
4+
import browserStreamToIt from 'browser-readablestream-to-it'
75

86
const log = logger('ipfs:mfs:utils:to-async-iterator')
97

@@ -44,52 +42,7 @@ export function toAsyncIterator (content) {
4442
if (global.Blob && content instanceof global.Blob) {
4543
// HTML5 Blob objects (including Files)
4644
log('Content was an HTML5 Blob')
47-
48-
let index = 0
49-
50-
const iterator = {
51-
next: () => {
52-
if (index > content.size) {
53-
return {
54-
done: true
55-
}
56-
}
57-
58-
return new Promise((resolve, reject) => {
59-
const chunk = content.slice(index, MFS_MAX_CHUNK_SIZE)
60-
index += MFS_MAX_CHUNK_SIZE
61-
62-
const reader = new global.FileReader()
63-
64-
/**
65-
* @param {{ error?: Error }} ev
66-
*/
67-
const handleLoad = (ev) => {
68-
// @ts-expect-error No overload matches this call.
69-
reader.removeEventListener('loadend', handleLoad, false)
70-
71-
if (ev.error) {
72-
return reject(ev.error)
73-
}
74-
75-
resolve({
76-
done: false,
77-
value: new Uint8Array(/** @type {ArrayBuffer} */(reader.result))
78-
})
79-
}
80-
81-
// @ts-expect-error No overload matches this call.
82-
reader.addEventListener('loadend', handleLoad)
83-
reader.readAsArrayBuffer(chunk)
84-
})
85-
}
86-
}
87-
88-
return {
89-
[Symbol.asyncIterator]: () => {
90-
return iterator
91-
}
92-
}
45+
return browserStreamToIt(content.stream())
9346
}
9447

9548
throw errCode(new Error(`Don't know how to convert ${content} into an async iterator`), 'ERR_INVALID_PARAMS')

0 commit comments

Comments
 (0)