coffeenode-monitor
Version:
coffeenode-monitor ==================
208 lines (161 loc) • 8.17 kB
text/coffeescript
############################################################################################################
njs_fs = require 'fs'
njs_path = require 'path'
njs_cp = require 'child_process'
#...........................................................................................................
TRM = require 'coffeenode-trm'
rpr = TRM.rpr.bind TRM
log_ = TRM.log.bind TRM
badge = 'cndmon'
log = TRM.get_logger 'plain', badge
info = TRM.get_logger 'info', badge
whisper = TRM.get_logger 'whisper', badge
debug = TRM.get_logger 'debug', badge
alert = TRM.get_logger 'alert', badge
warn = TRM.get_logger 'warn', badge
help = TRM.get_logger 'help', badge
echo = TRM.echo.bind TRM
#...........................................................................................................
# https://github.com/bevry/watchr
watchr = require 'watchr'
#...........................................................................................................
server = null
server_is_running = no
### TAINT: globals are bad, and so is the module-global state-keeping below: ###
_restart_on_exit = no
home = process.cwd()
options_route = njs_path.join home, 'monitor-options'
version = ( require '../package.json' )[ 'version' ]
############################################################################################################
### Show opening banner: ###
log()
log TRM.grey ' * * * * * * * * * * * * * * * * * * '
log TRM.steel " CoffeeNode Monitor "
log TRM.steel " the friendly file & process watcher "
log TRM.grey " (v#{version}) "
log TRM.grey ' * * * * * * * * * * * * * * * * * * '
############################################################################################################
### Load options: ###
info "loading configuration settings from", TRM.lime options_route
try
O = require options_route
catch error
if /^Cannot find module/.test error[ 'message' ]
log()
alert "unable to load #{TRM.lime options_route}"
alert "please copy file", TRM.lime 'coffeenode-monitor/monitor-options.json'
alert "to", TRM.lime home
alert "and edit it to match your needs"
log()
process.exit()
else
throw error
############################################################################################################
### Preprocess settings: ###
unless O[ 'watch-routes' ]?
O[ 'watch-routes' ] = [ home, ]
#...........................................................................................................
unless O[ 'start' ]?
O[ 'start' ] = './lib/start.js'
############################################################################################################
### Report settings: ###
log()
for name, value of O
log ( TRM.grey 'setting' ), ( TRM.gold "#{name}:" ), ( TRM.lime rpr value )
#===========================================================================================================
# SERVER METHODS
#-----------------------------------------------------------------------------------------------------------
start = ->
#.........................................................................................................
if O[ 'on-change' ]? and O[ 'on-change' ].length > 0
info "executing #{rpr O[ 'on-change' ]}"
njs_cp.exec O[ 'on-change' ], ( error, stdout, stderr ) ->
throw error if error?
throw new Error stderr if stderr? and stderr.length isnt 0
for line in stdout.split '\n'
info line if line.length isnt 0
_start()
#.........................................................................................................
else
_start()
#.........................................................................................................
return null
#-----------------------------------------------------------------------------------------------------------
_start = ->
### TAINT: module-global state ###
_restart_on_exit = no
#.........................................................................................................
### TAINT: ad-hoc parsing isn't very safety-proof: ###
start_command = O[ 'start' ].split /[ ]+/
switch arity = start_command.length
when 0
throw new Error "unable to parse start command: #{rpr O[ 'start' ]}"
when 1
command = start_command[ 0 ]
parameters = []
else
command = start_command.shift()
parameters = start_command
#.........................................................................................................
info 'command: ', rpr command
info 'parameters:', rpr parameters
#.........................................................................................................
server = njs_cp.fork command, parameters
#.........................................................................................................
server.on 'error', ( error ) ->
alert error
#.........................................................................................................
server.on 'close', ( code, signal ) ->
server_is_running = no
if code?
warn "process with PID #{server[ 'pid' ]} received signal ##{code}"
if _restart_on_exit
start()
else
help "process will be restarted on code change"
#.........................................................................................................
server_is_running = yes
#-----------------------------------------------------------------------------------------------------------
stop_server = ( restart_on_exit = no ) ->
### TAINT: module-global state ###
_restart_on_exit = restart_on_exit
if server_is_running
info "stopping process with PID #{server.pid}"
server.kill 'SIGTERM'
else
# log TRM.red "server with PID #{server.pid} already shutdown"
server.emit 'close'
#-----------------------------------------------------------------------------------------------------------
restart_server = ->
stop_server yes
#===========================================================================================================
# FILE WATCHER
#-----------------------------------------------------------------------------------------------------------
### TAINT we need a solution for this: ###
watchr_options =
#.........................................................................................................
paths: O[ 'watch-routes' ]
#.........................................................................................................
### TAINT: experimental, must go to options ###
ignoreCustomPatterns: /(\.js|\.css)$/
#.........................................................................................................
listeners:
#.......................................................................................................
error: ( error ) ->
log TRM.red "an error occured:", error
#.......................................................................................................
change: ( type, route, current_stat, previous_stat ) ->
info "change:", route
restart_server()
#.......................................................................................................
watching: ( error, watchers ) ->
throw error if error?
log()
for filename, watcher of watchers[ 'children' ]
whisper "watching #{watcher[ 'path' ]}"
# ############################################################################################################
# log TRM.pink watchr_options
watchr.watch watchr_options
start()
# log TRM.pink process.argv
# log TRM.green process.cwd()