Search code examples
node.jsreact-nativegoogle-cloud-storagefirebase-storagefirebase-admin

Get progress of firebase admin file upload


I'm trying to get the progress of a 1 minute video uploading to firebase bucket storage using the admin sdk. I've seen a lot about using firebase.storage().ref.child..... but I'm unable to do that with the admin sdk since they don't have the same functions. This is my file upload:

exports.uploadMedia = (req, res) => {
    const BusBoy = require('busboy');
    const path = require('path');
    const os = require('os');
    const fs = require('fs');

    const busboy = new BusBoy({ headers: req.headers, limits: { files: 1, fileSize: 200000000 } });

    let mediaFileName;
    let mediaToBeUploaded = {};

    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {

        if(mimetype !== 'image/jpeg' && mimetype !== 'image/png' && mimetype !== 'video/quicktime' && mimetype !== 'video/mp4') {
            console.log(mimetype);
            return res.status(400).json({ error: 'Wrong file type submitted, only .png, .jpeg, .mov, and .mp4 files allowed'})
        }

        // my.image.png
        const imageExtension = filename.split('.')[filename.split('.').length - 1];
        
        //43523451452345231234.png
        mediaFileName = `${Math.round(Math.random()*100000000000)}.${imageExtension}`;
        const filepath = path.join(os.tmpdir(), mediaFileName);
        mediaToBeUploaded = { filepath, mimetype };
        file.pipe(fs.createWriteStream(filepath));

        file.on('limit', function(){
            fs.unlink(filepath, function(){
                return res.json({'Error': 'Max file size is 200 Mb, file size too large'});
            });
        });
    });
    busboy.on('finish', () => {
        admin
        .storage()
        .bucket()
        .upload(mediaToBeUploaded.filepath, {
            resumable: false,
            metadata: {
                metadata: {
                    contentType: mediaToBeUploaded.mimetype
                }
            }
        })
        .then(() => {
            const meadiaUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${mediaFileName}?alt=media`;
            return res.json({mediaUrl: meadiaUrl});
        })
        .catch((err) => {
            console.error(err);
            return res.json({'Error': 'Error uploading media'});
        });
    });
    req.pipe(busboy);
}

This works okay right now, but the only problem is that the user can't see where their 1 or 2 minute video upload is at. Currently, it's just a activity indicator and the user just sits their waiting without any notice. I'm using react native on the frontend if that helps with anything. Would appreciate any help!


Solution

  • I was able to implement on the client side a lot easier... but it works perfect with image and video upload progress. On the backend, I was using the admin sdk, but frontend I was originally using the firebase sdk.

            this.uploadingMedia = true;
            const imageExtension = this.mediaFile.split('.')[this.mediaFile.split('.').length - 1];
            const mediaFileName = `${Math.round(Math.random()*100000000000)}.${imageExtension}`;
            const response = await fetch(this.mediaFile);
            const blob = await response.blob();
            const storageRef = storage.ref(`${mediaFileName}`).put(blob);
            storageRef.on(`state_changed`,snapshot=>{
              this.uploadProgress = (snapshot.bytesTransferred/snapshot.totalBytes);
            }, error=>{
              this.error = error.message;
              this.submitting = false;
              this.uploadingMedia = false;
              return;
            },
            async () => {
              storageRef.snapshot.ref.getDownloadURL().then(async (url)=>{
                imageUrl = [];
                videoUrl = [url];
                this.uploadingMedia = false;
                this.submitPost(imageUrl, videoUrl);
              });
            });