diff --git a/index.js b/index.js index 0d3d9b8..9f340d7 100644 --- a/index.js +++ b/index.js @@ -1,20 +1,17 @@ -var program = require('commander'); -var https = require('https'); -var http = require('http'); -var fs = require('fs'); -var socketio = require('socket.io'); -var spawn = require('child_process').spawn; var connect = require('connect'); var cookieParser = require('cookie'); -var sanitizer = require('validator').sanitize; var daemon = require('daemon'); +var fs = require('fs'); +var http = require('http'); +var https = require('https'); +var program = require('commander'); +var sanitizer = require('validator').sanitize; +var socketio = require('socket.io'); +var tail = require('./lib/tail'); (function () { 'use strict'; - /** - * Parse arg - */ program .version(require('./package.json').version) .usage('[options] [file ...]') @@ -39,15 +36,12 @@ var daemon = require('daemon'); * Validate args */ var doAuthorization = false; - var files = []; var sessionSecret = null; var sessionKey = null; if (program.args.length === 0) { console.error('Arguments needed, use --help'); process.exit(); } else { - files = program.args; - if (program.user && program.password) { doAuthorization = true; sessionSecret = String(+new Date()) + Math.random(); @@ -66,7 +60,7 @@ var daemon = require('daemon'); args = args.concat(['-U', program.user, '-P', program.password]); } - args = args.concat(files); + args = args.concat(program.args); var proc = daemon.daemon( __filename, @@ -102,7 +96,7 @@ var daemon = require('daemon'); } else { res.writeHead(200, {'Content-Type': 'text/html'}); res.end(data.toString('utf-8').replace( - /__TITLE__/g, 'tail -F ' + files.join(' ')), 'utf-8' + /__TITLE__/g, 'tail -F ' + program.args.join(' ')), 'utf-8' ); } }); @@ -143,25 +137,20 @@ var daemon = require('daemon'); /** * When connected send starting data */ + var tailer = tail(program.args, {buffer: program.number}); io.sockets.on('connection', function (socket) { socket.emit('options:lines', program.lines); - var tail = spawn('tail', ['-n', program.number].concat(files)); - tail.stdout.on('data', function (data) { - var lines = sanitizer(data.toString('utf-8')).xss().split('\n'); - lines.pop(); - socket.emit('lines', lines); + tailer.getBuffer().forEach(function (line) { + socket.emit('line', line); }); }); /** * Send incoming data */ - var tail = spawn('tail', ['-F'].concat(files)); - tail.stdout.on('data', function (data) { - var lines = sanitizer(data.toString('utf-8')).xss().split('\n'); - lines.pop(); - io.sockets.emit('lines', lines); + tailer.on('line', function (line) { + io.sockets.emit('line', sanitizer(line).xss()); }); } })(); diff --git a/lib/tail.js b/lib/tail.js index 658a4b9..af194c5 100644 --- a/lib/tail.js +++ b/lib/tail.js @@ -1,25 +1,45 @@ +var EventEmitter = require('events').EventEmitter; +var spawn = require('child_process').spawn; +var util = require('util'); + (function () { 'use strict'; - var EventEmitter = require('events').EventEmitter; - var util = require('util'); - var spawn = require('child_process').spawn; - - var Tail = function (path) { + var Tail = function (path, options) { EventEmitter.call(this); + this.buffer = []; + this.options = options || {buffer: 0}; + var self = this; var tail = spawn('tail', ['-F'].concat(path)); - tail.stdout.on('data', function (data) { - var line = data.toString('utf-8'); - self.emit('line', line); + + var lines = data.toString('utf-8'); + lines = lines.split('\n'); + lines.pop(); + lines.forEach(function (line) { + if (self.options.buffer) { + if (self.buffer.length === self.options.buffer) { + self.buffer.shift(); + } + self.buffer.push(line); + } + self.emit('line', line); + }); + }); + + process.on('exit', function () { + tail.kill(); }); }; util.inherits(Tail, EventEmitter); + Tail.prototype.getBuffer = function () { + return this.buffer; + }; - module.exports = function (path) { - return new Tail(path); + module.exports = function (path, options) { + return new Tail(path, options); }; })(); diff --git a/lib/web/assets/app.js b/lib/web/assets/app.js index 6592861..5c601c1 100644 --- a/lib/web/assets/app.js +++ b/lib/web/assets/app.js @@ -95,10 +95,8 @@ window.App = (function (window, document, io) { .on('options:lines', function (limit) { _linesLimit = limit; }) - .on('lines', function (lines) { - for (var i = 0; i < lines.length; i += 1) { - that.log(lines[i]); - } + .on('line', function (line) { + that.log(line); }); // Elements diff --git a/test/tail.js b/test/tail.js index dd9da2b..1b7c9ba 100644 --- a/test/tail.js +++ b/test/tail.js @@ -11,14 +11,33 @@ temp.track(); it('should call event line if new line appear in file', function (done) { - temp.open('test', function (err, info) { + temp.open('', function (err, info) { tail(info.path).on('line', function (line) { line.should.equal('testline'); done(); }); - fs.write(info.fd, 'testline'); - fs.close(info.fd); + fs.writeSync(info.fd, 'testline\n'); + fs.closeSync(info.fd); + }); + }); + + it('should buffer lines on start', function (done) { + temp.open('', function (err, info) { + fs.writeSync(info.fd, 'testline1\n'); + fs.writeSync(info.fd, 'testline2\n'); + fs.writeSync(info.fd, 'testline3\n'); + fs.closeSync(info.fd); + + var calls = 0; + var tailer = tail(info.path, {buffer: 2}).on('line', function () { + calls += 1; + + if (calls === 3) { + tailer.getBuffer().should.eql(['testline2', 'testline3']); + done(); + } + }); }); }); });