简体   繁体   中英

Create File in Google Cloud Bucket from Firebase Cloud Function

I have a function that monitors a node in a Realtime database and once a new child is written to the node the function simply needs to create a html document in a Google Cloud bucket. The HTML document will have a unique name and will contain some data from the node. It's all fairly straightforward, however I can't actually create and write to the document. I've tried 3 methods so far (outlined in the code below), none of these methods work.

const {Storage} = require('@google-cloud/storage');
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const fs = require('fs');
const {StringStream} = require('@rauschma/stringio')

const instanceId = 'my-project-12345';
const bucketName = 'my-bucket';

exports.processCertification = functions.database.instance(instanceId).ref('/t/{userId}/{testId}')
    .onCreate((snapshot, context) => {
      const dataJ = snapshot.toJSON();

      var testResult = "Invalid";
      if(dataJ.r == 1) {testResult = "Positive";}
      else if(dataJ.r == 2) {testResult = "Negative";}

      console.log('Processing certificate:', context.params.testId, testResult);

      var storage = new Storage({projectId: instanceId});
      const fileName = context.params.testId + '.html';
      const fileContents = "<html><head></head><body>Result: " + testResult + "</body></html>"
      const options = {resumable:false, metadata:{contentType:'text/html'}};

      const bucket = storage.bucket(bucketName);
      const file = bucket.file(fileName);

      console.log('Saving to:' + bucketName + '/' + fileName);

      if(false) {
        // Test 1. the file.save method
        // Errors with:
        //  (node:2) MetadataLookupWarning: received unexpected error = URL is not defined code = UNKNOWN
        file.save(fileContents, options, function(err) {
          if (!err) {console.log("Save created object at " + bucketName + "/" + fileName);}
          else {console.log("Save Failed " + err);}
        });

      } else if(true) {
        // Test 2. the readStream.pipe method
        // No errors, doesn't output error message, doesn't output finish message, no file created
        fs.createReadStream(fileContents)
          .pipe(file.createWriteStream(options))
          .on('error', function(err) {console.log('WriteStream Error');})
          .on('finish', function() {console.log('WriteStream Written');});

      } else {
        // Test 3. the StringStream with readStream.pipe method
        // Errors with:
        //   (node:2) MetadataLookupWarning: received unexpected error = URL is not defined code = UNKNOWN
        const writeStream = storage.bucket(bucketName).file(fileName).createWriteStream(options);
        writeStream.on('finish', function(){console.log('WriteStream Written');}).on('error', function(err){console.log('WriteStream Error');});
        const readStream = new StringStream(fileContents);
        readStream.pipe(writeStream);

      }
      console.log('Function Finished');

      return 0;
    });

In all cases the "Processing certificate" and "Saving to" outputs appear, I also get the "Function Finished" message every time. The errors (or in one case no response) is written against each of the tests in the code.

My next step will be to create the file locally and then use upload() method, however each of these methods seem like they should work, plus the only error message I have is talking about URL errors so I suspect trying to use upload() method would run into the same problems as well.

I'm using Node.JS v8.17.0 and the following packages

"dependencies": {
  "@google-cloud/storage": "^5.0.0",
  "@rauschma/stringio": "^1.4.0",
  "firebase-admin": "^8.10.0",
  "firebase-functions": "^3.6.1"
}

Any advice is most welcome

In each case, you are not working with promises correctly. For database triggers (and all other background triggers), you must return a promise that resolves when all of the asynchronous work is complete in a function. Right now, you're not doing anything at all with promises, while each of the APIs you're calling are all asynchronous. Your function is just returning 0 immediately without waiting for the upload to complete, and Cloud Functions is simply terminating and cleaning up before anything can happen.

I suggest choosing one of the methods that returns a promise with the upload is complete (probably file.save() ), then return that promise from the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM