Я использую облачные функции для изменения размера и создания миниатюр для загруженных изображений в Firebase Storage.При первой загрузке создаются эскизы, но я также хочу иметь возможность редактировать эти изображения, сохраняя то же имя.Вот как я это делаю:
Я загружаю изображение с этой функцией на клиент:
uploadImage (imageFile, folderName, imageName){
const storageRef = firebase.storage().ref();
// need to prefix image name with "slot_"
storageRef.child(`${folderName}/slot_${imageName}`).put(imageFile)
}
Затем с помощью этой облачной функции создаются эскизы:
export const generateThumbs = functions.storage.object().onFinalize(async
object => {
const bucket = gcs.bucket(object.bucket)
const filePath = object.name;
const fileName = filePath.split('/').pop();
const bucketDir = dirname(filePath);
const slotSizes = [64,250]
const temporaryDirectory = join(tmpdir(), `thumbs_${fileName}`);
const temporaryFilePath = join(temporaryDirectory, 'source.png');
// avoid loop includes only images
if (fileName.includes('thumb_') ||
!object.contentType.includes('image')) {
return false;
}
await fileSystem.ensureDir(temporaryDirectory);
// original file in temp directory
await bucket.file(filePath).download({
destination: temporaryFilePath
});
const slotUploadPromises = slotSizes.map(async size => {
const thumbName = `thumb_${size}_${fileName}`;
const thumbPath = join(temporaryDirectory, thumbName);
await sharp(temporaryFilePath).resize(size, size).toFile(thumbPath);
return bucket.upload(thumbPath, {
destination: join(bucketDir, thumbName),
metadata: {
contentType: 'image/jpeg',
}
})
});
await Promise.all(slotUploadPromises)
// removes temp directory
return fileSystem.remove(temporaryDirectory);
Так что, если я позвоню uploadImage(appleImage, 'MyImages', 'test')
, у меня в папке хранения будет 3 изображения (имя очень важно):
- slot_test
- thumb_250_slot_test
- thumb_64_slot_test
В этот момент, если я позвоню снова uploadImage(avocadoImage, 'MyImages', 'test')
, я ожидаю, что в хранилище будет та же "структура именования", но с обновленным изображением вместо старых, поэтому новые эскизыследует просто перезаписать старые.Что на самом деле происходит, так это то, что «базовое» изображение обновляется, а оба эскиза - нет.Окончание:
- slot_test ( отображение ОБНОВЛЕНО изображение )
- thumb_250_slot_test ( отображение миниатюры OLD image )
- thumb_64_slot_test ( отображение миниатюры OLD изображения )
I'mЗарегистрированы функции облака, ошибки не генерируются во время выполнения функции, миниатюры создаются нормально, и консоль Firebase также обновляет дату создания миниатюр, но я все еще получаю старое изображение миниатюр.Я попытался удалить временный каталог, используя fs-extra emptyDir()
, я пытался сначала удалить все миниатюры (через клиента), а затем снова загрузить безуспешно.
РЕДАКТИРОВАТЬ: нашел решение моей проблемы с помощью НЕ создания любой временной папки или временных файлов и использования взамен острого конвейера.Тем не менее, я все еще пропускаю основную проблему в коде выше.Я совершенно уверен, что по какой-то причине эта функция не удаляла временную папку, и это создавало проблемы всякий раз, когда я пытался перезаписать изображения.Эта функция работает:
export const generateThumbs = functions.storage.object().onFinalize(async object => {
const bucket = gcs.bucket(object.bucket)
const filePath = object.name;
const fileName = filePath.split('/').pop();
const bucketDir = dirname(filePath);
// metadata file
const metadata = {
contentType: 'image/jpeg',
}
if (fileName.includes('thumb_') || !object.contentType.includes('image')) {
return false;
}
if (fileName.includes('slot')) {
// array of promises
const slotUploadPromises = slotSizes.map(async size => {
const thumbName = `thumb_${size}_${fileName}`;
const thumbPath = join(path.dirname(filePath), thumbName);
const thumbnailUploadStream = bucket.file(thumbPath).createWriteStream({ metadata });
const pipeline = sharp();
pipeline.resize(size, Math.floor((size * 9) / 16)).max()
.pipe(thumbnailUploadStream);
bucket.file(filePath).createReadStream().pipe(pipeline);
return new Promise((resolve, reject) =>
thumbnailUploadStream
.on('finish', resolve)
.on('error', reject));
});
await Promise.all(slotUploadPromises)
}