如何写入具有从Firestore触发的Firebase云功能的云存储桶?

xrd*_*xrd 1 google-cloud-storage firebase google-cloud-functions google-cloud-firestore

为了确保它尽可能干净和隔离,我创建了一个新的测试项目,除了这些步骤之外,其中没有任何其他内容。

然后,我在控制台中启用了Cloud Firestore。我创建了一个名为“ blarg”的新集合(名字叫eh!)。我向其中添加了一个文档,并使用了自动编号,然后添加了一个带有字符串dumpty的名为“ humpty”的字段。在控制台中看起来像这样:

在此处输入图片说明

我在signaturesFirebase控制台的storage部分中创建了一个目录。当我的函数(下面)触发时,我想将文件写入此目录。

然后,我使用以下代码添加了云功能。它显示了(我假设)正确的功能部分,名称testItOut和触发事件document.update/blarg/{eventId}

const functions = require('firebase-functions');
const os = require('os');
const fs = require('fs');
const path = require('path');
require('firebase-admin').initializeApp();

exports.testItOut = functions.firestore
    .document('blarg/{docId}')
    .onUpdate((change, context) => {
    console.log( "Inside #testItOut" );
    const projectId = 'testing-60477';
    const Storage = require('@google-cloud/storage');
    const storage = new Storage({
        projectId,
    });
    let bucketName = 'signatures'; 
    let fileName = 'temp.txt';
    const tempFilePath = path.join(os.tmpdir(), fileName);
    console.log( `Writing out to ${tempFilePath}` );
    fs.writeFileSync(tempFilePath, "something!" );

    return storage
        .bucket( bucketName )
        .upload( tempFilePath )
        .then( () => fs.unlinkSync(tempFilePath) )
        .catch(err => console.error('ERROR inside upload: ', err) );
    });
Run Code Online (Sandbox Code Playgroud)

package.json如下所示:

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "eslint .",
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "dependencies": {
    "@google-cloud/storage": "^1.7.0",
    "firebase-admin": "~5.12.1",
    "firebase-functions": "^1.0.3"
  },
  "devDependencies": {
    "eslint": "^4.12.0",
    "eslint-plugin-promise": "^3.6.0"
  },
  "private": true
}
Run Code Online (Sandbox Code Playgroud)

如果更改键“ humpty”的值,则会看到函数调用。但是,我在日志中看到错误。

ERROR inside upload:  { ApiError: testing-60477@appspot.gserviceaccount.com does not have storage.objects.create access to signatures/temp.txt.
    at Object.parseHttpRespBody (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:193:30)
    at Object.handleResp (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:131:18)
...
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

我想这是尽可能简单的方法。我究竟做错了什么?我以为调用已initializeApp()授予我的功能权限以自动写入该帐户的存储桶?

我看到的唯一奇怪的错误是未设置计费。我认为只有在使用外部API时才有必要。Google Storage是“外部API”吗?日志消息并不表示这是问题所在。

xrd*_*xrd 5

问题是我错误地认为对的调用bucket是在存储桶中设置子目录。而不是bucket('signatures')我应该将其设为空调用bucket(),然后为该调用提供一个options参数(如{ destination: '/signatures/temp.txt' }upload

const functions = require('firebase-functions');
const os = require('os');
const fs = require('fs');
const path = require('path');
const admin = require('firebase-admin');
admin.initializeApp();

exports.testItOut = functions.firestore
    .document('blarg/{docId}')
    .onUpdate((change, context) => {
    console.log( "Inside #testItOut" );
    const storage = admin.storage()
    let fileName = 'temp.txt';
    let destination = '/signatures/temp.txt';
    const tempFilePath = path.join(os.tmpdir(), fileName);
    console.log( `Writing out to ${tempFilePath}` );
    fs.writeFileSync(tempFilePath, "something!" );

    return storage
        .bucket()
        .upload( tempFilePath, { destination } )
        .then( () => fs.unlinkSync(tempFilePath) )
        .catch(err => console.error('ERROR inside upload: ', err) );
    });
Run Code Online (Sandbox Code Playgroud)

我感到困惑是因为我在Firebase文档中看到了很多调用bucket("albums")该示例的示例(例如:https : //cloud.google.com/nodejs/docs/reference/storage/1.6.x/Bucket#getFiles),并假定了表示存储桶可用于设置上传子目录。现在对我来说,区别很明显,但是我被抛弃了,因为对bucket的调用看起来不像bucketname-12345.appspot.com我在Firebase存储控制台中看到的那样。