0

I have the following function that works like a charm when used locally:

async function uploadFile(file: any, fileName: string, targetFolder: string) {
  return new Promise((resolve, reject) => {
    const destinationFilepath: string = `${targetFolder ? targetFolder + '/' : ''}${fileName}`;
    const storage = new Storage();

    const bucket = storage.bucket(UPLOAD_BUCKET);
    const blob = bucket.file(destinationFilepath);
    const blobStream = blob.createWriteStream();

    blobStream.on('error', (err: Error) => reject(err));

    blobStream.on('finish', () => {
      resolve({ message: `Success! File uploaded to ${blob.publicUrl()}`, publicUrl: blob.publicUrl(), bucket: bucket.name, fileName: blob.name });
    });

    blobStream.end(file.buffer);
  });
}

index.ts post route:

app.post('/gcs/upload/:folder?', async (req: Request, res: Response) => {
  const folder: string = req.params.folder || '';
  const fileName: string =  req?.file?.originalname ||  'FileWithoutFileName.txt';

  res.status(200).send(await uploadFile(req.rawBody, fileName, folder));
});

How can I convert this function so it works on Google Cloud Functions as well? I have tried so many things and I think the solution is using busboy, but I am confused and might not see the forest for the trees anymore.

Would it be as easy as using the req.rawBody for the buffer instead of file.buffer? Every suggestion I have found online suggest using os and fs, but I don't really know why. When I run it locally, I use the multer package and do memoryStorage.

Spurious
  • 1,903
  • 5
  • 27
  • 53

1 Answers1

0

I managed now to get this converted. I have a headache now, but maybe this is useful for people who would want to do something similar in the future:

I have added the console.log() for reference.

async function uploadFile(req: Request) {
  return new Promise((resolve, reject) => {
    const targetFolder: string = req.params.folder || '';
    const busboy = Busboy({ headers: req.headers });
    const storage = new Storage();
    const bucket = storage.bucket(UPLOAD_BUCKET);
    let retObj: any;

    busboy.on('file', (fieldname: string, file: any, info: Busboy.FileInfo) => {
      const { filename: fileName, encoding, mimeType } = info;
      console.log('fieldname', fieldname);
      console.log('file', file);
      console.log('fileName', fileName);
      console.log('encoding', encoding);
      console.log('mimetype', mimeType);
      const destinationFilepath: string = `${targetFolder ? targetFolder + '/' : ''}${fileName}`;
      const blob = bucket.file(destinationFilepath);
      retObj = { message: `Success! File uploaded to ${blob.publicUrl()}`, publicUrl: blob.publicUrl(), bucket: bucket.name, fileName: blob.name };
      file.pipe(blob.createWriteStream());
    });

    busboy.on('finish', () => resolve(retObj));

    busboy.end(req.rawBody);
  });

The original post route is now much simpler:

app.post('/gcs/upload/:folder?', async (req: Request, res: Response) => {
  const { securitytoken: securityToken } = req.headers;
  if (!req.rawBody) res.status(400).send('Missing File');
  res.status(200).send(await uploadFile(req));
});

Maybe this is of use for someone.

Spurious
  • 1,903
  • 5
  • 27
  • 53