Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase cloud function for file upload

Tags:

I have this cloud function that I wrote to upload file to google cloud storage:

const gcs = require('@google-cloud/storage')({keyFilename:'2fe4e3d2bfdc.json'});  var filePath = file.path + "/" + file.name;      return bucket.upload(filePath, {         destination: file.name     }).catch(reason => {             console.error(reason);     }); 

I used formidable to parse the uploaded file and I tried to log the properties of the uploaded file and it seems fine; it is uploaded to a temp dir '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/ but when I try to upload the file to the gcs am getting this error:

{ Error: EACCES: permission denied, stat '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg'     at Error (native)   errno: -13,   code: 'EACCES',   syscall: 'stat',   path: '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg' } 

I am using this html form to upload the file:

<!DOCTYPE html> <html> <body>  <form action="https://us-central1-appname.cloudfunctions.net/uploadFile" method="post" enctype="multipart/form-data">     Select image to upload:     <input type="file" name="fileToUpload" id="fileToUpload">     <input type="submit" value="Upload Image" name="submit"> </form>  </body> </html> 
like image 893
dsharew Avatar asked Jul 14 '17 08:07

dsharew


People also ask

How do I upload documents to Firebase?

Upload from a Blob or File Once you've created an appropriate reference, you then call the uploadBytes() method. uploadBytes() takes files via the JavaScript File and Blob APIs and uploads them to Cloud Storage. Learn more about the tree-shakeable Web v9 modular SDK and upgrade from version 8.

How do I upload files to the cloud?

In the Google Cloud console, go to the Cloud Storage Buckets page. In the list of buckets, click on the name of the bucket that you want to upload an object to. In the Objects tab for the bucket, either: Drag and drop the desired files from your desktop or file manager to the main pane in the Google Cloud console.

Can I upload files to firestore?

you can't upload files to cloud firestore it is non sql database. For storage use Firebase Storage.


2 Answers

I got a solution from the Firebase Support Team

So first thing:

var filePath = file.path + "/" + file.name; 

we dont need the file.name since the file.path is full path of the file (including the file name).

So changed it to this instead:

var filePath = file.path; 

Second, the function terminates before the asynchronous work in 'form.parse(...)' is completed. That means the actual file upload might still be in progress while the function execution has ended.

The fix for that is to wrap the form.parse(...) in a promise:

exports.uploadFile = functions.https.onRequest((req, res) => {    var form = new formidable.IncomingForm();    return new Promise((resolve, reject) => {      form.parse(req, function(err, fields, files) {        var file = files.fileToUpload;        if(!file){          reject("no file to upload, please choose a file.");          return;        }        console.info("about to upload file as a json: " + file.type);        var filePath = file.path;        console.log('File path: ' + filePath);          var bucket = gcs.bucket('bucket-name');        return bucket.upload(filePath, {            destination: file.name        }).then(() => {          resolve();  // Whole thing completed successfully.        }).catch((err) => {          reject('Failed to upload: ' + JSON.stringify(err));        });      });    }).then(() => {      res.status(200).send('Yay!');      return null    }).catch(err => {      console.error('Error while parsing form: ' + err);      res.status(500).send('Error while parsing form: ' + err);    });  }); 

Lastly, you may want to consider using the Cloud Storage for Firebase in uploading your file instead of Cloud functions. Cloud Storage for Firebase allows you to upload files directly to it, and would work much better:

  1. It has access control
  2. It has resumable uploads/downloads (great for poor connectivity)
  3. It can accept files of any size without timeout-issues
  4. If you want to trigger a Cloud Function on file upload even, you can do that and a lot more
like image 168
dsharew Avatar answered Sep 28 '22 04:09

dsharew


I managed this by downloading the file to the tmp instead.

You will need:

const mkdirp = require('mkdirp-promise'); 

Then, inside onChange. I created tempLocalDir like so:

const LOCAL_TMP_FOLDER = '/tmp/'; const fileDir = (the name of the file); //whatever method you choose to do this const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`; 

Then I use mkdirp to make the temp directory

return mkdirp(tempLocalDir).then(() => { // Then Download file from bucket. const bucket = gcs.bucket(object.bucket); return bucket.file(filePath).download({   destination: tempLocalFile }).then(() => {     console.log('The file has been downloaded to', tempLocalFile);     //Here I have some code that converts images then returns the converted image     //Then I use     return bucket.upload((the converted image), {         destination: (a file path in your database)     }).then(() => {         console.log('JPEG image uploaded to Storage at', filePath);     })//You can perform more actions of end the promise here 

I think my code achieves that you were trying to accomplish. I hope this helps; I can offer more code if necessary.

like image 32
Drei Avatar answered Sep 28 '22 02:09

Drei