aboutsummaryrefslogtreecommitdiff
path: root/src/api/utils/multerStorage.js
blob: 1f1f0ddd27a14ff1995fa32123813f11b5cd270e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
const fs = require('fs');
const path = require('path');
const blake3 = require('blake3');
const jetpack = require('fs-jetpack');
const FileType = require('file-type');

function DiskStorage(opts) {
	this.getFilename = opts.filename;

	if (typeof opts.destination === 'string') {
		jetpack.dir(opts.destination);
		this.getDestination = ($0, $1, cb) => { cb(null, opts.destination); };
	} else {
		this.getDestination = opts.destination;
	}
}

DiskStorage.prototype._handleFile = function _handleFile(req, file, cb) {
	const that = this; // eslint-disable-line consistent-this

	that.getDestination(req, file, (err, destination) => {
		if (err) return cb(err);

		that.getFilename(req, file, (err, filename) => {
			if (err) return cb(err);

			const finalPath = path.join(destination, filename);
			const onerror = err => {
				hash.dispose(); // eslint-disable-line no-use-before-define
				cb(err);
			};

			let outStream;
			let hash;
			if (file._isChunk) {
				if (!file._chunksData.stream) {
					file._chunksData.stream = fs.createWriteStream(finalPath, { flags: 'a' });
					file._chunksData.stream.on('error', onerror);
				}
				if (!file._chunksData.hasher) {
					file._chunksData.hasher = blake3.createHash();
				}

				outStream = file._chunksData.stream;
				hash = file._chunksData.hasher;
			} else {
				outStream = fs.createWriteStream(finalPath);
				outStream.on('error', onerror);
				hash = blake3.createHash();
			}

			file.stream.on('error', onerror);
			file.stream.on('data', d => hash.update(d));

			if (file._isChunk) {
				if (file._chunksData.chunks === 0) {
					FileType.stream(file.stream).then(ftStream => {
						file._chunksData.fileType = ftStream.fileType;
						file.stream.on('end', () => {
							cb(null, {
								destination,
								filename,
								path: finalPath,
								fileType: file._chunksData.fileType
							});
						});
						ftStream.pipe(outStream, { end: false });
					});
				} else {
					file.stream.on('end', () => {
						cb(null, {
							destination,
							filename,
							path: finalPath,
							fileType: file._chunksData.fileType
						});
					});
					file.stream.pipe(outStream, { end: false });
				}
			} else {
				FileType.stream(file.stream).then(ftStream => {
					outStream.on('finish', () => {
						cb(null, {
							destination,
							filename,
							path: finalPath,
							size: outStream.bytesWritten,
							hash: hash.digest('hex'),
							fileType: ftStream.fileType
						});
					});
					ftStream.pipe(outStream);
				});
			}
		});
	});
};

DiskStorage.prototype._removeFile = function _removeFile(req, file, cb) {
	const path = file.path;

	delete file.destination;
	delete file.filename;
	delete file.path;

	fs.unlink(path, cb);
};

module.exports = opts => new DiskStorage(opts);