0
votes

everybody. I've been going through this for hours and I need some help.

I am trying to set up a Cloud Function to resize an image uploaded to Firebase Cloud Storage. I've followed Google's docs and every file I've download and reuploaded through the GCF has been non-accessible and I can't figure out why. For starters, I'm just trying to reupload the image I'm downloading in the function and I can't even get that going.

This is the GCF itself:

const functions = require('firebase-functions');

const path = require('path');
const os = require('os');

const fs = require('fs-extra');

const { Storage } = require('@google-cloud/storage');
const gcs = new Storage();

exports.generateOptions = functions.storage.object().onFinalize(async object => {

  const bucket = gcs.bucket(object.bucket);
  const filePath = object.name;
  const fileName = filePath.split('/').pop();
  const bucketDir = path.dirname(filePath);

  const workingDir = path.join(os.tmpdir(), 'copies');
  const tmpFilePath = path.join(workingDir, fileName);

  if (fileName.includes('copy_') || !object.contentType.startsWith('image/')) {
    return false;
  }

  await fs.ensureDir(workingDir);

  await bucket.file(filePath).download({
    destination: tmpFilePath
  });

  const copyName = `copy_${fileName}`;

  await bucket.upload(tmpFilePath, {
    destination: path.join(bucketDir, copyName)
  })

  // Cleanup
  return fs.remove(workingDir);
}); 

Now, I've set flags to see if the bucket and the file exist (with bucket.exists() and bucket.file.exists() methods from @google-cloud/storage package) and they exist and the file is downloaded properly as far as I know.

After I reupload the file, the function runs fine and I end up with the original and the copied file, as follows:

Firebase Storage Bucket

So far so good. But when I try to open the file, it gets stuck without opening it or returning a download link.

Opening the image

So I've tried to open the file the other way, using this:

Other way to open

And after I click on 'Open' ('Abrir' in Spanish) it opens a new tab showing the following link:

Resulting link

So instead of getting a regular downloadURL, I end up with 'undefined' and I have no idea why.

I'm hoping someone has some sort of solution or workaround, or has encountered a problem like this before.

This is the package.json (for whatever it's worth):

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "eslint .",
    "serve": "firebase emulators:start --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "10"
  },
  "dependencies": {
    "@google-cloud/storage": "^5.1.1",
    "firebase-admin": "^8.10.0",
    "firebase-functions": "^3.6.1",
    "fs-extra": "^9.0.1",
    "sharp": "^0.25.4"
  },
  "devDependencies": {
    "eslint": "^5.12.0",
    "eslint-plugin-promise": "^4.0.1",
    "firebase-functions-test": "^0.2.0"
  },
  "private": true
}

Any help would be greatly appreciated!

2

2 Answers

2
votes

The problem is due to the fact that you're uploading the file via backend code. None of this would happen with files uploaded from web and mobile clients using the Firebase client SDK. You should be able to download the file just fine using code, and you should still be able to generate a download URL in client code if needed.

This is actually a well known problem, and I suggest that you contact Firebase support directly to file an issue to add your voice.

0
votes

In case someone wonders here, I contacted Firebase support and was told the problem is with lack of metadata when uploading from the Admin SDK.

I was given the following workaround:

await bucket.file(filePath).download({
  destination: tmpFilePath,
  metadata: {
    metadata :{
      firebaseStorageDownloadTokens: uuidv4()
    }
  },
});

Of course, you would need to install the uuid package for node.js (npm install uuid). With this added, the Firebase Console UI behaves properly.