2013-11-19 13:53:36 +00:00
|
|
|
###
|
2013-11-26 22:24:15 +00:00
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
WebAPI-ECA Engine
|
|
|
|
|
=================
|
2013-11-26 22:24:15 +00:00
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
>This is the main module that is used to run the whole application:
|
2013-11-20 14:41:41 +00:00
|
|
|
>
|
2014-02-18 21:34:36 +00:00
|
|
|
> node webapi-eca [opt]
|
2013-11-20 14:41:41 +00:00
|
|
|
>
|
2014-02-18 21:34:36 +00:00
|
|
|
> See below in the optimist CLI preparation for allowed optional parameters `[opt]`.
|
2013-11-19 13:53:36 +00:00
|
|
|
###
|
2013-11-19 17:13:38 +00:00
|
|
|
|
2014-02-19 13:14:08 +00:00
|
|
|
# **Loads Modules:**
|
2013-11-26 22:24:15 +00:00
|
|
|
|
2013-11-28 15:05:47 +00:00
|
|
|
# - [Logging](logging.html)
|
2014-02-18 21:34:36 +00:00
|
|
|
logger = require './logging'
|
2013-11-28 15:05:47 +00:00
|
|
|
|
|
|
|
|
# - [Configuration](config.html)
|
2013-11-19 17:13:38 +00:00
|
|
|
conf = require './config'
|
2013-11-28 15:05:47 +00:00
|
|
|
|
2014-02-13 17:16:03 +00:00
|
|
|
# - [Persistence](persistence.html)
|
|
|
|
|
db = require './persistence'
|
2013-11-28 15:05:47 +00:00
|
|
|
|
2014-02-20 16:22:56 +00:00
|
|
|
# - [ECA Components Manager](components-manager.html)
|
|
|
|
|
cm = require './components-manager'
|
|
|
|
|
|
2013-11-28 15:05:47 +00:00
|
|
|
# - [Engine](engine.html)
|
2013-11-19 17:13:38 +00:00
|
|
|
engine = require './engine'
|
2013-11-28 15:05:47 +00:00
|
|
|
|
2014-02-18 08:48:18 +00:00
|
|
|
# - [HTTP Listener](http-listener.html)
|
|
|
|
|
http = require './http-listener'
|
2013-11-28 15:05:47 +00:00
|
|
|
|
2014-04-19 01:49:48 +00:00
|
|
|
# - [Encryption](encryption.html)
|
|
|
|
|
encryption = require './encryption'
|
|
|
|
|
|
2014-02-20 16:22:56 +00:00
|
|
|
# - [Event Poller](event-poller.html) *(will be forked into a child process)*
|
|
|
|
|
nameEP = 'event-poller'
|
|
|
|
|
|
2014-02-17 22:27:26 +00:00
|
|
|
# - 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'
|
|
|
|
|
|
2014-04-02 21:08:05 +00:00
|
|
|
# - External Modules: [optimist](https://github.com/substack/node-optimist)
|
2014-02-17 22:27:26 +00:00
|
|
|
optimist = require 'optimist'
|
|
|
|
|
|
2013-11-19 17:13:38 +00:00
|
|
|
procCmds = {}
|
2013-11-20 14:41:41 +00:00
|
|
|
|
2014-02-17 22:27:26 +00:00
|
|
|
###
|
2014-02-18 21:34:36 +00:00
|
|
|
Let's prepare the optimist CLI optional arguments `[opt]`:
|
2014-02-17 22:27:26 +00:00
|
|
|
###
|
|
|
|
|
usage = 'This runs your webapi-based ECA engine'
|
|
|
|
|
opt =
|
2014-02-18 21:34:36 +00:00
|
|
|
# `-h`, `--help`: Display the help
|
2014-04-16 15:42:56 +00:00
|
|
|
'h':
|
|
|
|
|
alias : 'help',
|
|
|
|
|
describe: 'Display this'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
# `-c`, `--config-path`: Specify a path to a custom configuration file, other than "config/config.json"
|
2014-04-16 15:42:56 +00:00
|
|
|
'c':
|
|
|
|
|
alias : 'config-path',
|
|
|
|
|
describe: 'Specify a path to a custom configuration file, other than "config/config.json"'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
# `-w`, `--http-port`: Specify a HTTP port for the web server
|
2014-04-16 15:42:56 +00:00
|
|
|
'w':
|
|
|
|
|
alias : 'http-port',
|
|
|
|
|
describe: 'Specify a HTTP port for the web server'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
# `-d`, `--db-port`: Specify a port for the redis DB
|
2014-04-16 15:42:56 +00:00
|
|
|
'd':
|
|
|
|
|
alias : 'db-port',
|
|
|
|
|
describe: 'Specify a port for the redis DB'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
|
|
|
|
# `-s`, `--db-select`: Specify a database
|
|
|
|
|
's':
|
|
|
|
|
alias : 'db-select',
|
|
|
|
|
describe: 'Specify a database identifier'
|
|
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
# `-m`, `--log-mode`: Specify a log mode: [development|productive]
|
2014-04-16 15:42:56 +00:00
|
|
|
'm':
|
|
|
|
|
alias : 'log-mode',
|
|
|
|
|
describe: 'Specify a log mode: [development|productive]'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
2014-04-05 01:09:40 +00:00
|
|
|
# `-i`, `--log-io-level`: Specify the log level for the I/O. in development expensive origin
|
|
|
|
|
# lookups are made and added to the log entries
|
2014-04-16 15:42:56 +00:00
|
|
|
'i':
|
|
|
|
|
alias : 'log-io-level',
|
|
|
|
|
describe: 'Specify the log level for the I/O'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
# `-f`, `--log-file-level`: Specify the log level for the log file
|
2014-04-16 15:42:56 +00:00
|
|
|
'f':
|
|
|
|
|
alias : 'log-file-level',
|
|
|
|
|
describe: 'Specify the log level for the log file'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
2014-02-18 21:34:36 +00:00
|
|
|
# `-p`, `--log-file-path`: Specify the path to the log file within the "logs" folder
|
2014-04-16 15:42:56 +00:00
|
|
|
'p':
|
|
|
|
|
alias : 'log-file-path',
|
|
|
|
|
describe: 'Specify the path to the log file within the "logs" folder'
|
2014-04-21 20:42:39 +00:00
|
|
|
|
2014-04-05 17:02:03 +00:00
|
|
|
# `-n`, `--nolog`: Set this true if no output shall be generated
|
2014-04-16 15:42:56 +00:00
|
|
|
'n':
|
|
|
|
|
alias : 'nolog',
|
|
|
|
|
describe: 'Set this if no output shall be generated'
|
2014-02-18 21:34:36 +00:00
|
|
|
|
|
|
|
|
# now fetch the CLI arguments and exit if the help has been called.
|
2014-02-17 22:27:26 +00:00
|
|
|
argv = optimist.usage( usage ).options( opt ).argv
|
|
|
|
|
if argv.help
|
2014-04-16 15:42:56 +00:00
|
|
|
console.log optimist.help()
|
|
|
|
|
process.exit()
|
2013-11-19 17:13:38 +00:00
|
|
|
|
2014-04-02 21:08:05 +00:00
|
|
|
conf argv.c
|
|
|
|
|
# > Check whether the config file is ready, which is required to start the server.
|
|
|
|
|
if !conf.isReady()
|
2014-04-16 15:42:56 +00:00
|
|
|
console.error 'FAIL: Config file not ready! Shutting down...'
|
|
|
|
|
process.exit()
|
2014-04-02 21:08:05 +00:00
|
|
|
|
|
|
|
|
logconf = conf.getLogConf()
|
|
|
|
|
|
|
|
|
|
if argv.m
|
2014-04-16 15:42:56 +00:00
|
|
|
logconf[ 'mode' ] = argv.m
|
2014-04-02 21:08:05 +00:00
|
|
|
if argv.i
|
2014-04-16 15:42:56 +00:00
|
|
|
logconf[ 'io-level' ] = argv.i
|
2014-04-02 21:08:05 +00:00
|
|
|
if argv.f
|
2014-04-16 15:42:56 +00:00
|
|
|
logconf[ 'file-level' ] = argv.f
|
2014-04-02 21:08:05 +00:00
|
|
|
if argv.p
|
2014-04-16 15:42:56 +00:00
|
|
|
logconf[ 'file-path' ] = argv.p
|
2014-04-02 21:08:05 +00:00
|
|
|
if argv.n
|
2014-04-16 15:42:56 +00:00
|
|
|
logconf[ 'nolog' ] = true
|
2014-04-02 21:08:05 +00:00
|
|
|
try
|
2014-04-16 15:42:56 +00:00
|
|
|
fs.unlinkSync path.resolve __dirname, '..', 'logs', logconf[ 'file-path' ]
|
2014-04-02 21:08:05 +00:00
|
|
|
@log = logger.getLogger logconf
|
|
|
|
|
@log.info 'RS | STARTING SERVER'
|
|
|
|
|
|
2013-11-19 17:13:38 +00:00
|
|
|
###
|
|
|
|
|
This function is invoked right after the module is loaded and starts the server.
|
2013-11-20 23:20:06 +00:00
|
|
|
|
|
|
|
|
@private init()
|
2013-11-19 17:13:38 +00:00
|
|
|
###
|
2014-02-19 13:14:08 +00:00
|
|
|
init = =>
|
2014-02-17 22:27:26 +00:00
|
|
|
|
2014-04-16 15:42:56 +00:00
|
|
|
args =
|
|
|
|
|
logger: @log
|
|
|
|
|
logconf: logconf
|
|
|
|
|
# > Fetch the `http-port` argument
|
|
|
|
|
args[ 'http-port' ] = parseInt argv.w || conf.getHttpPort()
|
|
|
|
|
args[ 'db-port' ] = parseInt argv.d || conf.getDbPort()
|
2014-04-21 20:42:39 +00:00
|
|
|
args[ 'db-select' ] = parseInt argv.s || conf.fetchProp 'db-select'
|
2014-04-16 15:42:56 +00:00
|
|
|
|
|
|
|
|
#FIXME this has to come from user input for security reasons:
|
|
|
|
|
args[ 'keygen' ] = conf.getKeygenPassphrase()
|
|
|
|
|
args[ 'webhooks' ] = conf.fetchProp 'webhooks'
|
2014-04-19 01:49:48 +00:00
|
|
|
|
|
|
|
|
encryption args
|
2014-04-16 15:42:56 +00:00
|
|
|
|
|
|
|
|
@log.info 'RS | Initialzing DB'
|
|
|
|
|
db args
|
|
|
|
|
# > We only proceed with the initialization if the DB is ready
|
|
|
|
|
db.isConnected ( err ) =>
|
2014-04-21 20:42:39 +00:00
|
|
|
db.selectDatabase parseInt( args[ 'db-select' ] ) || 0
|
2014-04-16 15:42:56 +00:00
|
|
|
if err
|
|
|
|
|
@log.error 'RS | No DB connection, shutting down system!'
|
|
|
|
|
shutDown()
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
# > Initialize all required modules with the args object.
|
|
|
|
|
@log.info 'RS | Initialzing engine'
|
|
|
|
|
#TODO We could in the future make the engine a child process as well
|
|
|
|
|
engine args
|
|
|
|
|
|
|
|
|
|
# Start the event poller. The module manager will emit events for it
|
|
|
|
|
@log.info 'RS | Forking a child process for the event poller'
|
|
|
|
|
# Grab all required log config fields
|
|
|
|
|
|
|
|
|
|
cliArgs = [
|
|
|
|
|
# - the log mode: [development|productive], in development expensive origin
|
|
|
|
|
# lookups are made and added to the log entries
|
|
|
|
|
args.logconf[ 'mode' ]
|
|
|
|
|
# - the I/O log level, refer to logging.coffee for the different levels
|
|
|
|
|
args.logconf[ 'io-level' ]
|
|
|
|
|
# - the file log level, refer to logging.coffee for the different levels
|
|
|
|
|
args.logconf[ 'file-level' ]
|
|
|
|
|
# - the optional path to the log file
|
|
|
|
|
args.logconf[ 'file-path' ]
|
|
|
|
|
# - whether a log file shall be written at all [true|false]
|
|
|
|
|
args.logconf[ 'nolog' ]
|
2014-04-22 13:24:34 +00:00
|
|
|
# - The selected database
|
|
|
|
|
args[ 'db-select' ]
|
2014-04-16 15:42:56 +00:00
|
|
|
# - The keygen phrase, this has to be handled differently in the future!
|
|
|
|
|
args[ 'keygen' ]
|
|
|
|
|
]
|
2014-04-30 09:28:43 +00:00
|
|
|
# Initialize the event poller with the required CLI arguments
|
2014-04-16 15:42:56 +00:00
|
|
|
poller = cp.fork path.resolve( __dirname, nameEP ), cliArgs
|
|
|
|
|
|
|
|
|
|
# after the engine and the event poller have been initialized we can
|
|
|
|
|
# initialize the module manager and register event listener functions
|
|
|
|
|
# from engine and event poller
|
|
|
|
|
@log.info 'RS | Initialzing module manager'
|
|
|
|
|
cm args
|
|
|
|
|
cm.addRuleListener engine.internalEvent
|
|
|
|
|
cm.addRuleListener ( evt ) -> poller.send evt
|
|
|
|
|
|
|
|
|
|
@log.info 'RS | Initialzing http listener'
|
2014-04-30 09:28:43 +00:00
|
|
|
# The request handler passes certain requests to the components manager
|
2014-04-16 15:42:56 +00:00
|
|
|
args[ 'request-service' ] = cm.processRequest
|
|
|
|
|
# We give the HTTP listener the ability to shutdown the whole system
|
|
|
|
|
args[ 'shutdown-function' ] = shutDown
|
|
|
|
|
http args
|
|
|
|
|
|
2013-11-19 17:13:38 +00:00
|
|
|
###
|
|
|
|
|
Shuts down the server.
|
2013-11-20 23:20:06 +00:00
|
|
|
|
2013-11-26 22:24:15 +00:00
|
|
|
@private shutDown()
|
2013-11-19 17:13:38 +00:00
|
|
|
###
|
2014-02-20 09:17:06 +00:00
|
|
|
shutDown = () =>
|
2014-04-16 15:42:56 +00:00
|
|
|
@log.warn 'RS | Received shut down command!'
|
|
|
|
|
db?.shutDown()
|
|
|
|
|
engine.shutDown()
|
|
|
|
|
# We need to call process.exit() since the express server in the http-listener
|
|
|
|
|
# can't be stopped gracefully. Why would you stop this system anyways!??
|
|
|
|
|
process.exit()
|
2013-11-19 17:13:38 +00:00
|
|
|
|
|
|
|
|
###
|
|
|
|
|
## Process Commands
|
|
|
|
|
|
|
|
|
|
When the server is run as a child process, this function handles messages
|
|
|
|
|
from the parent process (e.g. the testing suite)
|
|
|
|
|
###
|
2013-11-26 22:24:15 +00:00
|
|
|
process.on 'message', ( cmd ) -> procCmds[cmd]?()
|
2013-11-19 17:13:38 +00:00
|
|
|
|
2014-02-19 13:14:08 +00:00
|
|
|
process.on 'SIGINT', shutDown
|
|
|
|
|
process.on 'SIGTERM', shutDown
|
|
|
|
|
|
2013-11-28 15:05:47 +00:00
|
|
|
# The die command redirects to the shutDown function.
|
2013-11-19 17:13:38 +00:00
|
|
|
procCmds.die = shutDown
|
|
|
|
|
|
2013-11-28 15:05:47 +00:00
|
|
|
# *Start initialization*
|
2013-11-19 17:13:38 +00:00
|
|
|
init()
|