I'm new to Node.js and I am writing a client to consume a text-based TCP stream from a server. For testing purposes, I want to simulate the server in Node so I can test with no other dependencies.
I have a file of captured data that looks like:
$X,... <-- broadcast every second
$A,...
$A,...
$B,...
$X,... <-- broadcast every second
$A,...
$A,...
$C,...
$X,... <-- broadcast every second
The server emits a line starting with $X every second. The other records are broadcast as events happen. How can I modify my network server below to broadcast this data and throttle it so it emits one line at a time and pauses for one second every time it encounters a line starting with $X?
Here is my code so far which reads in the data and broadcasts it over a port:
var http = require('http')
, fs = require('fs')
;
var server = http.createServer(function (req, res) {
var stream = fs.createReadStream(__dirname + '/data.txt');
stream.pipe(res);
});
server.listen(8000);
console.log('server running on 8000');
This works but obviously just streams out the whole file at warp speed. What I want is to spit out all of the lines from one $X to the next, pause for one second (close enough for testing purposes) and then continue to the next $X and so on like:
> telnet 127.0.0.1 8000
$X,...
$A,...
$A,...
$B,...
(output would pause for one second)
$X,...
$A,...
$A,...
$C,...
(output would pause for one second)
$X,...
...
In my example above, the broadcast always starts from the beginning of data.txt when I connect with a client. Ideally, this server would keep broadcasting this data in a loop, allowing clients to disconnect and reconnect at any time and start receiving data wherever the server simulator was currently at.
(PS - data.txt is a relatively small file, < 1MB in most cases)
UPDATE -
Thanks to Laurent's pointer, I was able to get it working with the following:
var net = require('net'),
fs = require('fs'),
async = require('async');
var server = net.createServer(function (socket) {
var lines = fs.readFileSync(__dirname + '/data-small.txt').toString().split(/\n+/);
async.whilst(
function () {
return lines.length > 0;
},
function (done) {
var line = lines.shift();
socket.write(line + '\r\n');
setTimeout(done, /^\$X,/.test(line) ? 1000 : 0);
},
function (err) {
// no more lines present
socket.end();
});
});
server.listen(8000);
console.log('server running on 8000');
I'm now getting a blast of lines until an $X, a 1s pause, and then it continues! Thanks!
Drilling into my 2nd part: is there a way to synchronize output of this faux server so all clients see the same output regardless of when they connect?
If you want to keep all clients in sync, you need to do something entirely different. Here's a starting point. Also, it seems like the net module would be a better fit.
var net = require('net'),
fs = require('fs'),
_ = require('underscore');
var current = 0,
sockets = [];
// dirty parser for blocs
var data = fs.readFileSync(__dirname + '/data.txt').toString(),
blocs = _.chain(data.split(/\$X,/)).compact().map(function (bloc) {
return '$X,' + bloc;
}).value();
function streamBloc() {
console.log('writing bloc #' + current + ' to ' + sockets.length + ' sockets');
_(sockets).each(function (socket) {
socket.write(blocs[current]);
});
current = (current + 1) % blocs.length;
setTimeout(streamBloc, 1000);
}
var server = net.createServer(function (socket) {
console.log('incoming connection');
// immediately write current bloc
socket.write(blocs[current]);
// add to sockets so that it receive future blocs
sockets.push(socket);
// cleanup when the client leaves
socket.on('end', function () {
sockets = _(sockets).without(socket);
});
}).listen(8000, function () {
console.log('server listening on port 8000');
});
streamBloc();