|
'use strict'; |
|
|
|
var logger = require('winston'), |
|
http = require('http'), |
|
cluster = require('cluster'), |
|
util = require('util'), |
|
os = require('os'), |
|
connect = require('connect'), |
|
_ = require('underscore'), |
|
dbg = require('debug')('mockSrv'), |
|
exitCode = { ok: 0, fatal: -1, servStartupErr: -5, usage: 10 }, |
|
optimist = require('optimist') |
|
.alias('h', 'help') |
|
.describe('logLevel', 'Controls the verbosity of the ErrorLog') |
|
.describe('workers', 'The number of worker processes') |
|
.describe('cluster', 'Enable cluster') |
|
.describe('port', 'Set the server port number'); |
|
|
|
function startupServ(options) { |
|
var srv, started, app, mockRepBuf, mockRepBufLen; |
|
|
|
/* create http server */ |
|
mockRepBuf = '01234567890123456789012345678901234567890123456789'; |
|
_.times(10, function () { mockRepBuf += mockRepBuf; }); |
|
mockRepBufLen = mockRepBuf.length; |
|
logger.debug('Mock repBuf is created. (len=%d)', mockRepBufLen); |
|
started = false; |
|
app = connect(); |
|
if (options.reqLogger) { |
|
/* enable request logger */ |
|
app.use(connect.logger('dev')); |
|
} |
|
app.use(connect.query()) |
|
.use('/basic-auth', connect.basicAuth(function(user, pass){ |
|
dbg('basic-auth request (user=%s; pass=%s; pid=%d)', |
|
user, pass, process.pid); |
|
return user === 'mock' && pass === 'mock'; |
|
})) |
|
.use('/basic-auth', function (req, res) { |
|
dbg('basic-auth passed'); |
|
res.writeHead(200, { 'Content-Type': 'text/plain', 'Server': 'mserv' }); |
|
res.end('Authorized'); |
|
}) |
|
.use('/get-data', function(req, res) { |
|
var repLen, repDelay; |
|
|
|
/* check parameters */ |
|
repLen = req.query.len || 1024; |
|
repLen = Math.max(repLen, 1); |
|
repDelay = req.query.delay || 0; |
|
dbg('get-data request (len=%d, delay=%d)', repLen, repDelay); |
|
|
|
/* send data to client */ |
|
function sndData() { |
|
var sndLen; |
|
res.writeHead(200, { 'Content-Type': 'text/plain', 'Server': 'mserv' }); |
|
for (sndLen = 0; sndLen < repLen;) { |
|
if ((mockRepBufLen + sndLen) > repLen) { |
|
/* the last piece */ |
|
res.write(mockRepBuf.substr(0, repLen - sndLen)); |
|
sndLen = repLen; |
|
} |
|
else { |
|
res.write(mockRepBuf); |
|
sndLen += mockRepBufLen; |
|
} |
|
} |
|
res.end(); |
|
} |
|
if (repDelay <= 0) { |
|
sndData(); |
|
} |
|
else { |
|
setTimeout(sndData, repDelay); |
|
} |
|
}) |
|
.use(function(req, res) { |
|
dbg('http req, pid %d', process.pid); |
|
res.writeHead(200, { 'Content-Type': 'text/plain', 'Server': 'mserv' }); |
|
res.end(util.format('HTTP(s) Mock Server. PID=%d\n', process.pid)); |
|
}); |
|
srv = http.createServer(app); |
|
srv.on('error', function (err) { |
|
logger.error('Server error: %s', err.toString()); |
|
if (!started) { |
|
logger.error('Server startup failed.'); |
|
process.exit(exitCode.servStartupErr); |
|
} |
|
}).on('close', function () { |
|
logger.debug('Server closed. (pid=%d)', process.pid); |
|
}); |
|
srv.listen(options.port, function () { |
|
started = true; |
|
logger.info('Server started. (Port=%d)', options.port); |
|
}); |
|
} |
|
|
|
(function (argv) { |
|
var workers, srvOpts; |
|
|
|
if (argv.help) { |
|
optimist.showHelp(); |
|
process.exit(exitCode.usage); |
|
} |
|
|
|
/* startup logger */ |
|
logger.cli(); |
|
logger['default'].transports.console.level = argv.logLevel || 'debug'; |
|
logger['default'].transports.console.timestamp = true; |
|
|
|
if (argv.cluster && cluster.isMaster) { |
|
logger.debug('Master process is creating the workers.'); |
|
workers = argv.workers || os.cpus().length; |
|
_.times(Math.max(workers, 1), function () { |
|
var wrk = cluster.fork(); |
|
logger.debug('The worker(%d) has been created.', wrk.id); |
|
}); |
|
cluster.on('exit', function (worker, code, signal) { |
|
logger.info('The worker(%d) exited. (pid=%d, code=%d, signal=%d)', |
|
worker.id, worker.process.pid, code, signal); |
|
}); |
|
} |
|
else { |
|
/* create the server */ |
|
srvOpts = { |
|
port: argv.port || 2333, |
|
reqLogger: argv.reqLogger |
|
}; |
|
logger.debug('Worker process(%d) is creating the server: %j', |
|
process.pid, srvOpts, {}); |
|
startupServ(srvOpts); |
|
} |
|
})(optimist.argv); |