Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Destroy method does not trigger Close event except the first stream! #153

Open
hnguyen48206 opened this issue Jun 17, 2021 · 1 comment

Comments

@hnguyen48206
Copy link

Hi everyone, I'm new to Nodejs and MongoDB in general and currently trying to use GridFs as a file storage. My setup is basically using busboy to handle the multipart form-data and then check when the uploading file exceeds the pre-specified file size limit, then I will use destroy method to cancel the stream and using the close event to check if I need to remove uploaded chunks from gridfs. All works just fine for the very first time file upload but not from the second one onward. The destroy method is called but 'close' event is not which means I do not get the callback to see if chunks deletion is needed.

router.post('/uploadfile', function (req, res) {
    //Limit file size to 6MB only
    var busboy = new Busboy({
        headers: req.headers, limits: {
            fileSize: 6 * 1024 * 1024
        }
    });

    var limit_reach = false;

    busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
        console.log('got file', filename, mimetype, encoding);
        // If the file is larger than the set limit, then destroy the streaming
        file.on('limit', function () {
            // writeStream.emit('close')
            writeStream.destroy(new Error('Destroyed the stream cause File was too large'))
            limit_reach = true;
            res.status(500).send('Destroyed the stream cause File was too large');
        });

        var writeStream
        try {
            //Remove Vietnamese characters and spaces
            let nameAfterProcessed = removeAccents(filename).replace(/\s/g, "")
            console.log(nameAfterProcessed)

            writeStream = gfs.createWriteStream({
                filename: nameAfterProcessed,
                content_type: mimetype,
            });
        } catch (error) {
            console.log(error)
        }
        if (writeStream != null) {
            writeStream.on('error', (err) => {
                //All the info of the uploaded file has been return. Storing the fileID to your data model for later use. 
                console.log(err)
            });
            writeStream.on('close', (file) => {
                //All the info of the uploaded file has been return. Storing the fileID to your data model for later use. 
                console.log(file)
                //check if File has been sucessfully uploaded or the stream was canceled by any reason.
                if(limit_reach)
                {
                    //Delete all unessary chunks in grid fs chunks using fileID
                    deleteUnfinishedUploadedFile(file._id)
                }
            });
            file.pipe(writeStream);
        }
    }).on('finish', function () {
        // show a link to the uploaded file
        if (!limit_reach)
            res.status(200).send('uploaded successfully');
    });
    req.pipe(busboy);
});

My development environment (node version: 10.16.3):

{
  "name": "vietnamagro_backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.21.1",
    "body-parser": "^1.19.0",
    "busboy": "^0.3.1",
    "cheerio": "^1.0.0-rc.6",
    "cors": "^2.8.5",
    "email-validator": "^2.0.4",
    "express": "^4.17.1",
    "firebase-admin": "^9.5.0",
    "gridfs-stream": "^1.1.1",
    "http-proxy-middleware": "^1.2.0",
    "mongodb": "^3.6.6",
    "node-cron": "^3.0.0",
    "nodemon": "^2.0.7",
    "socket.io": "^4.1.2",
    "toad-scheduler": "^1.3.0",
    "uuid": "^8.3.2"
  }
}
@hnguyen48206
Copy link
Author

For anyone who's having the same situation with what I mentioned above, here is my work-around at this moment though I'm not so certain why. In short, delaying the logic in _closeInternal method in writestream.js does the trick.

GridWriteStream.prototype._closeInternal = function (cb) {
	console.log('abc jhjkjhj')
	if (!this._opened) return;
	if (this._closing) return;
	this._closing = true;

	var self = this;
       // Here is where you want to delay with a settimeout
	setTimeout(() => {
		self._store.close(function (err, file) {
			self._closing = false;
			self._opened = false;
			if (err) return self._error(err);
			self.emit('close', file);
	
			if (cb) cb();
		});
	}, 2000);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant