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>
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: