1

I'm trying to make a node server capable of sending all file names found in a directory (recursively) to a client over web sockets. The idea here is that the directory is quite large and I want to start getting results on the client side before the entire directory is read.

I imagine something like this should do it:

Server side:

var express = require('express'),
  app = express(),
  server = require('http').createServer(app),
  io = require('socket.io').listen(server),
  fs = require('graceful-fs'),
  rootDirectory = "/some/absolute/path";
  port = 3000,
  recursivelyReadDirectory = function (rootDirectory) {
    // TODO
  },
  sync = io
    .of('/sync')
    .on('connection', function (socket) {
      recursivelyReadDirectory(rootDirectory).on('chunk', function (filename) {
       socket.emit('filename', filename);
      });
    });
server.listen(port);

Client side:

var socket = io.connect('http://localhost:3000/sync');
socket.on('filename', function (filename) {
  console.log(filename);
});

So if I had the following in /some/absolue/path on the server:

.
|-- a
|   `-- c.txt
`-- b.txt

I would expect the client side script to log

c.txt
b.txt

or

b.txt
c.txt
hippietrail
  • 15,848
  • 18
  • 99
  • 158
Shawn
  • 10,931
  • 18
  • 81
  • 126

1 Answers1

0

I created a small working example:

app.js

var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server),
    fs = require('fs'),
    rootDirectory = "c:/tmp",
    port = 3000,
    recursivelyReadDirectory = function (rootDirectory) {
        // TODO
    };

app.use(express.static(__dirname + '/public'));

var walk = function (dir, action, done) {

    // this flag will indicate if an error occured (in this case we don't want to go on walking the tree)
    var dead = false;

    // this flag will store the number of pending async operations
    var pending = 0;

    var fail = function (err) {
        if (!dead) {
            dead = true;
            done(err);
        }
    };

    var checkSuccess = function () {
        if (!dead && pending == 0) {
            done();
        }
    };

    var performAction = function (file, stat) {
        if (!dead) {
            try {
                action(file, stat);
            }
            catch (error) {
                fail(error);
            }
        }
    };

    // this function will recursively explore one directory in the context defined by the variables above
    var dive = function (dir) {
        pending++; // async operation starting after this line
        fs.readdir(dir, function (err, list) {
            if (!dead) { // if we are already dead, we don't do anything
                if (err) {
                    fail(err); // if an error occured, let's fail
                }
                else { // iterate over the files
                    list.forEach(function (file) {
                        if (!dead) { // if we are already dead, we don't do anything
                            var path = dir + "/" + file;
                            pending++; // async operation starting after this line
                            fs.stat(path, function (err, stat) {
                                if (!dead) { // if we are already dead, we don't do anything
                                    if (err) {
                                        fail(err); // if an error occured, let's fail
                                    }
                                    else {
                                        if (stat && stat.isDirectory()) {
                                            dive(path); // it's a directory, let's explore recursively
                                        }
                                        else {
                                            performAction(path, stat); // it's not a directory, just perform the action
                                        }
                                        pending--;
                                        checkSuccess(); // async operation complete
                                    }
                                }
                            });
                        }
                    });
                    pending--;
                    checkSuccess(); // async operation complete
                }
            }
        });
    };

    // start exploration
    dive(dir);
};

io
    .on('connection', function (socket) {
        walk(rootDirectory, function (path, stat) {
            console.log(path);
            socket.emit('filename', path);
        }, function (err) {
            if (err) {
                socket.emit('error', 'Something went wrong');
            } else {
                socket.emit('done');
            }
        });
    });
server.listen(port);

index.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect('http://localhost');
    socket.on('filename', function (data) {
        console.log(data);
    });
</script>
</body>
</html>
Werner Kvalem Vesterås
  • 10,226
  • 5
  • 43
  • 50