mirror of https://github.com/mthenw/frontail.git
parent
c3fbf35568
commit
9ace721324
62
index.js
62
index.js
|
@ -3,43 +3,18 @@
|
|||
var connect = require('connect');
|
||||
var cookieParser = require('cookie');
|
||||
var crypto = require('crypto');
|
||||
var daemon = require('daemon');
|
||||
var fs = require('fs');
|
||||
var program = require('commander');
|
||||
var sanitizer = require('validator').sanitize;
|
||||
var socketio = require('socket.io');
|
||||
var tail = require('./lib/tail');
|
||||
var connectBuilder = require('./lib/connect_builder');
|
||||
var program = require('./lib/options_parser');
|
||||
var serverBuilder = require('./lib/server_builder');
|
||||
var daemonize = require('./lib/daemonize');
|
||||
|
||||
program
|
||||
.version(require('./package.json').version)
|
||||
.usage('[options] [file ...]')
|
||||
.option('-h, --host <host>', 'listening host, default 0.0.0.0', String, '0.0.0.0')
|
||||
.option('-p, --port <port>', 'listening port, default 9001', Number, 9001)
|
||||
.option('-n, --number <number>', 'starting lines number, default 10', Number, 10)
|
||||
.option('-l, --lines <lines>', 'number on lines stored in browser, default 2000', Number, 2000)
|
||||
.option('-t, --theme <theme>', 'name of the theme (default, dark)', String, 'default')
|
||||
.option('-d, --daemonize', 'run as daemon')
|
||||
.option('-U, --user <username>',
|
||||
'Basic Authentication username, option works only along with -P option', String, false)
|
||||
.option('-P, --password <password>',
|
||||
'Basic Authentication password, option works only along with -U option', String, false)
|
||||
.option('-k, --key <key.pem>',
|
||||
'Private Key for HTTPS, option works only along with -c option',
|
||||
String, false)
|
||||
.option('-c, --certificate <cert.pem>',
|
||||
'Certificate for HTTPS, option works only along with -k option',
|
||||
String, false)
|
||||
.option('--pid-path <path>',
|
||||
'if run as daemon file that will store the process id, default /var/run/frontail.pid',
|
||||
String, '/var/run/frontail.pid')
|
||||
.option('--log-path <path>', 'if run as daemon file that will be used as a log, default /dev/null',
|
||||
String, '/dev/null')
|
||||
.option('--ui-hide-topbar', 'hide topbar (log file name and search box)')
|
||||
.option('--ui-no-indent', 'don\'t indent log lines')
|
||||
.parse(process.argv);
|
||||
|
||||
/**
|
||||
* Parse args
|
||||
*/
|
||||
program.parse(process.argv);
|
||||
if (program.args.length === 0) {
|
||||
console.error('Arguments needed, use --help');
|
||||
process.exit();
|
||||
|
@ -56,27 +31,10 @@ var files = program.args.join(' ');
|
|||
var filesNamespace = crypto.createHash('md5').update(files).digest('hex');
|
||||
|
||||
if (program.daemonize) {
|
||||
/**
|
||||
* Daemonize process
|
||||
*/
|
||||
var logFile = fs.openSync(program.logPath, 'a');
|
||||
var args = ['-p', program.port, '-n', program.number, '-l', program.lines, '-t', program.theme];
|
||||
|
||||
if (doAuthorization) {
|
||||
args = args.concat(['-U', program.user, '-P', program.password]);
|
||||
}
|
||||
|
||||
args = args.concat(program.args);
|
||||
|
||||
var proc = daemon.daemon(
|
||||
__filename,
|
||||
args,
|
||||
{
|
||||
stdout: logFile,
|
||||
stderr: logFile
|
||||
}
|
||||
);
|
||||
fs.writeFileSync(program.pidPath, proc.pid);
|
||||
daemonize(__filename, program, {
|
||||
doAuthorization: doAuthorization,
|
||||
doSecure: doSecure
|
||||
});
|
||||
} else {
|
||||
/**
|
||||
* HTTP(s) server setup
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
'use strict';
|
||||
|
||||
var daemon = require('daemon');
|
||||
var fs = require('fs');
|
||||
|
||||
var defaultOptions = {
|
||||
doAuthorization: false,
|
||||
doSecure: false
|
||||
};
|
||||
|
||||
module.exports = function (script, params, options) {
|
||||
options = options || defaultOptions;
|
||||
|
||||
var logFile = fs.openSync(params.logPath, 'a');
|
||||
|
||||
var args = [
|
||||
'-h', params.host,
|
||||
'-p', params.port,
|
||||
'-n', params.number,
|
||||
'-l', params.lines,
|
||||
'-t', params.theme
|
||||
];
|
||||
|
||||
if (options.doAuthorization) {
|
||||
args.push(
|
||||
'-U', params.user,
|
||||
'-P', params.password
|
||||
);
|
||||
}
|
||||
|
||||
if (options.doSecure) {
|
||||
args.push(
|
||||
'-k', params.key,
|
||||
'-c', params.certificate
|
||||
);
|
||||
}
|
||||
|
||||
if (params.uiHideTopbar) {
|
||||
args.push('--ui-hide-topbar');
|
||||
}
|
||||
|
||||
if (!params.uiIndent) {
|
||||
args.push('--ui-no-indent');
|
||||
}
|
||||
|
||||
args = args.concat(params.args);
|
||||
|
||||
var proc = daemon.daemon(script, args, {
|
||||
stdout: logFile,
|
||||
stderr: logFile
|
||||
});
|
||||
|
||||
fs.writeFileSync(params.pidPath, proc.pid);
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
var program = require('commander');
|
||||
|
||||
program
|
||||
.version(require('../package.json').version)
|
||||
.usage('[options] [file ...]')
|
||||
.option('-h, --host <host>', 'listening host, default 0.0.0.0', String, '0.0.0.0')
|
||||
.option('-p, --port <port>', 'listening port, default 9001', Number, 9001)
|
||||
.option('-n, --number <number>', 'starting lines number, default 10', Number, 10)
|
||||
.option('-l, --lines <lines>', 'number on lines stored in browser, default 2000', Number, 2000)
|
||||
.option('-t, --theme <theme>', 'name of the theme (default, dark)', String, 'default')
|
||||
.option('-d, --daemonize', 'run as daemon')
|
||||
.option('-U, --user <username>',
|
||||
'Basic Authentication username, option works only along with -P option', String, false)
|
||||
.option('-P, --password <password>',
|
||||
'Basic Authentication password, option works only along with -U option', String, false)
|
||||
.option('-k, --key <key.pem>',
|
||||
'Private Key for HTTPS, option works only along with -c option',
|
||||
String, false)
|
||||
.option('-c, --certificate <cert.pem>',
|
||||
'Certificate for HTTPS, option works only along with -k option',
|
||||
String, false)
|
||||
.option('--pid-path <path>',
|
||||
'if run as daemon file that will store the process id, default /var/run/frontail.pid',
|
||||
String, '/var/run/frontail.pid')
|
||||
.option('--log-path <path>', 'if run as daemon file that will be used as a log, default /dev/null',
|
||||
String, '/dev/null')
|
||||
.option('--ui-hide-topbar', 'hide topbar (log file name and search box)')
|
||||
.option('--ui-no-indent', 'don\'t indent log lines');
|
||||
|
||||
module.exports = program;
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "frontail",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"description": "realtime log stream in the browser",
|
||||
"homepage": "https://github.com/mthenw/frontail",
|
||||
"author": "Maciej Winnicki <maciej.winnicki@gmail.com>",
|
||||
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"jshint": "~2.3.0",
|
||||
"should": "~2.0.2",
|
||||
"should": "~3.3.2",
|
||||
"mocha": "~1.13.0",
|
||||
"temp": "~0.6.0",
|
||||
"sinon": "~1.7.3",
|
||||
|
|
|
@ -70,7 +70,7 @@ describe('connectBuilder', function () {
|
|||
.expect('<head><title>/testfile</title></head>', done);
|
||||
});
|
||||
|
||||
it('builds app that sets socket.io namespace based on files', function (done) {
|
||||
it('should build app that sets socket.io namespace based on files', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_ns', '/testfile', 'ns', 'dark')
|
||||
.build();
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
'use strict';
|
||||
|
||||
require('should');
|
||||
var daemon = require('daemon');
|
||||
var optionsParser = require('../lib/options_parser');
|
||||
var daemonize = require('../lib/daemonize');
|
||||
var sinon = require('sinon');
|
||||
var fs = require('fs');
|
||||
|
||||
describe('daemonize', function () {
|
||||
beforeEach(function () {
|
||||
sinon.stub(daemon, 'daemon');
|
||||
daemon.daemon.returns({pid: 1000});
|
||||
sinon.stub(fs, 'writeFileSync');
|
||||
sinon.stub(fs, 'openSync');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
daemon.daemon.restore();
|
||||
fs.writeFileSync.restore();
|
||||
fs.openSync.restore();
|
||||
});
|
||||
|
||||
describe('should daemon', function () {
|
||||
it('current script', function () {
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[0].should.match('script');
|
||||
});
|
||||
|
||||
it('with hostname', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-h', '127.0.0.1']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-h', '127.0.0.1']);
|
||||
});
|
||||
|
||||
it('with port', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-p', '80']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-p', 80]);
|
||||
});
|
||||
|
||||
it('with lines number', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-n', '1']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-n', 1]);
|
||||
});
|
||||
|
||||
it('with lines stored in browser', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-l', '1']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-l', 1]);
|
||||
});
|
||||
|
||||
it('with theme', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-t', 'dark']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-t', 'dark']);
|
||||
});
|
||||
|
||||
it('with authorization', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-U', 'user', '-P', 'passw0rd']);
|
||||
|
||||
daemonize('script', optionsParser, {doAuthorization: true});
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-U', 'user', '-P', 'passw0rd']);
|
||||
});
|
||||
|
||||
it('without authorization if option doAuthorization not passed', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-U', 'user', '-P', 'passw0rd']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.not.containDeep(['-U', 'user', '-P', 'passw0rd']);
|
||||
});
|
||||
|
||||
it('with secure connection', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-k', 'key.file', '-c', 'cert.file']);
|
||||
|
||||
daemonize('script', optionsParser, {doSecure: true});
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-k', 'key.file', '-c', 'cert.file']);
|
||||
});
|
||||
|
||||
it('without secure connection if option doSecure not passed', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '-k', 'key.file', '-c', 'cert.file']);
|
||||
|
||||
daemonize('script', optionsParser, {doSecure: true});
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['-k', 'key.file', '-c', 'cert.file']);
|
||||
});
|
||||
|
||||
it('with hide-topbar option', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '--ui-hide-topbar']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['--ui-hide-topbar']);
|
||||
});
|
||||
|
||||
it('with no-indent option', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '--ui-no-indent']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['--ui-no-indent']);
|
||||
});
|
||||
|
||||
it('with file to tail', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '/path/to/file']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
daemon.daemon.lastCall.args[1].should.containDeep(['/path/to/file']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should write pid to pidfile', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '--pid-path', '/path/to/pid']);
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
fs.writeFileSync.lastCall.args[0].should.be.equal('/path/to/pid');
|
||||
fs.writeFileSync.lastCall.args[1].should.be.equal(1000);
|
||||
});
|
||||
|
||||
it('should log to file', function () {
|
||||
optionsParser.parse(['node', '/path/to/frontail', '--log-path', '/path/to/log']);
|
||||
fs.openSync.returns('file');
|
||||
|
||||
daemonize('script', optionsParser);
|
||||
|
||||
fs.openSync.lastCall.args[0].should.equal('/path/to/log');
|
||||
fs.openSync.lastCall.args[1].should.equal('a');
|
||||
daemon.daemon.lastCall.args[2].should.eql({
|
||||
stdout: 'file',
|
||||
stderr: 'file'
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue