46 lines
1.9 KiB
JavaScript
46 lines
1.9 KiB
JavaScript
import config from 'config';
|
|
import path from 'path';
|
|
import fs from 'fs/promises';
|
|
import mime from 'mime';
|
|
import crypto from 'crypto';
|
|
import { fileTypeFromBuffer } from 'file-type';
|
|
import sharp from 'sharp';
|
|
import { HttpError } from '#src/errors.js';
|
|
function hashFile(fileBuffer) {
|
|
return crypto.createHash('sha256')
|
|
.update(fileBuffer)
|
|
.digest('hex');
|
|
}
|
|
async function validateMimetype(file, fileBuffer) {
|
|
const { mime } = await fileTypeFromBuffer(fileBuffer);
|
|
if (mime !== file.mimetype) {
|
|
throw new HttpError(`MIME type mismatch: ${file.mimetype} expected, ${mime} found`, 400);
|
|
}
|
|
}
|
|
async function generateThumb(type, fileBuffer, hash, targetPath) {
|
|
if (type === 'image') {
|
|
await sharp(fileBuffer)
|
|
.resize({ height: config.uploads.thumbHeight })
|
|
.jpeg({ quality: config.uploads.thumbQuality })
|
|
.toFile(path.join(targetPath, `${hash}_t.jpg`));
|
|
}
|
|
}
|
|
export async function uploadFiles(files, options) {
|
|
console.log('FILES', files, options);
|
|
await files.reduce(async (chain, file) => {
|
|
await chain;
|
|
const tempFilePath = path.join(config.uploads.path, 'temp', file.tempName);
|
|
const fileBuffer = await fs.readFile(tempFilePath);
|
|
const hash = hashFile(fileBuffer);
|
|
await validateMimetype(file, fileBuffer);
|
|
const targetPath = path.join(config.uploads.path, 'full', hash.slice(0, 2), hash.slice(2, 4));
|
|
const extension = mime.getExtension(file.mimetype);
|
|
await fs.mkdir(targetPath, { recursive: true });
|
|
await Promise.all([
|
|
generateThumb(file.mimetype.split('/')[0], fileBuffer, hash, targetPath),
|
|
fs.rename(path.join(config.uploads.path, 'temp', file.tempName), path.join(targetPath, `${hash}.${extension}`)),
|
|
]);
|
|
}, Promise.resolve());
|
|
return files;
|
|
}
|
|
//# sourceMappingURL=files.js.map
|