mirror of
https://github.com/Hopiu/webapi-eca.git
synced 2026-03-16 22:10:31 +00:00
Huge refactoring of architecture started
This commit is contained in:
parent
92ab16ba74
commit
264ef6eeb6
25 changed files with 742 additions and 411 deletions
|
|
@ -7,26 +7,26 @@ Configuration
|
|||
###
|
||||
|
||||
# **Requires:**
|
||||
|
||||
# - [Logging](logging.html)
|
||||
log = require './logging'
|
||||
|
||||
# - Node.js Modules: [fs](http://nodejs.org/api/fs.html) and
|
||||
# [path](http://nodejs.org/api/path.html)
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
|
||||
###
|
||||
##Module call
|
||||
Module call
|
||||
-----------
|
||||
|
||||
Calling the module as a function will act as a constructor and load the config file.
|
||||
It is possible to hand an args object with the properties nolog (true if no outputs shall
|
||||
be generated) and configPath for a custom configuration file path.
|
||||
|
||||
Calling the module as a function will make it look for the `configPath` property in the
|
||||
args object and then try to load a config file from that relative path.
|
||||
@param {Object} args
|
||||
###
|
||||
exports = module.exports = ( args ) ->
|
||||
exports = module.exports = ( args ) =>
|
||||
args = args ? {}
|
||||
log args
|
||||
if typeof args.configPath is 'string'
|
||||
if args.nolog
|
||||
@nolog = true
|
||||
if args.configPath
|
||||
loadConfigFile args.configPath
|
||||
else
|
||||
loadConfigFile path.join 'config', 'config.json'
|
||||
|
|
@ -41,20 +41,25 @@ Reads the config file synchronously from the file system and try to parse it.
|
|||
###
|
||||
loadConfigFile = ( configPath ) =>
|
||||
@config = null
|
||||
confProperties = [
|
||||
'log'
|
||||
'http-port'
|
||||
'db-port'
|
||||
'crypto-key'
|
||||
]
|
||||
#TODO Try to get rid of crypto key
|
||||
try
|
||||
@config = JSON.parse fs.readFileSync path.resolve __dirname, '..', configPath
|
||||
if @config and @config.http_port and @config.db_port and
|
||||
@config.crypto_key and @config.session_secret
|
||||
log.print 'CF', 'config file loaded successfully'
|
||||
else
|
||||
log.error 'CF', new Error """Missing property in config file, requires:
|
||||
- http_port
|
||||
- db_port
|
||||
- crypto_key
|
||||
- session_secret"""
|
||||
isReady = true
|
||||
for prop in confProperties
|
||||
if !@config[prop]
|
||||
isReady = false
|
||||
if not isReady and not @nolog
|
||||
console.error """Missing property in config file, requires:
|
||||
- #{ confProperties.join "\n -" }"""
|
||||
catch e
|
||||
e.addInfo = 'no config ready'
|
||||
log.error 'CF', e
|
||||
if not @nolog
|
||||
console.error "Failed loading config file: #{ e.message }"
|
||||
|
||||
|
||||
###
|
||||
|
|
@ -77,25 +82,25 @@ exports.isReady = => @config?
|
|||
|
||||
@public getHttpPort()
|
||||
###
|
||||
exports.getHttpPort = -> fetchProp 'http_port'
|
||||
exports.getHttpPort = -> fetchProp 'http-port'
|
||||
|
||||
###
|
||||
***Returns*** the DB port*
|
||||
|
||||
@public getDBPort()
|
||||
###
|
||||
exports.getDBPort = -> fetchProp 'db_port'
|
||||
exports.getDBPort = -> fetchProp 'db-port'
|
||||
|
||||
###
|
||||
***Returns*** the log conf object
|
||||
|
||||
@public getLogConf()
|
||||
###
|
||||
exports.getLogConf = -> fetchProp 'log'
|
||||
|
||||
###
|
||||
***Returns*** the crypto key
|
||||
|
||||
@public getCryptoKey()
|
||||
###
|
||||
exports.getCryptoKey = -> fetchProp 'crypto_key'
|
||||
|
||||
###
|
||||
***Returns*** the session secret
|
||||
|
||||
@public getSessionSecret()
|
||||
###
|
||||
exports.getSessionSecret = -> fetchProp 'session_secret'
|
||||
exports.getCryptoKey = -> fetchProp 'crypto-key'
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ log = require './logging'
|
|||
|
||||
# - [Config](config.html)
|
||||
config = require './config'
|
||||
# TODO remove config
|
||||
|
||||
# - [User Handler](user_handler.html)
|
||||
requestHandler = require './request_handler'
|
||||
|
|
@ -53,10 +54,14 @@ Adds the shutdown handler to the admin commands.
|
|||
@public addHandlers( *fShutDown* )
|
||||
###
|
||||
exports.addHandlers = ( fShutDown ) ->
|
||||
requestHandler.addHandlers fShutDown
|
||||
requestHandler.addShutdownHandler fShutDown
|
||||
# Add cookie support for session handling.
|
||||
app.use express.cookieParser()
|
||||
app.use express.session { secret: config.getSessionSecret() }
|
||||
#TODO This needs to be fixed!
|
||||
sess_sec = "149u*y8C:@kmN/520Gt\\v'+KFBnQ!\\r<>5X/xRI`sT<Iw"
|
||||
app.use express.session { secret: sess_sec }
|
||||
# app.use express.session { secret: config.getSessionSecret() }
|
||||
|
||||
#At the moment there's no redis session backbone (didn't work straight away)
|
||||
log.print 'HL', 'no session backbone'
|
||||
|
||||
|
|
|
|||
59
coffee/new_logging.coffee
Normal file
59
coffee/new_logging.coffee
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
# Logging
|
||||
# =======
|
||||
# A Helper to handle logging.
|
||||
|
||||
# **Requires:**
|
||||
# - Node.js Module(s): [path](http://nodejs.org/api/path.html)
|
||||
path = require 'path'
|
||||
|
||||
# - External Module(s): [bunyan](https://github.com/trentm/node-bunyan)
|
||||
bunyan = require 'bunyan'
|
||||
|
||||
###
|
||||
Module call
|
||||
-----------
|
||||
|
||||
Calling the module as a function will act as a constructor and load the config file.
|
||||
It is possible to hand an args object with the properties nolog (true if no outputs shall
|
||||
be generated) and configPath for a custom configuration file path.
|
||||
|
||||
@param {Object} args
|
||||
###
|
||||
exports = module.exports = ( args ) =>
|
||||
emptylog =
|
||||
{
|
||||
info: () ->
|
||||
warn: () ->
|
||||
error: () ->
|
||||
}
|
||||
args = args ? {}
|
||||
if args.nolog
|
||||
emptylog
|
||||
else
|
||||
try
|
||||
opt =
|
||||
name: "webapi-eca"
|
||||
if args['mode'] is 'development'
|
||||
opt.src = true
|
||||
if args['file-path']
|
||||
@logPath = path.resolve __dirname, '..', 'logs', args['file-path']
|
||||
else
|
||||
@logPath = path.resolve __dirname, '..', 'logs', 'server.log'
|
||||
opt.streams = [
|
||||
{
|
||||
level: args['io-level']
|
||||
stream: process.stdout
|
||||
},
|
||||
{
|
||||
level: args['file-level']
|
||||
type: 'rotating-file'
|
||||
path: @logPath
|
||||
period: '1d'
|
||||
count: 3
|
||||
}
|
||||
]
|
||||
bunyan.createLogger opt
|
||||
catch e
|
||||
console.error e
|
||||
emptylog
|
||||
|
|
@ -55,7 +55,7 @@ exports = module.exports = ( args ) =>
|
|||
@ai = new IndexedModules( 'action-invoker', @db )
|
||||
else
|
||||
log.error 'DB', 'Initialization failed because of missing config file!'
|
||||
|
||||
|
||||
###
|
||||
Checks whether the db is connected and passes either an error on failure after
|
||||
ten attempts within five seconds, or nothing on success to the callback(err).
|
||||
|
|
@ -845,4 +845,4 @@ Shuts down the db link.
|
|||
|
||||
@public shutDown()
|
||||
###
|
||||
exports.shutDown = => @db.quit()
|
||||
exports.shutDown = () => @db.quit()
|
||||
|
|
|
|||
|
|
@ -28,14 +28,6 @@ qs = require 'querystring'
|
|||
# [crypto-js](https://github.com/evanvosberg/crypto-js)
|
||||
mustache = require 'mustache'
|
||||
crypto = require 'crypto-js'
|
||||
|
||||
# Prepare the admin command handlers which are invoked via HTTP requests.
|
||||
objAdminCmds =
|
||||
'loadrules': mm.loadRulesFromFS
|
||||
'loadaction': mm.loadActionModuleFromFS
|
||||
'loadactions': mm.loadActionModulesFromFS
|
||||
'loadevent': mm.loadEventModuleFromFS
|
||||
'loadevents': mm.loadEventModulesFromFS
|
||||
|
||||
# Prepare the user command handlers which are invoked via HTTP requests.
|
||||
objUserCmds =
|
||||
|
|
@ -57,15 +49,14 @@ exports = module.exports = ( args ) ->
|
|||
module.exports
|
||||
|
||||
###
|
||||
This allows the parent to add handlers. The event handler will receive
|
||||
the events that were received. The shutdown function will be called if the
|
||||
admin command shutdown is issued.
|
||||
This allows the parent to add the shutdown handler.
|
||||
The shutdown function will be called if the admin command shutdown is issued.
|
||||
|
||||
@public addHandlers( *fShutdown* )
|
||||
@public addShutdownHandler( *fShutdown* )
|
||||
@param {function} fShutdown
|
||||
###
|
||||
exports.addHandlers = ( fShutdown ) =>
|
||||
objAdminCmds.shutdown = ( args, answerHandler ) ->
|
||||
exports.addShutdownHandler = ( fShutdown ) =>
|
||||
@objAdminCmds.shutdown = ( args, answerHandler ) ->
|
||||
answerHandler.answerSuccess 'Shutting down... BYE!'
|
||||
setTimeout fShutdown, 500
|
||||
|
||||
|
|
@ -284,13 +275,13 @@ objects.*
|
|||
|
||||
@public handleAdmin( *req, resp* )
|
||||
###
|
||||
exports.handleAdmin = ( req, resp ) ->
|
||||
exports.handleAdmin = ( req, resp ) =>
|
||||
if req.session and req.session.user
|
||||
if req.session.user.isAdmin is "true"
|
||||
q = req.query
|
||||
log.print 'RH', 'Received admin request: ' + req.originalUrl
|
||||
if q.cmd
|
||||
objAdminCmds[q.cmd]? q, answerHandler req, resp, true
|
||||
@objAdminCmds[q.cmd]? q, answerHandler req, resp, true
|
||||
else
|
||||
resp.send 404, 'Command unknown!'
|
||||
else
|
||||
|
|
|
|||
|
|
@ -5,26 +5,15 @@ Server
|
|||
|
||||
>This is the main module that is used to run the whole server:
|
||||
>
|
||||
> node server [log_type http_port]
|
||||
> node server [opt]
|
||||
>
|
||||
>Valid `log_type`'s are:
|
||||
>
|
||||
>- `0`: standard I/O output (default)
|
||||
>- `1`: log file (server.log)
|
||||
>- `2`: silent
|
||||
>
|
||||
>`http_port` can be set to use another port, than defined in the
|
||||
>[config](config.html) file, to listen to, e.g. used by the test suite.
|
||||
>
|
||||
>
|
||||
|
||||
TODO how about we allow spawning child processes with servers based on address?
|
||||
> See below in the optimist CLI preparation for allowed optional parameters
|
||||
###
|
||||
|
||||
# **Requires:**
|
||||
|
||||
# - [Logging](logging.html)
|
||||
log = require './logging'
|
||||
logger = require './new_logging'
|
||||
|
||||
# - [Configuration](config.html)
|
||||
conf = require './config'
|
||||
|
|
@ -38,9 +27,54 @@ engine = require './engine'
|
|||
# - [HTTP Listener](http_listener.html)
|
||||
http_listener = require './http_listener'
|
||||
|
||||
args = {}
|
||||
# - Node.js Modules: [fs](http://nodejs.org/api/fs.html),
|
||||
# [path](http://nodejs.org/api/path.html)
|
||||
# and [child_process](http://nodejs.org/api/child_process.html)
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
cp = require 'child_process'
|
||||
|
||||
# - External Module: [optimist](https://github.com/substack/node-optimist)
|
||||
optimist = require 'optimist'
|
||||
|
||||
procCmds = {}
|
||||
|
||||
###
|
||||
Let's prepare the optimist CLI
|
||||
###
|
||||
usage = 'This runs your webapi-based ECA engine'
|
||||
opt =
|
||||
'h':
|
||||
alias : 'help',
|
||||
describe: 'Display this'
|
||||
'c':
|
||||
alias : 'config-path',
|
||||
describe: 'Specify a path to a custom configuration file, other than "config/config.json"'
|
||||
'w':
|
||||
alias : 'http-port',
|
||||
describe: 'Specify a HTTP port for the web server'
|
||||
'd':
|
||||
alias : 'db-port',
|
||||
describe: 'Specify a port for the redis DB'
|
||||
'm':
|
||||
alias : 'log-mode',
|
||||
describe: 'Specify a log mode: [development|productive]'
|
||||
'i':
|
||||
alias : 'log-io-level',
|
||||
describe: 'Specify the log level for the I/O'
|
||||
'f':
|
||||
alias : 'log-file-level',
|
||||
describe: 'Specify the log level for the log file'
|
||||
'p':
|
||||
alias : 'log-file-path',
|
||||
describe: 'Specify the path to the log file within the "logs" folder'
|
||||
'n':
|
||||
alias : 'nolog',
|
||||
describe: 'Set this if no output shall be generated'
|
||||
argv = optimist.usage( usage ).options( opt ).argv
|
||||
if argv.help
|
||||
console.log optimist.help()
|
||||
process.exit()
|
||||
|
||||
###
|
||||
Error handling of the express port listener requires special attention,
|
||||
|
|
@ -50,7 +84,7 @@ the port is already in use.
|
|||
process.on 'uncaughtException', ( err ) ->
|
||||
switch err.errno
|
||||
when 'EADDRINUSE'
|
||||
err.addInfo = 'http_port already in use, shutting down!'
|
||||
err.addInfo = 'http-port already in use, shutting down!'
|
||||
log.error 'RS', err
|
||||
shutDown()
|
||||
# else log.error 'RS', err
|
||||
|
|
@ -61,50 +95,63 @@ This function is invoked right after the module is loaded and starts the server.
|
|||
@private init()
|
||||
###
|
||||
init = ->
|
||||
log.print 'RS', 'STARTING SERVER'
|
||||
conf args
|
||||
conf argv.c
|
||||
# > Check whether the config file is ready, which is required to start the server.
|
||||
if !conf.isReady()
|
||||
log.error 'RS', 'Config file not ready!'
|
||||
console.error 'FAIL: Config file not ready! Shutting down...'
|
||||
process.exit()
|
||||
|
||||
# > Fetch the `log_type` argument and post a log about which log type is used.
|
||||
if process.argv.length > 2
|
||||
args.logType = parseInt(process.argv[2]) || 0
|
||||
switch args.logType
|
||||
when 0 then log.print 'RS', 'Log type set to standard I/O output'
|
||||
when 1 then log.print 'RS', 'Log type set to file output'
|
||||
when 2 then log.print 'RS', 'Log type set to silent'
|
||||
else log.print 'RS', 'Unknown log type, using standard I/O'
|
||||
log args
|
||||
else
|
||||
log.print 'RS', 'No log method argument provided, using standard I/O'
|
||||
|
||||
# > Fetch the `http_port` argument
|
||||
if process.argv.length > 3 then args.http_port = parseInt process.argv[3]
|
||||
else log.print 'RS', 'No HTTP port passed, using standard port from config file'
|
||||
|
||||
logconf = conf.getLogConf()
|
||||
if argv.m
|
||||
logconf[ 'mode' ] = argv.m
|
||||
if argv.i
|
||||
logconf[ 'io-level' ] = argv.i
|
||||
if argv.f
|
||||
logconf[ 'file-level' ] = argv.f
|
||||
if argv.p
|
||||
logconf[ 'file-path' ] = argv.p
|
||||
if argv.n
|
||||
logconf[ 'nolog' ] = argv.n
|
||||
try
|
||||
fs.unlinkSync path.resolve __dirname, '..', 'logs', logconf[ 'file-path' ]
|
||||
log = logger logconf
|
||||
log.info 'RS | STARTING SERVER'
|
||||
|
||||
args =
|
||||
logger: log
|
||||
logconf: logconf
|
||||
# > Fetch the `http-port` argument
|
||||
args[ 'http-port' ] = parseInt argv.w || conf.getHttpPort()
|
||||
|
||||
log.print 'RS', 'Initialzing DB'
|
||||
log.info 'RS | Initialzing DB'
|
||||
db args
|
||||
# > We only proceed with the initialization if the DB is ready
|
||||
db.isConnected ( err, result ) ->
|
||||
if !err
|
||||
|
||||
# > Initialize all required modules with the args object.
|
||||
log.print 'RS', 'Initialzing engine'
|
||||
log.info 'RS | Initialzing engine'
|
||||
engine args
|
||||
log.print 'RS', 'Initialzing http listener'
|
||||
log.info 'RS | Initialzing http listener'
|
||||
http_listener args
|
||||
|
||||
# > Distribute handlers between modules to link the application.
|
||||
log.print 'RS', 'Passing handlers to engine'
|
||||
log.info 'RS | Passing handlers to engine'
|
||||
engine.addPersistence db
|
||||
log.print 'RS', 'Passing handlers to http listener'
|
||||
log.info 'RS | Passing handlers to http listener'
|
||||
#TODO engine pushEvent needs to go into redis queue
|
||||
http_listener.addHandlers shutDown
|
||||
#log.print 'RS', 'Passing handlers to module manager'
|
||||
http_listener.addShutdownHandler shutDown
|
||||
#TODO loadAction and addRule will be removed
|
||||
#mm.addHandlers db, engine.loadActionModule, engine.addRule
|
||||
log.info 'RS | For e child process for the event poller'
|
||||
cliArgs = [
|
||||
args.logconf['mode']
|
||||
args.logconf['io-level']
|
||||
args.logconf['file-level']
|
||||
args.logconf['file-path']
|
||||
args.logconf['nolog']
|
||||
]
|
||||
poller = cp.fork path.resolve( __dirname, 'event_poller' ), cliArgs
|
||||
|
||||
###
|
||||
Shuts down the server.
|
||||
|
|
@ -112,7 +159,7 @@ Shuts down the server.
|
|||
@private shutDown()
|
||||
###
|
||||
shutDown = ->
|
||||
log.print 'RS', 'Received shut down command!'
|
||||
log.warn 'RS | Received shut down command!'
|
||||
engine?.shutDown()
|
||||
http_listener?.shutDown()
|
||||
|
||||
|
|
|
|||
|
|
@ -8,28 +8,31 @@ Configuration
|
|||
|
||||
|
||||
(function() {
|
||||
var exports, fetchProp, fs, loadConfigFile, log, path,
|
||||
var exports, fetchProp, fs, loadConfigFile, path,
|
||||
_this = this;
|
||||
|
||||
log = require('./logging');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
/*
|
||||
##Module call
|
||||
Module call
|
||||
-----------
|
||||
|
||||
Calling the module as a function will act as a constructor and load the config file.
|
||||
It is possible to hand an args object with the properties nolog (true if no outputs shall
|
||||
be generated) and configPath for a custom configuration file path.
|
||||
|
||||
Calling the module as a function will make it look for the `configPath` property in the
|
||||
args object and then try to load a config file from that relative path.
|
||||
@param {Object} args
|
||||
*/
|
||||
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
args = args != null ? args : {};
|
||||
log(args);
|
||||
if (typeof args.configPath === 'string') {
|
||||
if (args.nolog) {
|
||||
_this.nolog = true;
|
||||
}
|
||||
if (args.configPath) {
|
||||
loadConfigFile(args.configPath);
|
||||
} else {
|
||||
loadConfigFile(path.join('config', 'config.json'));
|
||||
|
|
@ -47,19 +50,26 @@ Configuration
|
|||
|
||||
|
||||
loadConfigFile = function(configPath) {
|
||||
var e;
|
||||
var confProperties, e, isReady, prop, _i, _len;
|
||||
_this.config = null;
|
||||
confProperties = ['log', 'http-port', 'db-port', 'crypto-key'];
|
||||
try {
|
||||
_this.config = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', configPath)));
|
||||
if (_this.config && _this.config.http_port && _this.config.db_port && _this.config.crypto_key && _this.config.session_secret) {
|
||||
return log.print('CF', 'config file loaded successfully');
|
||||
} else {
|
||||
return log.error('CF', new Error("Missing property in config file, requires:\n- http_port\n- db_port\n- crypto_key\n- session_secret"));
|
||||
isReady = true;
|
||||
for (_i = 0, _len = confProperties.length; _i < _len; _i++) {
|
||||
prop = confProperties[_i];
|
||||
if (!_this.config[prop]) {
|
||||
isReady = false;
|
||||
}
|
||||
}
|
||||
if (!isReady && !_this.nolog) {
|
||||
return console.error("Missing property in config file, requires: \n- " + (confProperties.join("\n -")));
|
||||
}
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
e.addInfo = 'no config ready';
|
||||
return log.error('CF', e);
|
||||
if (!_this.nolog) {
|
||||
return console.error("Failed loading config file: " + e.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -95,7 +105,7 @@ Configuration
|
|||
|
||||
|
||||
exports.getHttpPort = function() {
|
||||
return fetchProp('http_port');
|
||||
return fetchProp('http-port');
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -106,7 +116,18 @@ Configuration
|
|||
|
||||
|
||||
exports.getDBPort = function() {
|
||||
return fetchProp('db_port');
|
||||
return fetchProp('db-port');
|
||||
};
|
||||
|
||||
/*
|
||||
***Returns*** the log conf object
|
||||
|
||||
@public getLogConf()
|
||||
*/
|
||||
|
||||
|
||||
exports.getLogConf = function() {
|
||||
return fetchProp('log');
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -117,18 +138,7 @@ Configuration
|
|||
|
||||
|
||||
exports.getCryptoKey = function() {
|
||||
return fetchProp('crypto_key');
|
||||
};
|
||||
|
||||
/*
|
||||
***Returns*** the session secret
|
||||
|
||||
@public getSessionSecret()
|
||||
*/
|
||||
|
||||
|
||||
exports.getSessionSecret = function() {
|
||||
return fetchProp('session_secret');
|
||||
return fetchProp('crypto-key');
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
var path = require('path'),
|
||||
cp = require('child_process'),
|
||||
log = require('./logging'),
|
||||
qEvents = new (require('./queue')).Queue(), //TODO export queue into redis
|
||||
// qEvents = new (require('./queue')).Queue(), //TODO export queue into redis
|
||||
regex = /\$X\.[\w\.\[\]]*/g, // find properties of $X
|
||||
listRules = {},
|
||||
listActionModules = {},
|
||||
isRunning = true,
|
||||
ml, poller, db;
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
exports = module.exports = function( args ) {
|
||||
args = args || {};
|
||||
log(args);
|
||||
ml = require('./module_loader')(args);
|
||||
poller = cp.fork(path.resolve(__dirname, 'eventpoller'), [log.getLogType()]);
|
||||
poller.on('message', function(evt) {
|
||||
exports.pushEvent(evt);
|
||||
});
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
log = require('./logging'),
|
||||
var logger = require('./new_logging'),
|
||||
listMessageActions = {},
|
||||
listAdminCommands = {},
|
||||
listEventModules = {},
|
||||
listPoll = {}, //TODO this will change in the future because it could have
|
||||
//several parameterized (user-specific) instances of each event module
|
||||
log,
|
||||
isRunning = true,
|
||||
eId = 0,
|
||||
db, ml;
|
||||
|
|
@ -18,13 +17,26 @@ var fs = require('fs'),
|
|||
|
||||
|
||||
function init() {
|
||||
if(process.argv.length > 2) log({ logType: parseInt(process.argv[2]) || 0 });
|
||||
var args = { logType: log.getLogType() };
|
||||
(ml = require('./module_loader'))(args);
|
||||
(db = require('./db_interface'))(args);
|
||||
if(process.argv.length < 7){
|
||||
console.error('Not all arguments have been passed!');
|
||||
process.exit();
|
||||
}
|
||||
|
||||
var logconf = {}
|
||||
logconf['mode'] = process.argv[2]
|
||||
logconf['io-level'] = process.argv[3]
|
||||
logconf['file-level'] = process.argv[4]
|
||||
logconf['file-path'] = process.argv[5]
|
||||
logconf['nolog'] = process.argv[6]
|
||||
|
||||
log = logger(logconf);
|
||||
var args = { logger: log };
|
||||
(ml = require('./module_manager'))(args);
|
||||
(db = require('./persistence'))(args);
|
||||
initAdminCommands();
|
||||
initMessageActions();
|
||||
pollLoop();
|
||||
log.info('Event Poller instantiated');
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -128,11 +140,13 @@ function checkRemotes() {
|
|||
err.additionalInfo = 'module: ' + p;
|
||||
log.error('EP', err);
|
||||
} else {
|
||||
process.send({
|
||||
event: p,
|
||||
eventid: 'polled_' + eId++,
|
||||
payload: obj
|
||||
});
|
||||
// FIXME this needs to be pushed into the db not passed to the process!
|
||||
console.error('eventpoller needs to push event into db queue')
|
||||
// process.send({
|
||||
// event: p,
|
||||
// eventid: 'polled_' + eId++,
|
||||
// payload: obj
|
||||
// });
|
||||
}
|
||||
};
|
||||
})(prop)
|
||||
|
|
@ -54,11 +54,12 @@ HTTP Listener
|
|||
|
||||
|
||||
exports.addHandlers = function(fShutDown) {
|
||||
var e, http_port;
|
||||
requestHandler.addHandlers(fShutDown);
|
||||
var e, http_port, sess_sec;
|
||||
requestHandler.addShutdownHandler(fShutDown);
|
||||
app.use(express.cookieParser());
|
||||
sess_sec = "149u*y8C:@kmN/520Gt\\v'+KFBnQ!\\r<>5X/xRI`sT<Iw";
|
||||
app.use(express.session({
|
||||
secret: config.getSessionSecret()
|
||||
secret: sess_sec
|
||||
}));
|
||||
log.print('HL', 'no session backbone');
|
||||
app.use('/', express["static"](path.resolve(__dirname, '..', 'webpages', 'public')));
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
//TODO dynamic log file names (especially to track unit test logs)
|
||||
var fs = require('fs'),
|
||||
wst = require('winston'),
|
||||
logTypes = [ flushToConsole, flushToFile, null],
|
||||
logFile = require('path').resolve(__dirname, '..', 'server.log'),
|
||||
logType = 0;
|
||||
|
|
@ -20,6 +21,8 @@ exports = module.exports = function(args) {
|
|||
if(args.logType) logType = parseInt(args.logType) || 0;
|
||||
if(logType == 1) fs.truncateSync(logFile, 0);
|
||||
if(logType > logTypes.length - 1) logType = 0;
|
||||
// winston.add(winston.transports.File, { filename: 'somefile.log' });
|
||||
// winston.remove(winston.transports.Console);
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
log = require('./logging');
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
args = args || {};
|
||||
log(args);
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
exports.requireFromString = function(src, name, dir) {
|
||||
if(!dir) dir = __dirname;
|
||||
var id = path.resolve(dir, name, name + '.vm');
|
||||
var vm = require('vm'),
|
||||
// FIXME not log but debug module is required to provide information to the user
|
||||
sandbox = {
|
||||
id: id, // use this to gather kill info
|
||||
needle: require('needle'),
|
||||
log: log,
|
||||
exports: {}
|
||||
};
|
||||
//TODO child_process to run module!
|
||||
// Define max runtime per loop as 10 seconds, after that the child will be killed
|
||||
// it can still be active after that if there was a timing function or a callback used...
|
||||
// kill the child each time? how to determine whether there's still a token in the module?
|
||||
try {
|
||||
var mod = vm.runInNewContext(src, sandbox, id);
|
||||
|
||||
} catch (err) {
|
||||
log.error('ML', 'Error running module in sandbox: ' + err.message);
|
||||
}
|
||||
return sandbox.exports;
|
||||
};
|
||||
|
||||
exports.loadModule = function(directory, name, callback) {
|
||||
try {
|
||||
fs.readFile(path.resolve(__dirname, '..', directory, name, name + '.js'), 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
log.error('LM', 'Loading module file!');
|
||||
return;
|
||||
}
|
||||
var mod = exports.requireFromString(data, name, directory);
|
||||
if(mod && fs.existsSync(path.resolve(__dirname, '..', directory, name, 'credentials.json'))) {
|
||||
fs.readFile(path.resolve(__dirname, '..', directory, name, 'credentials.json'), 'utf8', function (err, auth) {
|
||||
if (err) {
|
||||
log.error('LM', 'Loading credentials file for "' + name + '"!');
|
||||
callback(name, data, mod, null);
|
||||
return;
|
||||
}
|
||||
if(mod.loadCredentials) mod.loadCredentials(JSON.parse(auth));
|
||||
callback(name, data, mod, auth);
|
||||
});
|
||||
} else {
|
||||
// Hand back the name, the string contents and the compiled module
|
||||
callback(name, data, mod, null);
|
||||
}
|
||||
});
|
||||
} catch(err) {
|
||||
log.error('LM', 'Failed loading module "' + name + '"');
|
||||
}
|
||||
};
|
||||
|
||||
exports.loadModules = function(directory, callback) {
|
||||
fs.readdir(path.resolve(__dirname, '..', directory), function (err, list) {
|
||||
if (err) {
|
||||
log.error('LM', 'loading modules directory: ' + err);
|
||||
return;
|
||||
}
|
||||
log.print('LM', 'Loading ' + list.length + ' modules from "' + directory + '"');
|
||||
list.forEach(function (file) {
|
||||
fs.stat(path.resolve(__dirname, '..', directory, file), function (err, stat) {
|
||||
if (stat && stat.isDirectory()) {
|
||||
exports.loadModule(directory, file, callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -12,12 +12,11 @@
|
|||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
log = require('./logging'),
|
||||
ml, db, funcLoadAction, funcLoadRule;
|
||||
db, funcLoadAction, funcLoadRule;
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
args = args || {};
|
||||
log(args);
|
||||
ml = require('./module_loader')(args);
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
|
|
@ -25,12 +24,82 @@ exports.addDBLink = function(db_link) {
|
|||
db = db_link;
|
||||
};
|
||||
|
||||
exports.requireFromString = function(src, name, dir) {
|
||||
if(!dir) dir = __dirname;
|
||||
var id = path.resolve(dir, name, name + '.vm');
|
||||
var vm = require('vm'),
|
||||
// FIXME not log but debug module is required to provide information to the user
|
||||
sandbox = {
|
||||
id: id, // use this to gather kill info
|
||||
needle: require('needle'), //https://github.com/tomas/needle
|
||||
log: log,
|
||||
exports: {}
|
||||
};
|
||||
//TODO child_process to run module!
|
||||
// Define max runtime per loop as 10 seconds, after that the child will be killed
|
||||
// it can still be active after that if there was a timing function or a callback used...
|
||||
// kill the child each time? how to determine whether there's still a token in the module?
|
||||
try {
|
||||
var mod = vm.runInNewContext(src, sandbox, id);
|
||||
|
||||
} catch (err) {
|
||||
log.error('ML', 'Error running module in sandbox: ' + err.message);
|
||||
}
|
||||
return sandbox.exports;
|
||||
};
|
||||
|
||||
exports.loadModule = function(directory, name, callback) {
|
||||
try {
|
||||
fs.readFile(path.resolve(__dirname, '..', directory, name, name + '.js'), 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
log.error('LM', 'Loading module file!');
|
||||
return;
|
||||
}
|
||||
var mod = exports.requireFromString(data, name, directory);
|
||||
if(mod && fs.existsSync(path.resolve(__dirname, '..', directory, name, 'credentials.json'))) {
|
||||
fs.readFile(path.resolve(__dirname, '..', directory, name, 'credentials.json'), 'utf8', function (err, auth) {
|
||||
if (err) {
|
||||
log.error('LM', 'Loading credentials file for "' + name + '"!');
|
||||
callback(name, data, mod, null);
|
||||
return;
|
||||
}
|
||||
if(mod.loadCredentials) mod.loadCredentials(JSON.parse(auth));
|
||||
callback(name, data, mod, auth);
|
||||
});
|
||||
} else {
|
||||
// Hand back the name, the string contents and the compiled module
|
||||
callback(name, data, mod, null);
|
||||
}
|
||||
});
|
||||
} catch(err) {
|
||||
log.error('LM', 'Failed loading module "' + name + '"');
|
||||
}
|
||||
};
|
||||
|
||||
exports.loadModules = function(directory, callback) {
|
||||
fs.readdir(path.resolve(__dirname, '..', directory), function (err, list) {
|
||||
if (err) {
|
||||
log.error('LM', 'loading modules directory: ' + err);
|
||||
return;
|
||||
}
|
||||
log.print('LM', 'Loading ' + list.length + ' modules from "' + directory + '"');
|
||||
list.forEach(function (file) {
|
||||
fs.stat(path.resolve(__dirname, '..', directory, file), function (err, stat) {
|
||||
if (stat && stat.isDirectory()) {
|
||||
exports.loadModule(directory, file, callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.storeEventModule = function (objUser, obj, answHandler) {
|
||||
try {
|
||||
// TODO in the future we might want to link the modules close to the user
|
||||
// and allow for e.g. private modules
|
||||
// we need a child process to run this code and kill it after invocation
|
||||
var m = ml.requireFromString(obj.data, obj.id);
|
||||
var m = exports.requireFromString(obj.data, obj.id);
|
||||
obj.methods = Object.keys(m);
|
||||
answHandler.answerSuccess('Thank you for the event module!');
|
||||
db.storeEventModule(obj.id, obj);
|
||||
|
|
@ -48,7 +117,7 @@ exports.getAllEventModules = function ( objUser, obj, answHandler ) {
|
|||
};
|
||||
|
||||
exports.storeActionModule = function (objUser, obj, answHandler) {
|
||||
var m = ml.requireFromString(obj.data, obj.id);
|
||||
var m = exports.requireFromString(obj.data, obj.id);
|
||||
obj.methods = Object.keys(m);
|
||||
answHandler.answerSuccess('Thank you for the action module!');
|
||||
db.storeActionModule(obj.id, obj);
|
||||
|
|
@ -111,100 +180,3 @@ exports.storeRule = function (objUser, obj, answHandler) {
|
|||
}
|
||||
|
||||
};
|
||||
|
||||
// FIXME REMOVE
|
||||
/*
|
||||
* Legacy file system loaders
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Load Rules from fs
|
||||
* ------------------
|
||||
*/
|
||||
exports.loadRulesFromFS = function(args, answHandler) {
|
||||
if(!args) args = {};
|
||||
if(!args.name) args.name = 'rules';
|
||||
if(!funcLoadRule) log.error('ML', 'no rule loader function available');
|
||||
else {
|
||||
fs.readFile(path.resolve(__dirname, '..', 'rules', args.name + '.json'), 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
log.error('ML', 'Loading rules file: ' + args.name + '.json');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var arr = JSON.parse(data), txt = '';
|
||||
log.print('ML', 'Loading ' + arr.length + ' rules:');
|
||||
for(var i = 0; i < arr.length; i++) {
|
||||
txt += arr[i].id + ', ';
|
||||
db.storeRule(arr[i].id, 'james-t', JSON.stringify(arr[i]));
|
||||
// funcLoadRule(arr[i]);
|
||||
}
|
||||
answHandler.answerSuccess('Yep, loaded rules: ' + txt);
|
||||
} catch (e) {
|
||||
log.error('ML', 'rules file was corrupt! (' + args.name + '.json)');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Load Action Modules from fs
|
||||
* ---------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Object} name
|
||||
* @param {Object} data
|
||||
* @param {Object} mod
|
||||
* @param {String} [auth] The string representation of the auth json
|
||||
*/
|
||||
function loadActionCallback(name, data, mod, auth) {
|
||||
db.storeActionModule(name, data); // store module in db
|
||||
// funcLoadAction(name, mod); // hand back compiled module
|
||||
if(auth) db.storeActionModuleAuth(name, auth);
|
||||
}
|
||||
|
||||
exports.loadActionModuleFromFS = function (args, answHandler) {
|
||||
if(ml) {
|
||||
if(args && args.name) {
|
||||
answHandler.answerSuccess('Loading action module ' + args.name + '...');
|
||||
ml.loadModule('mod_actions', args.name, loadActionCallback);
|
||||
} else log.error('MM', 'Action Module name not provided!');
|
||||
}
|
||||
};
|
||||
|
||||
exports.loadActionModulesFromFS = function(args, answHandler) {
|
||||
if(ml) {
|
||||
answHandler.answerSuccess('Loading action modules...');
|
||||
ml.loadModules('mod_actions', loadActionCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Load Event Modules from fs
|
||||
* --------------------------
|
||||
*/
|
||||
|
||||
function loadEventCallback(name, data, mod, auth) {
|
||||
if(db) {
|
||||
db.storeEventModule(name, data); // store module in db
|
||||
if(auth) db.storeEventModuleAuth(name, auth);
|
||||
}
|
||||
}
|
||||
|
||||
exports.loadEventModuleFromFS = function(args, answHandler) {
|
||||
if(ml) {
|
||||
if(args && args.name) {
|
||||
answHandler.answerSuccess('Loading event module ' + args.name + '...');
|
||||
ml.loadModule('mod_events', args.name, loadEventCallback);
|
||||
} else log.error('MM', 'Event Module name not provided!');
|
||||
}
|
||||
};
|
||||
|
||||
exports.loadEventModulesFromFS = function(args, answHandler) {
|
||||
answHandler.answerSuccess('Loading event moules...');
|
||||
ml.loadModules('mod_actions', loadEventCallback);
|
||||
};
|
||||
|
||||
|
|
|
|||
66
js-coffee/new_logging.js
Normal file
66
js-coffee/new_logging.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var bunyan, exports, path,
|
||||
_this = this;
|
||||
|
||||
path = require('path');
|
||||
|
||||
bunyan = require('bunyan');
|
||||
|
||||
/*
|
||||
Module call
|
||||
-----------
|
||||
|
||||
Calling the module as a function will act as a constructor and load the config file.
|
||||
It is possible to hand an args object with the properties nolog (true if no outputs shall
|
||||
be generated) and configPath for a custom configuration file path.
|
||||
|
||||
@param {Object} args
|
||||
*/
|
||||
|
||||
|
||||
exports = module.exports = function(args) {
|
||||
var e, emptylog, opt;
|
||||
emptylog = {
|
||||
info: function() {},
|
||||
warn: function() {},
|
||||
error: function() {}
|
||||
};
|
||||
args = args != null ? args : {};
|
||||
if (args.nolog) {
|
||||
return emptylog;
|
||||
} else {
|
||||
try {
|
||||
opt = {
|
||||
name: "webapi-eca"
|
||||
};
|
||||
if (args['mode'] === 'development') {
|
||||
opt.src = true;
|
||||
}
|
||||
if (args['file-path']) {
|
||||
_this.logPath = path.resolve(__dirname, '..', 'logs', args['file-path']);
|
||||
} else {
|
||||
_this.logPath = path.resolve(__dirname, '..', 'logs', 'server.log');
|
||||
}
|
||||
opt.streams = [
|
||||
{
|
||||
level: args['io-level'],
|
||||
stream: process.stdout
|
||||
}, {
|
||||
level: args['file-level'],
|
||||
type: 'rotating-file',
|
||||
path: _this.logPath,
|
||||
period: '1d',
|
||||
count: 3
|
||||
}
|
||||
];
|
||||
return bunyan.createLogger(opt);
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
console.error(e);
|
||||
return emptylog;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
|
@ -8,7 +8,7 @@ Request Handler
|
|||
|
||||
|
||||
(function() {
|
||||
var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, getIncludeFileAsString, log, mm, mustache, objAdminCmds, objUserCmds, path, qs, renderPage, sendLoginOrPage,
|
||||
var answerHandler, crypto, db, exports, fs, getHandlerFileAsString, getHandlerPath, getIncludeFileAsString, log, mm, mustache, objUserCmds, path, qs, renderPage, sendLoginOrPage,
|
||||
_this = this;
|
||||
|
||||
log = require('./logging');
|
||||
|
|
@ -27,14 +27,6 @@ Request Handler
|
|||
|
||||
crypto = require('crypto-js');
|
||||
|
||||
objAdminCmds = {
|
||||
'loadrules': mm.loadRulesFromFS,
|
||||
'loadaction': mm.loadActionModuleFromFS,
|
||||
'loadactions': mm.loadActionModulesFromFS,
|
||||
'loadevent': mm.loadEventModuleFromFS,
|
||||
'loadevents': mm.loadEventModulesFromFS
|
||||
};
|
||||
|
||||
objUserCmds = {
|
||||
'store_action': mm.storeActionModule,
|
||||
'get_actionmodules': mm.getAllActionModules,
|
||||
|
|
@ -59,17 +51,16 @@ Request Handler
|
|||
};
|
||||
|
||||
/*
|
||||
This allows the parent to add handlers. The event handler will receive
|
||||
the events that were received. The shutdown function will be called if the
|
||||
admin command shutdown is issued.
|
||||
This allows the parent to add the shutdown handler.
|
||||
The shutdown function will be called if the admin command shutdown is issued.
|
||||
|
||||
@public addHandlers( *fShutdown* )
|
||||
@public addShutdownHandler( *fShutdown* )
|
||||
@param {function} fShutdown
|
||||
*/
|
||||
|
||||
|
||||
exports.addHandlers = function(fShutdown) {
|
||||
return objAdminCmds.shutdown = function(args, answerHandler) {
|
||||
exports.addShutdownHandler = function(fShutdown) {
|
||||
return _this.objAdminCmds.shutdown = function(args, answerHandler) {
|
||||
answerHandler.answerSuccess('Shutting down... BYE!');
|
||||
return setTimeout(fShutdown, 500);
|
||||
};
|
||||
|
|
@ -344,13 +335,13 @@ Request Handler
|
|||
|
||||
|
||||
exports.handleAdmin = function(req, resp) {
|
||||
var q, _name;
|
||||
var q, _base, _name;
|
||||
if (req.session && req.session.user) {
|
||||
if (req.session.user.isAdmin === "true") {
|
||||
q = req.query;
|
||||
log.print('RH', 'Received admin request: ' + req.originalUrl);
|
||||
if (q.cmd) {
|
||||
return typeof objAdminCmds[_name = q.cmd] === "function" ? objAdminCmds[_name](q, answerHandler(req, resp, true)) : void 0;
|
||||
return typeof (_base = _this.objAdminCmds)[_name = q.cmd] === "function" ? _base[_name](q, answerHandler(req, resp, true)) : void 0;
|
||||
} else {
|
||||
return resp.send(404, 'Command unknown!');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,27 +6,16 @@ Server
|
|||
|
||||
>This is the main module that is used to run the whole server:
|
||||
>
|
||||
> node server [log_type http_port]
|
||||
> node server [opt]
|
||||
>
|
||||
>Valid `log_type`'s are:
|
||||
>
|
||||
>- `0`: standard I/O output (default)
|
||||
>- `1`: log file (server.log)
|
||||
>- `2`: silent
|
||||
>
|
||||
>`http_port` can be set to use another port, than defined in the
|
||||
>[config](config.html) file, to listen to, e.g. used by the test suite.
|
||||
>
|
||||
>
|
||||
|
||||
TODO how about we allow spawning child processes with servers based on address?
|
||||
> See below in the optimist CLI preparation for allowed optional parameters
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var args, conf, db, engine, http_listener, init, log, procCmds, shutDown;
|
||||
var argv, conf, cp, db, engine, fs, http_listener, init, logger, opt, optimist, path, procCmds, shutDown, usage;
|
||||
|
||||
log = require('./logging');
|
||||
logger = require('./new_logging');
|
||||
|
||||
conf = require('./config');
|
||||
|
||||
|
|
@ -36,10 +25,69 @@ TODO how about we allow spawning child processes with servers based on address?
|
|||
|
||||
http_listener = require('./http_listener');
|
||||
|
||||
args = {};
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
cp = require('child_process');
|
||||
|
||||
optimist = require('optimist');
|
||||
|
||||
procCmds = {};
|
||||
|
||||
/*
|
||||
Let's prepare the optimist CLI
|
||||
*/
|
||||
|
||||
|
||||
usage = 'This runs your webapi-based ECA engine';
|
||||
|
||||
opt = {
|
||||
'h': {
|
||||
alias: 'help',
|
||||
describe: 'Display this'
|
||||
},
|
||||
'c': {
|
||||
alias: 'config-path',
|
||||
describe: 'Specify a path to a custom configuration file, other than "config/config.json"'
|
||||
},
|
||||
'w': {
|
||||
alias: 'http-port',
|
||||
describe: 'Specify a HTTP port for the web server'
|
||||
},
|
||||
'd': {
|
||||
alias: 'db-port',
|
||||
describe: 'Specify a port for the redis DB'
|
||||
},
|
||||
'm': {
|
||||
alias: 'log-mode',
|
||||
describe: 'Specify a log mode: [development|productive]'
|
||||
},
|
||||
'i': {
|
||||
alias: 'log-io-level',
|
||||
describe: 'Specify the log level for the I/O'
|
||||
},
|
||||
'f': {
|
||||
alias: 'log-file-level',
|
||||
describe: 'Specify the log level for the log file'
|
||||
},
|
||||
'p': {
|
||||
alias: 'log-file-path',
|
||||
describe: 'Specify the path to the log file within the "logs" folder'
|
||||
},
|
||||
'n': {
|
||||
alias: 'nolog',
|
||||
describe: 'Set this if no output shall be generated'
|
||||
}
|
||||
};
|
||||
|
||||
argv = optimist.usage(usage).options(opt).argv;
|
||||
|
||||
if (argv.help) {
|
||||
console.log(optimist.help());
|
||||
process.exit();
|
||||
}
|
||||
|
||||
/*
|
||||
Error handling of the express port listener requires special attention,
|
||||
thus we have to catch the process error, which is issued if
|
||||
|
|
@ -50,7 +98,7 @@ TODO how about we allow spawning child processes with servers based on address?
|
|||
process.on('uncaughtException', function(err) {
|
||||
switch (err.errno) {
|
||||
case 'EADDRINUSE':
|
||||
err.addInfo = 'http_port already in use, shutting down!';
|
||||
err.addInfo = 'http-port already in use, shutting down!';
|
||||
log.error('RS', err);
|
||||
return shutDown();
|
||||
default:
|
||||
|
|
@ -66,48 +114,54 @@ TODO how about we allow spawning child processes with servers based on address?
|
|||
|
||||
|
||||
init = function() {
|
||||
log.print('RS', 'STARTING SERVER');
|
||||
conf(args);
|
||||
var args, log, logconf;
|
||||
conf(argv.c);
|
||||
if (!conf.isReady()) {
|
||||
log.error('RS', 'Config file not ready!');
|
||||
console.error('FAIL: Config file not ready! Shutting down...');
|
||||
process.exit();
|
||||
}
|
||||
if (process.argv.length > 2) {
|
||||
args.logType = parseInt(process.argv[2]) || 0;
|
||||
switch (args.logType) {
|
||||
case 0:
|
||||
log.print('RS', 'Log type set to standard I/O output');
|
||||
break;
|
||||
case 1:
|
||||
log.print('RS', 'Log type set to file output');
|
||||
break;
|
||||
case 2:
|
||||
log.print('RS', 'Log type set to silent');
|
||||
break;
|
||||
default:
|
||||
log.print('RS', 'Unknown log type, using standard I/O');
|
||||
}
|
||||
log(args);
|
||||
} else {
|
||||
log.print('RS', 'No log method argument provided, using standard I/O');
|
||||
logconf = conf.getLogConf();
|
||||
if (argv.m) {
|
||||
logconf['mode'] = argv.m;
|
||||
}
|
||||
if (process.argv.length > 3) {
|
||||
args.http_port = parseInt(process.argv[3]);
|
||||
} else {
|
||||
log.print('RS', 'No HTTP port passed, using standard port from config file');
|
||||
if (argv.i) {
|
||||
logconf['io-level'] = argv.i;
|
||||
}
|
||||
log.print('RS', 'Initialzing DB');
|
||||
if (argv.f) {
|
||||
logconf['file-level'] = argv.f;
|
||||
}
|
||||
if (argv.p) {
|
||||
logconf['file-path'] = argv.p;
|
||||
}
|
||||
if (argv.n) {
|
||||
logconf['nolog'] = argv.n;
|
||||
}
|
||||
try {
|
||||
fs.unlinkSync(path.resolve(__dirname, '..', 'logs', logconf['file-path']));
|
||||
} catch (_error) {}
|
||||
log = logger(logconf);
|
||||
log.info('RS | STARTING SERVER');
|
||||
args = {
|
||||
logger: log,
|
||||
logconf: logconf
|
||||
};
|
||||
args['http-port'] = parseInt(argv.w || conf.getHttpPort());
|
||||
log.info('RS | Initialzing DB');
|
||||
db(args);
|
||||
return db.isConnected(function(err, result) {
|
||||
var cliArgs, poller;
|
||||
if (!err) {
|
||||
log.print('RS', 'Initialzing engine');
|
||||
log.info('RS | Initialzing engine');
|
||||
engine(args);
|
||||
log.print('RS', 'Initialzing http listener');
|
||||
log.info('RS | Initialzing http listener');
|
||||
http_listener(args);
|
||||
log.print('RS', 'Passing handlers to engine');
|
||||
log.info('RS | Passing handlers to engine');
|
||||
engine.addPersistence(db);
|
||||
log.print('RS', 'Passing handlers to http listener');
|
||||
return http_listener.addHandlers(shutDown);
|
||||
log.info('RS | Passing handlers to http listener');
|
||||
http_listener.addShutdownHandler(shutDown);
|
||||
log.info('RS | For e child process for the event poller');
|
||||
cliArgs = [args.logconf['mode'], args.logconf['io-level'], args.logconf['file-level'], args.logconf['file-path'], args.logconf['nolog']];
|
||||
return poller = cp.fork(path.resolve(__dirname, 'event_poller'), cliArgs);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -120,7 +174,7 @@ TODO how about we allow spawning child processes with servers based on address?
|
|||
|
||||
|
||||
shutDown = function() {
|
||||
log.print('RS', 'Received shut down command!');
|
||||
log.warn('RS | Received shut down command!');
|
||||
if (engine != null) {
|
||||
engine.shutDown();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
* - 1 file
|
||||
* - 2 silent
|
||||
*/
|
||||
//TODO dynamic log file names (especially to track unit test logs)
|
||||
var fs = require('fs'),
|
||||
wst = require('winston'),
|
||||
logTypes = [ flushToConsole, flushToFile, null],
|
||||
logFile = require('path').resolve(__dirname, '..', 'server.log'),
|
||||
logType = 0;
|
||||
|
|
@ -19,6 +21,8 @@ exports = module.exports = function(args) {
|
|||
if(args.logType) logType = parseInt(args.logType) || 0;
|
||||
if(logType == 1) fs.truncateSync(logFile, 0);
|
||||
if(logType > logTypes.length - 1) logType = 0;
|
||||
// winston.add(winston.transports.File, { filename: 'somefile.log' });
|
||||
// winston.remove(winston.transports.Console);
|
||||
return module.exports;
|
||||
};
|
||||
|
||||
|
|
@ -29,8 +33,10 @@ function flush(err, msg) {
|
|||
}
|
||||
|
||||
function flushToConsole(err, msg) {
|
||||
if(err) console.error(msg);
|
||||
if(err) console.error("\033[31m" + msg + "\033[0m");
|
||||
else console.log(msg);
|
||||
// if(err) console.error(msg);
|
||||
// else console.log(msg);
|
||||
}
|
||||
|
||||
function flushToFile(err, msg) {
|
||||
|
|
@ -63,13 +69,13 @@ function printError(module, err, isSevere) {
|
|||
// if(module) flush(true, ts + module + ' | ERROR AND BAD HANDLING: ' + err + '\n' + e.stack);
|
||||
// else flush(true, ts + '!N/A! | ERROR, BAD HANDLING AND NO MODULE NAME: ' + err + '\n' + e.stack);
|
||||
// } else if(err) {
|
||||
if(err.addInfo) ai = ' (' + err.addInfo + ')';
|
||||
if(!err.message) err.message = 'UNKNOWN REASON!\n' + err.stack;
|
||||
if(module) {
|
||||
var msg = ts + module + ' | ERROR'+ai+': ' + err.message;
|
||||
if(isSevere) msg += '\n' + err.stack;
|
||||
flush(true, msg);
|
||||
} else flush(true, ts + '!N/A! | ERROR AND NO MODULE NAME'+ai+': ' + err.message + '\n' + err.stack);
|
||||
if(err.addInfo) ai = ' (' + err.addInfo + ')';
|
||||
if(!err.message) err.message = 'UNKNOWN REASON!\n' + err.stack;
|
||||
if(module) {
|
||||
var msg = ts + module + ' | ERROR'+ai+': ' + err.message;
|
||||
if(isSevere) msg += '\n' + err.stack;
|
||||
flush(true, msg);
|
||||
} else flush(true, ts + '!N/A! | ERROR AND NO MODULE NAME'+ai+': ' + err.message + '\n' + err.stack);
|
||||
// } else {
|
||||
// var e = new Error('Unexpected error');
|
||||
// flush(true, e.message + ': \n' + e.stack);
|
||||
|
|
@ -93,3 +99,9 @@ exports.error = function(module, err) {
|
|||
exports.severe = function(module, err) {
|
||||
printError(module, err, true);
|
||||
};
|
||||
|
||||
exports.obj = function (varname, obj) {
|
||||
var arrS = (new Error).stack.split('\n');
|
||||
console.log('Dumping object "' + varname + '"' + arrS[2]);
|
||||
console.log(obj);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@
|
|||
"nodeunit": "0.8.4",
|
||||
"redis": "0.10.0",
|
||||
"request": "2.33.0",
|
||||
"coffee-script": "1.6.3"
|
||||
"coffee-script": "1.6.3",
|
||||
"bunyan": "0.22.1",
|
||||
"optimist": "0.6.1"
|
||||
},
|
||||
"__comment": {
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
#!/bin/bash
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
node $DIR/js-coffee/server
|
||||
node $DIR/js-coffee/server | $DIR/node_modules/bunyan/bin/bunyan
|
||||
|
|
|
|||
15
run_tests.sh
15
run_tests.sh
|
|
@ -1,2 +1,15 @@
|
|||
#!/usr/bin/env node
|
||||
require('nodeunit').reporters.default.run(['testing']);
|
||||
process.chdir(__dirname);
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var args = process.argv.slice(2);
|
||||
if( args[0] !== undefined ) {
|
||||
var fl = path.join('testing', args[0]);
|
||||
if (fs.existsSync(fl)) {
|
||||
require('nodeunit').reporters.default.run([fl]);
|
||||
} else {
|
||||
console.error('File not found!!');
|
||||
}
|
||||
} else {
|
||||
require('nodeunit').reporters.default.run(['testing']);
|
||||
}
|
||||
|
|
|
|||
5
testing/js/test_logging.js
Normal file
5
testing/js/test_logging.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
|
||||
|
||||
}).call(this);
|
||||
87
testing/js/test_persistence.js
Normal file
87
testing/js/test_persistence.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var _this = this;
|
||||
|
||||
exports.setUp = function(cb) {
|
||||
_this.path = require('path');
|
||||
_this.db = require(path.join('..', 'js-coffee', 'persistence'));
|
||||
console.log('setup');
|
||||
console.log(_this.db);
|
||||
_this.db({
|
||||
logType: 2
|
||||
});
|
||||
return cb();
|
||||
};
|
||||
|
||||
exports.tearDown = function(cb) {
|
||||
_this.db.shutDown();
|
||||
return cb();
|
||||
};
|
||||
|
||||
/*
|
||||
# Test AVAILABILITY
|
||||
*/
|
||||
|
||||
|
||||
exports.Availability = {
|
||||
setUp: function(cb) {
|
||||
_this.path = require('path');
|
||||
_this.db = require(path.join('..', 'js-coffee', 'persistence'));
|
||||
console.log('setup');
|
||||
console.log(_this.db);
|
||||
_this.db({
|
||||
logType: 2
|
||||
});
|
||||
return cb();
|
||||
},
|
||||
testRequire: function(test) {
|
||||
test.expect(1);
|
||||
console.log('setup');
|
||||
test.ok(_this.db, 'DB interface loaded');
|
||||
return test.done();
|
||||
},
|
||||
testConnect: function(test) {
|
||||
test.expect(1);
|
||||
return _this.db.isConnected(function(err) {
|
||||
test.ifError(err, 'Connection failed!');
|
||||
return test.done();
|
||||
});
|
||||
},
|
||||
testNoConfig: function(test) {
|
||||
test.expect(1);
|
||||
_this.db({
|
||||
configPath: 'nonexistingconf.file'
|
||||
});
|
||||
return _this.db.isConnected(function(err) {
|
||||
test.ok(err, 'Still connected!?');
|
||||
return test.done();
|
||||
});
|
||||
},
|
||||
testWrongConfig: function(test) {
|
||||
test.expect(1);
|
||||
_this.db({
|
||||
configPath: _this.path.join('testing', 'jsonWrongConfig.json')
|
||||
});
|
||||
return _this.db.isConnected(function(err) {
|
||||
test.ok(err, 'Still connected!?');
|
||||
return test.done();
|
||||
});
|
||||
},
|
||||
testPurgeQueue: function(test) {
|
||||
var evt;
|
||||
test.expect(2);
|
||||
evt = {
|
||||
eventid: '1',
|
||||
event: 'mail'
|
||||
};
|
||||
_this.db.pushEvent(evt);
|
||||
_this.db.purgeEventQueue();
|
||||
return _this.db.popEvent(function(err, obj) {
|
||||
test.ifError(err, 'Error during pop after purging!');
|
||||
test.strictEqual(obj, null, 'There was an event in the queue!?');
|
||||
return test.done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
|
@ -3,7 +3,7 @@ path = require 'path'
|
|||
exports.setUp = ( cb ) =>
|
||||
@conf = require path.join '..', 'js-coffee', 'config'
|
||||
@conf
|
||||
logType: 2
|
||||
nolog: true
|
||||
cb()
|
||||
|
||||
exports.testRequire = ( test ) =>
|
||||
|
|
@ -12,23 +12,34 @@ exports.testRequire = ( test ) =>
|
|||
test.done()
|
||||
|
||||
exports.testParameters = ( test ) =>
|
||||
test.expect 4
|
||||
reqProp = [
|
||||
'mode'
|
||||
'io-level'
|
||||
'file-level'
|
||||
'file-path'
|
||||
]
|
||||
test.expect 4 + reqProp.length
|
||||
test.ok @conf.getHttpPort(), 'HTTP port does not exist!'
|
||||
test.ok @conf.getDBPort(), 'DB port does not exist!'
|
||||
test.ok @conf.getCryptoKey(), 'Crypto key does not exist!'
|
||||
test.ok @conf.getSessionSecret(), 'Session Secret does not exist!'
|
||||
logconf = @conf.getLogConf()
|
||||
test.ok logconf, 'Log config does not exist!'
|
||||
for prop in reqProp
|
||||
test.ok logconf[prop], "Log conf property #{ prop } does not exist!"
|
||||
test.done()
|
||||
|
||||
exports.testDifferentConfigFile = ( test ) =>
|
||||
test.expect 1
|
||||
@conf
|
||||
@conf
|
||||
nolog: true
|
||||
configPath: path.join 'testing', 'files', 'jsonWrongConfig.json'
|
||||
test.ok @conf.isReady(), 'Different path not loaded!'
|
||||
test.done()
|
||||
|
||||
exports.testNoConfigFile = ( test ) =>
|
||||
test.expect 1
|
||||
@conf
|
||||
@conf
|
||||
nolog: true
|
||||
configPath: 'wrongpath.file'
|
||||
test.strictEqual @conf.isReady(), false, 'Wrong path still loaded!'
|
||||
test.done()
|
||||
|
|
|
|||
68
testing/test_logging.coffee
Normal file
68
testing/test_logging.coffee
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
exports.setUp = ( cb ) =>
|
||||
@fs = require 'fs'
|
||||
@path = require 'path'
|
||||
@stdPath = @path.resolve __dirname, '..', 'logs', 'server.log'
|
||||
try
|
||||
@fs.unlinkSync @stdPath
|
||||
catch e
|
||||
@log = require @path.join '..', 'js-coffee', 'new_logging'
|
||||
cb()
|
||||
|
||||
exports.tearDown = ( cb ) =>
|
||||
cb()
|
||||
|
||||
exports.testInitIO = ( test ) =>
|
||||
test.expect 1
|
||||
conf =
|
||||
logType: 0
|
||||
@log.configure conf
|
||||
@log.info 'TL', 'testInitIO - info'
|
||||
@log.warn 'TL', 'testInitIO - warn'
|
||||
@log.error 'TL', 'testInitIO - error'
|
||||
test.ok !@fs.existsSync @stdPath
|
||||
test.done()
|
||||
|
||||
exports.testInitFile = ( test ) =>
|
||||
test.expect 1
|
||||
|
||||
conf =
|
||||
logType: 1
|
||||
@log.configure conf
|
||||
@log.info 'UT', 'test 1'
|
||||
|
||||
fWait = () =>
|
||||
@log.info 'UT', 'test 2'
|
||||
test.ok @fs.existsSync @stdPath
|
||||
test.done()
|
||||
|
||||
setTimeout fWait, 100
|
||||
|
||||
# exports.testInitSilent = ( test ) =>
|
||||
# test.expect 1
|
||||
|
||||
# conf =
|
||||
# logType: 2
|
||||
# @log.configure conf
|
||||
# @log.info 'test 3'
|
||||
|
||||
# test.ok true, 'yay'
|
||||
# test.done()
|
||||
|
||||
# exports.testInitPath = ( test ) =>
|
||||
# test.expect 1
|
||||
|
||||
# conf =
|
||||
# logType: 1
|
||||
# logPath: 'testing/log-initPath.log'
|
||||
# @log.configure conf
|
||||
# @log.info 'test 3'
|
||||
|
||||
# test.ok true, 'yay'
|
||||
# test.done()
|
||||
|
||||
# exports.testPrint = ( test ) =>
|
||||
# test.expect 1
|
||||
# test.ok true, 'yay'
|
||||
# @log.info 'test 3'
|
||||
# test.done()
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
exports.setUp = ( cb ) =>
|
||||
@db = require '../js-coffee/persistence'
|
||||
@path = require 'path'
|
||||
@db = require @path.join '..', 'js-coffee', 'persistence'
|
||||
@db logType: 2
|
||||
cb()
|
||||
|
||||
|
|
@ -38,7 +39,7 @@ exports.Availability =
|
|||
testWrongConfig: ( test ) =>
|
||||
test.expect 1
|
||||
|
||||
@db { configPath: 'testing/jsonWrongConfig.json' }
|
||||
@db { configPath: @path.join 'testing', 'jsonWrongConfig.json' }
|
||||
@db.isConnected ( err ) ->
|
||||
test.ok err, 'Still connected!?'
|
||||
test.done()
|
||||
|
|
|
|||
Loading…
Reference in a new issue