|
1 |
| -var concat = require('concat-stream') |
| 1 | +const Writable = require('stream').Writable |
| 2 | +const Buffer = require('buffer').Buffer |
| 3 | +const isUint8Array = require('util').types.isUint8Array |
2 | 4 |
|
3 |
| -function MemoryStorage (opts) {} |
| 5 | +class MemoryStorage { |
| 6 | + _handleFile (req, file, cb) { |
| 7 | + file.stream.pipe( |
| 8 | + new ConcatStream(function (data) { |
| 9 | + cb(null, { |
| 10 | + buffer: data, |
| 11 | + size: data.length |
| 12 | + }) |
| 13 | + }) |
| 14 | + ) |
| 15 | + } |
4 | 16 |
|
5 |
| -MemoryStorage.prototype._handleFile = function _handleFile (req, file, cb) { |
6 |
| - file.stream.pipe(concat({ encoding: 'buffer' }, function (data) { |
7 |
| - cb(null, { |
8 |
| - buffer: data, |
9 |
| - size: data.length |
| 17 | + _removeFile (req, file, cb) { |
| 18 | + delete file.buffer |
| 19 | + cb(null) |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +module.exports = function () { |
| 24 | + return new MemoryStorage() |
| 25 | +} |
| 26 | + |
| 27 | +/** |
| 28 | + * Writable stream that concatenates all written chunks into a single Buffer. |
| 29 | + * |
| 30 | + * Implementation inspired by the concat-stream npm package (https://www.npmjs.com/package/concat-stream), |
| 31 | + * modified for our specific use case. |
| 32 | + */ |
| 33 | +class ConcatStream extends Writable { |
| 34 | + /** |
| 35 | + * Creates a new ConcatStream instance. |
| 36 | + * @param {function(Buffer): void} cb - Callback invoked with the concatenated Buffer when the stream finishes. |
| 37 | + */ |
| 38 | + constructor (cb) { |
| 39 | + super() |
| 40 | + this.body = [] |
| 41 | + this.on('finish', function () { |
| 42 | + cb(this.getBody()) |
10 | 43 | })
|
11 |
| - })) |
| 44 | + } |
| 45 | + |
| 46 | + _write (chunk, enc, next) { |
| 47 | + this.body.push(chunk) |
| 48 | + next() |
| 49 | + } |
| 50 | + |
| 51 | + /** |
| 52 | + * Concatenates all collected chunks into a single Buffer. |
| 53 | + * @returns {Buffer} The concatenated buffer containing all written data. |
| 54 | + */ |
| 55 | + getBody () { |
| 56 | + const bufs = [] |
| 57 | + for (const p of this.body) { |
| 58 | + // Buffer.concat can handle Buffer and Uint8Array (and subclasses) |
| 59 | + if (Buffer.isBuffer(p) || isUint8Array(p)) { |
| 60 | + bufs.push(p) |
| 61 | + } else if (isBufferish(p)) { |
| 62 | + bufs.push(Buffer.from(p)) |
| 63 | + } else { |
| 64 | + bufs.push(Buffer.from(String(p))) |
| 65 | + } |
| 66 | + } |
| 67 | + return Buffer.concat(bufs) |
| 68 | + } |
12 | 69 | }
|
13 | 70 |
|
14 |
| -MemoryStorage.prototype._removeFile = function _removeFile (req, file, cb) { |
15 |
| - delete file.buffer |
16 |
| - cb(null) |
| 71 | +/** |
| 72 | + * Checks if the given value is array-like. |
| 73 | + * @param {*} arr |
| 74 | + * @returns {boolean} |
| 75 | + */ |
| 76 | +function isArrayish (arr) { |
| 77 | + return /Array\]$/.test(Object.prototype.toString.call(arr)) |
17 | 78 | }
|
18 | 79 |
|
19 |
| -module.exports = function (opts) { |
20 |
| - return new MemoryStorage(opts) |
| 80 | +/** |
| 81 | + * Checks if the given value is Buffer-like. |
| 82 | + * @param {*} p |
| 83 | + * @returns {boolean} |
| 84 | + */ |
| 85 | +function isBufferish (p) { |
| 86 | + return ( |
| 87 | + typeof p === 'string' || |
| 88 | + isArrayish(p) || |
| 89 | + (p && typeof p.subarray === 'function') |
| 90 | + ) |
21 | 91 | }
|
0 commit comments