Uploading Local File to Server with Nodejs

A few weeks ago i started a project that required a batch of cold data to be uploaded into a database so that a team of users could work through it. I already knew the data is sent in csv format so the initial issue was getting the file from my local laptop to the server. For that i'll be using posix module.

To start I'll install it using npm - npm install posix. Now I'll create a route handler.

var express = require('express');
var router = express.Router();
var http = require("http");
var url = require("url");
var multipart = require("multipart");
var sys = require("sys");
var events = require("events");
var posix = require("posix");

router.get('/api/upload/', function(req, res){

This is requiring the modules that we will be using and telling the app that any get request to "api/upload" should be handled by the given function.

// Request body is binary
req.setBodyEncoding("binary");

// Handle request as multipart
var stream = new multipart.Stream(req);

// Create promise that will be used to emit event on file close
var closePromise = new events.Promise();

stream.addListener("part", function(part) {..}

stream.addListener("complete", function() {..}

Let's discuss what is happening here. Firstly we've get the encoding type to be binary, then we've opened a new stream to read the file binary data, a closePromise is declared which will be used later on when we've finished, and two listeners are created to handle when the upload is finished, and when something is being uploaded.

Within the stream listener we'll create another listener on the which will handle "chunks" of data being transfered up, and another promise which will write the chunks to the file.

stream.addListener("part", function(part) {
    sys.debug("Received part, name = " + part.name + ",        filename = " + part.filename);

    var openPromise = null;

    // Add handler for a request part body chunk received
    part.addListener("body", function(chunk) {
        // Calculate upload progress
        var progress = (stream.bytesReceived / stream.bytesTotal * 100).toFixed(2);
        var mb = (stream.bytesTotal / 1024 / 1024).toFixed(1);

        sys.debug("Uploading " + mb + "mb (" + progress + "%)");

        // Ask to open/create file (if not asked before)
        if (openPromise == null) {
            sys.debug("Opening file");
            openPromise = posix.open("./uploads/" + part.filename, process.O_CREAT | process.O_WRONLY, 0600);
        }

        // Add callback to execute after file is opened
        // If file is already open it is executed immediately
        openPromise.addCallback(function(fileDescriptor) {
            // Write chunk to file
            write_chunk(req, fileDescriptor, chunk, 
                (stream.bytesReceived == stream.bytesTotal), closePromise);
        });
    });
});