silk-gui
Version:
GUI for developers and Node OS
222 lines (197 loc) • 5.3 kB
JavaScript
var async = require('async');
var events = require('events');
var fs = require('fs');
var util = require('util');
var pathUtil = require('path');
var childProcess = require('child_process');
var npmi = require('npmi');
var methods = require('../fork_framework/ws2fork_com.js');
var db = require('../db.js');
var silkElectron = require('silk-electron');
var path = require('path');
// start higher to not conflict with old app loader
var nextId = 500;
/**
* Manages a single app
* This will usually be used indirectly through the app loader which
* will handle events. If that is not needed this can be used directly.
*/
function App(path, expressApp, next) {
var self = this;
self.id = nextId;
nextId += 1;
self.state = 'stopped';
self.path = path;
self.packageJson = {};
self.expressApp = expressApp;
process.nextTick(self.init.bind(self, next));
}
util.inherits(App, events.EventEmitter);
/**
* Loads the app's id from the database
* @param next
*/
App.prototype.loadId = function loadId(next) {
var self = this;
db.collections.appId.findOne({ path: self.path }, function (err, data) {
if (data === null) {
console.log('generating id');
db.collections.appId.insert({ path: self.path }, function (err, document) {
if (err) {
return console.log(err);
}
self.id = document[0]._id;
return next(err, document[0]._id);
});
} else {
self.id = data._id;
next(err, data._id);
}
});
};
/**
* Loads the package.json in the app's directory.
* @param next - callback
*/
App.prototype.loadJSON = function loadJSON(next) {
var self = this;
var j;
fs.readFile(self.path + '/package.json', function (err, contents) {
if (err) {
return next(err);
}
try {
j = JSON.parse(contents);
self.packageJson = j;
self.name = j.productName || j.name;
self.title = self.name;
self.url = j.silk.url;
self.icon = j.icon || path.join(__root, 'core/public/images/default-logo.png');
self.expressApp.get('/icon/' + self.id, function (req, res) {
res.sendfile(pathUtil.resolve(self.path, self.icon), function () {
res.end();
});
});
} catch (e) {
console.log(e);
return next(new Error('Error parsing package.json.'));
}
return next(null, self.packageJson);
});
};
App.prototype.installDeps = function installDeps(next) {
var self = this;
var finishedSetup = db.collections.finishedSetup;
function finish() {
finishedSetup.insert({ path: self.path });
}
finishedSetup.findOne({ path: self.path }, function (err, document) {
if (err) {
return next(err);
}
if (document === null) {
// setup never finished. run it now
if (self.packageJson.scripts && self.packageJson.scripts['setup-silk']) {
childProcess.exec('npm run setup-silk', function () {
console.log('finished npm run setup-silk');
finish();
next();
});
} else if (self.packageJson.scripts && self.packageJson.scripts.setup) {
childProcess.exec('npm run setup', {
cwd: self.path
}, function () {
console.log('finished npm run setup for ' + self.name);
finish();
next();
});
} else {
npmi({
path: self.path
}, function (err) {
if(err) {
console.log('error in npm install:');
console.log(err);
}
console.log('finished npm install');
finish();
next(err);
});
}
} else {
next(null);
}
});
};
App.prototype.init = function init(next) {
var self = this;
async.series([
self.loadId.bind(self),
self.loadJSON.bind(self),
self.installDeps.bind(self)
], function (err) {
if (err) {
console.log('error loading', self);
console.log(err);
return next(err);
}
next(null, self);
});
};
App.prototype.clean = function clean() {
var self = this;
return {
id: self.id,
name: self.name,
url: self.url,
title: self.title,
path: self.path,
icon: '/icon/' + self.id
};
};
App.prototype.start = function start(next) {
var self = this;
var forkOpts = {
cwd: __root,
env: process.env,
stdio: 'pipe'
};
// check if it has server
try {
require.resolve(self.path);
} catch (e) {
// has no server.
this.state = 'started';
return next();
}
// now actually try to start it
self.state = 'starting';
// we first need to link the modules electron provides
silkElectron.add(self.path);
self.fork = childProcess.fork(this.path, [], forkOpts);
methods.addFork(self.fork);
setTimeout(function () {
silkElectron.remove(self.path);
}, 2000);
self.fork.on('message', function (message) {
if (message.cmd === 'ready') {
self.state = 'running';
next();
}
});
};
App.prototype.stop = function start (next) {
var self = this;
self.fork.disconnect();
self.fork.kill();
self.fork.removeAllListeners();
self.state = 'stopped';
next();
};
App.prototype.restart = function restart (next) {
var self = this;
self.stop(function () {
self.start(next);
});
};
module.exports = App;