UNPKG

weaver

Version:

Interactive process management system

162 lines (117 loc) 3.27 kB
assert = require('assert') resolve = require('path').resolve zs = require('z-schema') schema = require('./schema') EventEmitter = require('events').EventEmitter Task = require('./task') Watcher = require('./watcher') validator = new zs(strictMode: true) class Weaver extends EventEmitter @logger: (fn) -> for item in [Weaver, Task, Watcher.constructor] item::log = fn return version : require('../package').version log : -> constructor: -> @on('error', @errorHandler) @on('upgrade', @upgradeHandler) @start = Date.now() @config = Object.create(null) return @ # Validate configuration object validate: (configuration) -> # Validate schema assert.ok(validator.validate(configuration, schema), 'Invalid configuration') # Perform additional validation for own name, task of configuration.tasks # Validate nested arrays for arguments for own key of task if key is 'arguments' for argument in task[key] if Array.isArray(argument) assert.equal( task.count, argument.length, "Nested array in arguments should contain #{task.count} values" ) task.name = name return configuration # Upgrade current state upgrade: (data, path) -> parts = [path] params = null try # Try to parse JSON data = JSON.parse(data) # Validate new state params = @validate(data) catch error error.message = "Config error: #{error.message}" @emit('error', error) if params if params.path parts.push(params.path) for own name, task of params.tasks task.cwd = resolve.apply(undefined, parts.concat(task.cwd or '.')) @config[name] = task @emit('upgrade') return # Get status report status: -> return Task.status() # Execute command with given arguments command: (action, name, args) -> fn = Task::[action + 'PID'] unless Array.isArray(args) args = [] unless typeof fn is 'function' throw new Error('Unknown action ' + action) unless name? # Execute command for all tasks for own name, task of Task.tasks fn.apply(task, args) else task = Task.tasks[name] if task if action is 'kill' args.unshift(null) fn.apply(task, args) else if `Number(name) == name` args.unshift(Number(name)) @command(action, null, args) else @log('Task ' + name + ' was not found') return # Stop all subtasks and exit die: (code) -> code = if code? then code else 1 tryExit = => for own name, task of Task.tasks for subtask in task.subtasks return if subtask.pid @emit('exit', code) return for own name, task of Task.tasks if task.timeout > timeout timeout = task.timeout task.dropSubtasks() task.on('exit', tryExit) setImmediate(tryExit) return errorHandler: (error) -> @log(error.message) return upgradeHandler: -> # Spot dropped tasks for own name, task of Task.tasks unless name of @config task.dropSubtasks() # Create or update tasks for own name, options of @config task = Task.create(name) # Setup error handler unless task.listeners('error').length task.on('error', @emit.bind(@, 'error')) task.upgrade(options) return module.exports = new Weaver()