Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to upload image file via HTTP Google Cloud Function?

I have read tutorials on how to upload the image to a bucket and do post processing via background function. But my requirement is to upload the image, do post processing and return the result immediately via HTTP function. Please let me know if this is the correct way to do or not as I didn't get much material online on this. Here is how I went about it:

HTTP Cloud function:

exports.uploadImage = function (req, res){
 var file = req.body.file;
 uploadSomewhere(file)(); < post-processing code which is working fine >

UI form:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script> 
<script src="http://malsup.github.com/jquery.form.js"></script>
<form id="myForm" action="<cloud_function_url>/uploadImage" method="post"> 
  <label for="file">Choose file to upload</label>
  <input type="file" id="file" name="file" multiple>
  <input type="submit" value="Submit" /> 
</form>

<script> 
 $(document).ready(function() { 
  $('#myForm').ajaxForm(function() { 
 }); 
}); 
</script>

The problem is, after I deployed the function, when I upload the image from the folder where function is present, image gets uploaded. But if I upload the image from any other location, it returns me error:

Error: Error in uploading image file .... - Error: ENOENT: no such file or directory, open '....'

Please let me know what am I doing wrong or if you need more information.

like image 802
anmolagrawal Avatar asked Oct 01 '17 11:10

anmolagrawal


People also ask

Can I upload files to Google Cloud Storage from URL?

It is not possible to upload a file to Google Cloud Storage directly from an URL. Since you are running the script from a local environment, the file contents that you want to upload, need to be in that same environment. This means that the contents of the url need to either be stored in the memory, or in a file.

How do you upload the file to a cloud location and share the URL?

Click on "Remote Upload" in Google Drive tab to trigger the upload file via URL link window. In the pop up window, enter/paste the source file URL link address. You can also specify the name.

How do I upload photos to Google Cloud from Android?

To upload a file to Cloud Storage, you first create a reference to the full path of the file, including the file name. Once you've created an appropriate reference, you then call the putBytes() , putFile() , or putStream() method to upload the file to Cloud Storage.


1 Answers

There is sample code for uploading files directly to Cloud Functions here: https://cloud.google.com/functions/docs/writing/http#multipart_data_and_file_uploads, but be aware there is a file size limit when using this approach (10MB). If you have files larger than that, I recommend you use the Cloud Storage approach and use something like the Firebase Realtime Database to manage the state on the client.

So, you generate the signed upload URL using a Cloud Function, then use the RTDB to track progress for the client. Return the URL and a reference to the location in the DB where you're going to track progress. The client would watch this location for updates. The client then uploads the file to Cloud Storage and the second function is triggered. After post processing it updates the RTDB which pushes the update down to the client. From the client's perspective this is all synchronous, but it's actually a series of async operations with state coalescing in the database.

Here's the sample code for inline updates taken from the docs if you're OK with file sizes < 10MB:

/**
 * Parses a 'multipart/form-data' upload request
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
const path = require('path');
const os = require('os');
const fs = require('fs');

// Node.js doesn't have a built-in multipart/form-data parsing library.
// Instead, we can use the 'busboy' library from NPM to parse these requests.
const Busboy = require('busboy');

exports.uploadFile = (req, res) => {
  if (req.method === 'POST') {
    const busboy = new Busboy({ headers: req.headers });
    const tmpdir = os.tmpdir();

    // This object will accumulate all the fields, keyed by their name
    const fields = {};

    // This object will accumulate all the uploaded files, keyed by their name.
    const uploads = {};

    // This code will process each non-file field in the form.
    busboy.on('field', (fieldname, val) => {
      // TODO(developer): Process submitted field values here
      console.log(`Processed field ${fieldname}: ${val}.`);
      fields[fieldname] = val;
    });

    let fileWrites = [];

    // This code will process each file uploaded.
    busboy.on('file', (fieldname, file, filename) => {
      // Note: os.tmpdir() points to an in-memory file system on GCF
      // Thus, any files in it must fit in the instance's memory.
      console.log(`Processed file ${filename}`);
      const filepath = path.join(tmpdir, filename);
      uploads[fieldname] = filepath;

      const writeStream = fs.createWriteStream(filepath);
      file.pipe(writeStream);

      // File was processed by Busboy; wait for it to be written to disk.
      const promise = new Promise((resolve, reject) => {
        file.on('end', () => {
          writeStream.end();
        });
        writeStream.on('finish', resolve);
        writeStream.on('error', reject);
      });
      fileWrites.push(promise);
    });

    // Triggered once all uploaded files are processed by Busboy.
    // We still need to wait for the disk writes (saves) to complete.
    busboy.on('finish', () => {
      Promise.all(fileWrites)
        .then(() => {
          // TODO(developer): Process saved files here
          for (const name in uploads) {
            const file = uploads[name];
            fs.unlinkSync(file);
          }
          res.send();
        });
    });

    busboy.end(req.rawBody);
  } else {
    // Return a "method not allowed" error
    res.status(405).end();
  }
};
like image 146
Jason Polites Avatar answered Oct 14 '22 21:10

Jason Polites