🛠️ refactor: Handle .webp, Improve File Life Cycle 📁 (#1213)

* fix: handle webp images correctly

* refactor: use the userPath from the start of the filecycle to avoid handling the blob, whose loading may fail upon user request

* refactor: delete temp files on reload and new chat
This commit is contained in:
Danny Avila 2023-11-24 16:45:06 -05:00 committed by GitHub
parent 650759306d
commit cc39074e0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 160 additions and 66 deletions

View file

@ -1,16 +1,35 @@
const path = require('path');
const sharp = require('sharp');
const fs = require('fs').promises;
const fs = require('fs');
const { resizeImage } = require('./resize');
async function convertToWebP(inputFilePath, resolution = 'high') {
async function convertToWebP(req, file, resolution = 'high') {
const inputFilePath = file.path;
const { buffer: resizedBuffer, width, height } = await resizeImage(inputFilePath, resolution);
const outputFilePath = inputFilePath.replace(/\.[^/.]+$/, '') + '.webp';
const extension = path.extname(inputFilePath);
const { imageOutput } = req.app.locals.config;
const userPath = path.join(imageOutput, req.user.id);
if (!fs.existsSync(userPath)) {
fs.mkdirSync(userPath, { recursive: true });
}
const newPath = path.join(userPath, path.basename(inputFilePath));
if (extension.toLowerCase() === '.webp') {
const bytes = Buffer.byteLength(resizedBuffer);
await fs.promises.writeFile(newPath, resizedBuffer);
const filepath = path.posix.join('/', 'images', req.user.id, path.basename(newPath));
return { filepath, bytes, width, height };
}
const outputFilePath = newPath.replace(extension, '.webp');
const data = await sharp(resizedBuffer).toFormat('webp').toBuffer();
await fs.writeFile(outputFilePath, data);
await fs.promises.writeFile(outputFilePath, data);
const bytes = Buffer.byteLength(data);
const filepath = path.posix.join('/', 'images', 'temp', path.basename(outputFilePath));
await fs.unlink(inputFilePath);
const filepath = path.posix.join('/', 'images', req.user.id, path.basename(outputFilePath));
await fs.promises.unlink(inputFilePath);
return { filepath, bytes, width, height };
}

View file

@ -14,7 +14,7 @@ function encodeImage(imagePath) {
});
}
async function encodeAndMove(req, file) {
async function updateAndEncode(req, file) {
const { publicPath, imageOutput } = req.app.locals.config;
const userPath = path.join(imageOutput, req.user.id);
@ -23,24 +23,16 @@ async function encodeAndMove(req, file) {
}
const filepath = path.join(publicPath, file.filepath);
if (!filepath.includes('temp')) {
const base64 = await encodeImage(filepath);
return [file, base64];
}
const newPath = path.join(userPath, path.basename(file.filepath));
await fs.promises.rename(filepath, newPath);
const newFilePath = path.posix.join('/', 'images', req.user.id, path.basename(file.filepath));
const promises = [];
promises.push(updateFile({ file_id: file.file_id, filepath: newFilePath }));
promises.push(encodeImage(newPath));
promises.push(updateFile({ file_id: file.file_id }));
promises.push(encodeImage(filepath));
return await Promise.all(promises);
}
async function encodeAndFormat(req, files) {
const promises = [];
for (let file of files) {
promises.push(encodeAndMove(req, file));
promises.push(updateAndEncode(req, file));
}
// TODO: make detail configurable, as of now resizing is done

View file

@ -7,16 +7,18 @@ const { convertToWebP } = require('./images/convert');
* Files must be deleted from the server filesystem manually.
*
* @param {Object} params - The parameters object.
* @param {Express.Request} params.req - The Express request object.
* @param {Express.Response} params.res - The Express response object.
* @param {Express.Multer.File} params.file - The uploaded file.
* @param {ImageMetadata} params.metadata - Additional metadata for the file.
* @returns {Promise<void>}
*/
const localStrategy = async ({ res, file, metadata }) => {
const localStrategy = async ({ req, res, file, metadata }) => {
const { file_id, temp_file_id } = metadata;
const { filepath, bytes, width, height } = await convertToWebP(file.path);
const { filepath, bytes, width, height } = await convertToWebP(req, file);
const result = await createFile(
{
user: req.user.id,
file_id,
temp_file_id,
bytes,