- // Probe.js (c) 2010-2014 Loren West and other contributors
- // May be freely distributed under the MIT license.
- // For further details and documentation:
- // http://lorenwest.github.com/node-monitor
- (function(root){
- // Module loading
- var Monitor = root.Monitor || require('./Monitor'),
- log = Monitor.getLogger('Probe'),
- stat = Monitor.getStatLogger('Probe'),
- Cron = Monitor.Cron, _ = Monitor._, Backbone = Monitor.Backbone;
- /**
- * A software device used to expose real time data to monitors
- *
- * This is the base class from which all probe implementations extend.
- *
- * In order to send probe data to monitors, probe implementations simply set
- * their model data using ```set()```. Those changes are detected and propagated
- * to all monitors of this probe, firing their change events.
- *
- * In order to allow remote probe control, probes need only provide a method
- * called ```{name}_control()```. See the ```ping_control()``` method as an example,
- * and the ```Probe.onControl()``` method for more information.
- *
- * @class Probe
- * @extends Backbone.Model
- * @constructor
- * @param model - Initial data model. Can be a JS object or another Model.
- * @param model.id {String} The probe id.
- * Assigned by the <a href="Router.html">Router</a> on probe instantiation.
- */
- var Probe = Monitor.Probe = Backbone.Model.extend({
- defaults: {
- id: null
- },
- /**
- * Initialize the probe
- *
- * This is called on the probe during construction. It contains
- * the probe initialization attributes and an option to make probe
- * construction asynchronous.
- *
- * Probe implementations can defer the initial response to the monitor until
- * the initial state is loaded. This allows the callback on
- * <a href="Monitor.html#method_connect">```Monitor.connect()```</a>
- * to have the complete initial state of the probe when called.
- *
- * If the initial probe state cannot be determined in ```initialize```, it should
- * set the ```options.asyncInit``` option to ```true```, and call the
- * ```options.callback(error)``` once the initial state is determined.
- *
- * // Asynchronous initialization
- * options.asyncInit = true;
- * var callback = options.callback
- *
- * If ```asyncInit``` is set to true, the ```callback``` must be called once
- * the initial state of the probe is known (or in an error condition).
- *
- * // Set the initial state, and call the callback
- * this.set(...);
- * callback(null);
- *
- * See the <a href="../files/lib_probes_FileProbe.js.html#l47">```initialize```</a>
- * method of the <a href="FileProbe.html">FileProbe</a> probe for an example. It defers
- * returning the probe to the monitor until the initial file contents are loaded.
- *
- * @method initialize
- * @param attributes {Object} Initial probe attributes sent in from the Monitor
- * @param options {Object} Initialization options
- * @param options.asyncInit {boolean} Set this to TRUE if the initial probe
- * state can't be known immediately.
- * @param options.callback {function(error)} The callback to call
- * if asyncInit is set to true. If an error is passed, the probe
- * will not be used.
- */
- initialize: function(attributes, options) {
- var t = this;
- log.info('init', t.toJSON(), options);
- },
- /**
- * Release any resources consumed by this probe.
- *
- * This can be implemented by derived classes that need to be informed when
- * they are to be shut down.
- *
- * Probes that listen to events should use this method to remove their
- * event listeners.
- *
- * @method release
- */
- release: function(){
- var t = this;
- log.info('release', t.toJSON());
- },
- /**
- * Dispatch a control message to the appropriate control function.
- *
- * This is called when the
- * <a href="Monitor.html#method_control">```control()```</a>
- * method of a monitor is called.
- * The name determines the method name called on the probe.
- *
- * The probe must implement a method with the name ```{name}_control()```,
- * and that method must accept two parameters - an input params and a callback.
- * The callback must be called, passing an optional error and response object.
- *
- * For example, if the probe supports a control with the name ```go```, then
- * all it needs to do is implement the ```go_control()``` method with the
- * proper signature. See ```ping_control()``` for an example.
- *
- * @method onControl
- * @param name {String} Name of the control message.
- * @param [params] {Any} Input parameters specific to the control message.
- * @param [callback] {Function(error, response)} Called to send the message (or error) response.
- * <ul>
- * <li>error (Any) An object describing an error (null if no errors)</li>
- * <li>response (Any) Response parameters specific to the control message.
- * </ul>
- */
- onControl: function(name, params, callback) {
- var t = this,
- controlFn = t[name + '_control'],
- startTime = Date.now(),
- errMsg,
- logId = 'onControl.' + t.probeClass + '.' + name;
- params = params || {};
- callback = callback || function(){};
- log.info(logId, t.get('id'), params);
- if (!controlFn) {
- errMsg = 'No control function: ' + name;
- log.error(logId, errMsg);
- return callback({msg: errMsg});
- }
- var whenDone = function(error) {
- if (error) {
- log.error(logId, error);
- return callback(error);
- }
- var duration = Date.now() - startTime;
- log.info(logId, params);
- stat.time(t.logId, duration);
- callback.apply(null, arguments);
- };
- try {
- controlFn.call(t, params, whenDone);
- } catch (e) {
- errMsg = 'Error calling control: ' + t.probeClass + ':' + name;
- whenDone({msg:errMsg, err: e.toString()});
- }
- },
- /**
- * Respond to a ping control sent from a monitor
- *
- * @method ping_control
- * @param params {Object} Input parameters (not used)
- * @param callback {Function(error, response)} Called to send the message (or error) response.
- * <ul>
- * <li>error (Any) An object describing an error</li>
- * <li>response (String) The string 'pong' is returned as the response</li>
- * </ul>
- */
- ping_control: function(params, callback) {
- return callback(null, 'pong');
- }
- });
- // Register probe classes when loaded
- Probe.classes = {}; // key = name, data = class definition
- Probe.extend = function(params) {
- var t = this, probeClass = Backbone.Model.extend.apply(t, arguments);
- if (params.probeClass) {Probe.classes[params.probeClass] = probeClass;}
- return probeClass;
- };
- /**
- * Constructor for a list of Probe objects
- *
- * var myList = new Probe.List(initialElements);
- *
- * @static
- * @method List
- * @param [items] {Array} Initial list items. These can be raw JS objects or Probe data model objects.
- * @return {Backbone.Collection} Collection of Probe data model objects
- */
- Probe.List = Backbone.Collection.extend({model: Probe});
- }(this));
-