firebase - 如何使用云功能通过签名下载url删除存储图像?

标签 firebase firebase-storage google-cloud-functions google-cloud-firestore

我正在使用 firebase 云函数生成缩略图并将签名的图像 url 存储在 firestore 中:

'use strict';

const functions = require('firebase-functions');
const mkdirp = require('mkdirp-promise');
const gcs = require('@google-cloud/storage')({keyFilename: 'service-account-credentials.json'});
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

const THUMB_MAX_HEIGHT = 200;
const THUMB_MAX_WIDTH = 200;
const THUMB_PREFIX = 'thumb_';

exports.onUploadImage = functions.storage.object().onChange(async event => {
    const filePath = event.data.name;
    const contentType = event.data.contentType;
    const fileDir = path.dirname(filePath);
    const fileName = path.basename(filePath);
    const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}${fileName}`));
    const tempLocalFile = path.join(os.tmpdir(), filePath);
    const tempLocalDir = path.dirname(tempLocalFile);
    const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);

    if (!contentType.startsWith('image/')) {
        return null;
    }
    if (fileName.startsWith(THUMB_PREFIX)) {
        return null;
    }
    if (event.data.resourceState === 'not_exists') {
        return null;
    }

    const tankId = event.data.metadata.tankId;
    const userId = event.data.metadata.userId;
    const imageType = event.data.metadata.type;

    const bucket = gcs.bucket(event.data.bucket);
    const file = bucket.file(filePath);
    const thumbFile = bucket.file(thumbFilePath);
    
    const metadata = {
        contentType: contentType,
        customMetadata: {
            'type': imageType
        }
    };

    try {
        await mkdirp(tempLocalDir); 
        await file.download({destination: tempLocalFile}); 
        await spawn('convert', [tempLocalFile, '-thumbnail', `${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempLocalThumbFile], {capture: ['stdout', 'stderr']});
        await bucket.upload(tempLocalThumbFile, { destination: thumbFilePath, metadata: metadata });
        await fs.unlinkSync(tempLocalFile);
        await fs.unlinkSync(tempLocalThumbFile);

        const config = {
            action: 'read',
            expires: '03-01-2500'
        };

        const results = await Promise.all([
            thumbFile.getSignedUrl(config),
            file.getSignedUrl(config)
        ]);

        const thumbResult = results[0];
        const originalResult = results[1];
        const thumbFileUrl = thumbResult[0];
        const fileUrl = originalResult[0];

        const tankRef = admin.firestore().collection('tanks').doc(tankId);

        switch(imageType) {
            case 'gallery':
                await tankRef
                    .collection('gallery')
                    .add({
                        url: fileUrl,
                        thumbnail: thumbFileUrl,
                        createdAt: new Date()
                    });

                const tankSnapshot = await tankRef.get();
                const tankData = await tankSnapshot.data();

                let galleryCount = tankData.galleryCount || 0;
                galleryCount += 1;

                if (galleryCount < 0) galleryCount = 0;

                return await tankRef.update({ galleryCount }, { merge: true });
            case 'tankImage':
                await tankRef.set({ image: fileUrl, image_thumb: thumbFileUrl }, { merge: true });
                return null;
            case 'profileImage':
                await admin.auth().updateUser(userId, { photoURL: thumbFileUrl });
                await admin.firestore()
                    .collection('users')
                    .doc(userId)
                    .set({image: fileUrl});
                return null;
            default:
                return null
        }
    }
    catch(err) {
        console.log(err);
    }
});


现在我正在尝试编写另一个云函数,该函数在删除 firestore db 条目时从存储桶中删除存储的文件:

exports.onGalleryImageDelete = functions.firestore
    .document('/tanks/{tankId}/gallery/{docId}')
    .onDelete(async event => {
        const deletedDoc = event.data.previous.data();
        const bucket = admin.storage().bucket();

        await bucket.file(deletedDoc.url).delete();  // this is wrong... no idea how to solve this
        await bucket.file(deletedDoc.thumbnail).delete();

        return await updateTankDocumentCounter(event, 'galleryCount', 'onDelete');
    });


此代码实际上不起作用并返回一些 API 错误。如何从给定的签名下载网址中删除这些图像?

最佳答案

根据道格史蒂文森的评论,我存储了数据库的路径并最终得到了这个云函数:

exports.onGalleryImageDelete = functions.firestore
    .document('/tanks/{tankId}/gallery/{docId}')
    .onDelete(async event => {
        const deletedDoc = event.data.previous.data();
        const filePath = deletedDoc.path;
        const fileDir = path.dirname(filePath);
        const fileName = path.basename(filePath);
        const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}${fileName}`));

        const bucket = admin.storage().bucket();

        return await Promise.all([
            await bucket.file(filePath).delete(),
            await bucket.file(thumbFilePath).delete(),
            updateTankDocumentCounter(event, 'galleryCount', 'onDelete')
        ]);
    });

关于firebase - 如何使用云功能通过签名下载url删除存储图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48155210/

相关文章:

javascript - 具有 Firebase 云功能的自定义观察器

javascript - 如何获取 Firebase 实时数据库触发器云函数中先前节点和写入/更新节点之间的差异

android - 我如何获取 firebase storage android 中的文件夹名称列表?

android - 我如何使用 Firebase Storage 存储到不同的存储桶

javascript - 如何等待Firebase存储图像上传,然后运行下一个函数

google-cloud-platform - 将 us-central1 以外的区域用于 Google Cloud Functions

firebase - 如何在忽略现有功能的同时部署 Cloud Functions?

Firebase 托管 - 密码保护网站?

android - 使用 Firebase 数据库恢复 Activity 时如何正确恢复数据?

ios - 我在哪里上传 APNS/p12 证书文件到 Firebase 控制台?