drone.js | |
---|---|
/*
* drone.js: Controls the application lifetime for nodejs applications on a single server.
*
* (C) 2010, Nodejitsu Inc.
*
*/
var async = require('async'),
haibu = require('../../haibu'); | |
function Drone (options)@options {Object} Options for this instance.Constructor function for the Drone resource. | var Drone = exports.Drone = function (options) {
options = options || {};
this.apps = {};
this.appsDir = options.appsDir || haibu.config.get('directories:apps');
this.host = options.host || 'localhost';
this.drones = {};
this.spawner = new haibu.Spawner(options);
}; |
function start (app, callback)@app {App} Application to start in this instance.@callback {function} Continuation passed to respond to.Attempts to spawn the @app by passing it to the spawner. | Drone.prototype.start = function (app, callback) {
var self = this;
this.spawner.trySpawn(app, function (err, result) {
if (err) {
return callback(err, false);
}
else if (typeof result === 'undefined') {
return callback(new Error('Unknown error from Spawner.'));
}
self._add(app, result, function (err) { |
If there is an error persisting the drone to disk then just respond anyway since the drone process started correctly. | callback(null, self._formatRecord(result));
});
});
}; |
function stop (name, callback)@name {string} Name of the application to stop (i.e. app.name).@callback {function} Continuation passed to respond to.Stops all drones with app.name === name managed by this instance | Drone.prototype.stop = function (name, callback) {
if (typeof this.apps[name] === 'undefined') {
return callback(new Error('Cannot stop application that is not running.'));
}
var self = this,
app = this.apps[name],
keys = Object.keys(app.drones),
results = [];
function removeAndSave (key, next) {
app.drones[key].monitor.stop();
results.push(app.drones[key].process);
self._remove(app, app.drones[key], function () {
next();
});
}
async.forEach(keys, removeAndSave, function () {
callback(null, results);
});
}; |
function restart (name, callback)@name {string} Name of the application to restart (i.e. app.name).Restarts all drones with app = name managed by this instance and responds with the list of processes of new processes. | Drone.prototype.restart = function (name, callback) {
if (typeof this.apps[name] === 'undefined') {
return callback(new Error('Cannot restart application that is not running.'));
}
var self = this,
record = this.apps[name],
keys = Object.keys(record.drones),
processes = [];
function restartAndUpdate (key, next) {
var existing = record.drones[key].process.pid;
record.drones[key].monitor.once('restart', function (file, data) {
self._update(record, existing, data, function () {
processes.push(self._formatRecord(record.drones[data.pid]));
next();
});
});
record.drones[key].monitor.restart();
}
async.forEach(keys, restartAndUpdate, function () {
callback(null, processes);
});
}; |
function clean (app)@app {App} Application to clean in this instance.@callback {function} Continuation passed to respond to.Stops the potentially running application then removes all dependencies and source files associated with the application. | Drone.prototype.clean = function (app, callback) {
if (!app.user || !app.name) {
return callback(new Error('Both `user` and `name` are required.'));
}
var self = this;
this.stop(app.name, function (err, result) { |
Ignore errors and continue cleaning | haibu.utils.rmApp(self.appsDir, app, callback);
});
}; |
function update (name, callback)@name {string} Name of the application to update (i.e. app.name).Stops an application, Cleans all source and deps, Starts the pplication | Drone.prototype.update = function (app, callback) {
if (typeof this.apps[app.name] === 'undefined') {
return callback(new Error('Cannot update application that is not running.'));
}
var self = this;
this.clean(app, function (err) {
self.start(app, function (err, result) {
callback(err, result);
});
});
}; |
function show (name)@name {string} Name of the application to show (i.e. app.name)Shows details for drone with | Drone.prototype.show = function (name) {
var self = this,
app = this.apps[name],
appData;
appData = {
app: this.apps[name].app,
drones: []
};
if (app.drones) {
Object.keys(app.drones).forEach(function (pid) {
appData.drones.push(self._formatRecord(app.drones[pid]));
});
}
return appData;
} |
function list ()Lists details about all drones managed by this instance | Drone.prototype.list = function () {
var self = this,
allApps = {};
Object.keys(this.apps).forEach(function (name) {
allApps[name] = self.show(name);
});
return allApps;
}; |
function _add (app, drone)@app {App} Application for which to attach @drone to@drone {Object} Drone to attach to @appAttaches the specified drone to the application in this instance. | Drone.prototype._add = function (app, drone, callback) { |
Create a record for this app if it doesn't exist | this.apps[app.name] = this.apps[app.name] || {};
var self = this,
record = this.apps[app.name];
if (!record.app) { |
If we have not yet created a record for this app then sanitize the data in the app and update the record. | ['domain', 'subdomain'].forEach(function (prop) {
if (app[prop]) {
app[prop] = app[prop].toLowerCase();
}
});
['domains', 'subdomains'].forEach(function (prop) {
if (app[prop]) {
app[prop] = app[prop].map(function (value) {
return value.toLowerCase();
});
}
})
record.app = app;
record.drones = {};
}
record.drones[drone.process.pid] = drone;
callback();
}; |
function _remove (a, drone)@record {Object} Wrapped {app, drone} tuple set in _add@drone {Object} Drone metadata to remove from the specified applicationRemoves the specified drone object from the bookkeeping of this instance. | Drone.prototype._remove = function (record, drone, callback) {
var self = this;
delete record.drones[drone.process.pid]; |
If there are no more drones for this app delete the entire app | if (Object.keys(record.drones).length === 0) {
delete self.apps[record.app.name];
}
callback();
}; |
function _update (record, existing, update, callback)@record {Object} Wrapped {app, drone} tuple set in _add@existing {string} Existing pid for the drone to be updated.@updated {Object} New forever data for the droneUpdates the pid of the | Drone.prototype._update = function (record, existing, updated, callback) {
var drone = record.drones[existing];
delete record.drones[existing];
drone.process = drone.monitor.child;
drone.data = updated;
record.drones[updated.pid] = drone;
callback();
};
Drone.prototype._formatRecord = function (record) {
var response = haibu.utils.clone(record.drone);
if (record.socket && record.socket.port) {
response.port = record.socket.port;
response.host = record.socket.host;
}
response.host = response.host || this.host || 'localhost';
return response;
};
|