2018-05-18 21:15:49 +00:00
|
|
|
const async = require('async');
|
|
|
|
|
2018-05-07 18:30:30 +00:00
|
|
|
const Events = require('./events.js');
|
|
|
|
const Logger = require('./logger.js');
|
|
|
|
const Config = require('./config.js');
|
2018-05-18 21:15:49 +00:00
|
|
|
const Blockchain = require('../contracts/blockchain.js');
|
2018-05-19 03:19:08 +00:00
|
|
|
const Compiler = require('../contracts/compiler.js');
|
2018-05-07 18:30:30 +00:00
|
|
|
const ContractsManager = require('../contracts/contracts.js');
|
|
|
|
const DeployManager = require('../contracts/deploy_manager.js');
|
|
|
|
const CodeGenerator = require('../contracts/code_generator.js');
|
|
|
|
const ServicesMonitor = require('./services_monitor.js');
|
2018-05-18 21:15:49 +00:00
|
|
|
const Pipeline = require('../pipeline/pipeline.js');
|
2018-05-07 18:30:30 +00:00
|
|
|
const Watch = require('../pipeline/watch.js');
|
|
|
|
const LibraryManager = require('../versions/library_manager.js');
|
2018-05-21 21:22:19 +00:00
|
|
|
const CodeRunner = require('../coderunner/codeRunner.js');
|
2017-03-30 11:12:39 +00:00
|
|
|
|
|
|
|
class Engine {
|
|
|
|
constructor(options) {
|
|
|
|
this.env = options.env;
|
2018-05-14 18:32:19 +00:00
|
|
|
this.isDev = options.isDev;
|
2017-03-30 11:12:39 +00:00
|
|
|
this.embarkConfig = options.embarkConfig;
|
|
|
|
this.interceptLogs = options.interceptLogs;
|
2017-03-31 11:34:43 +00:00
|
|
|
this.version = options.version;
|
2018-04-19 04:25:43 +00:00
|
|
|
this.logFile = options.logFile;
|
2018-04-17 06:17:59 +00:00
|
|
|
this.logLevel = options.logLevel;
|
2018-04-19 04:25:43 +00:00
|
|
|
this.events = options.events;
|
2018-04-25 14:34:17 +00:00
|
|
|
this.context = options.context;
|
2017-03-30 11:12:39 +00:00
|
|
|
}
|
2017-03-03 06:22:12 +00:00
|
|
|
|
2017-03-30 11:38:14 +00:00
|
|
|
init(_options) {
|
|
|
|
let self = this;
|
|
|
|
let options = _options || {};
|
2018-04-19 04:25:43 +00:00
|
|
|
this.events = options.events || this.events || new Events();
|
|
|
|
this.logger = options.logger || new Logger({logLevel: options.logLevel || this.logLevel || 'debug', events: this.events, logFile: this.logFile});
|
2018-04-25 14:34:17 +00:00
|
|
|
this.config = new Config({env: this.env, logger: this.logger, events: this.events, context: this.context});
|
2017-03-30 11:38:14 +00:00
|
|
|
this.config.loadConfigFiles({embarkConfig: this.embarkConfig, interceptLogs: this.interceptLogs});
|
|
|
|
this.plugins = this.config.plugins;
|
|
|
|
|
|
|
|
this.servicesMonitor = new ServicesMonitor({events: this.events, logger: this.logger});
|
|
|
|
this.servicesMonitor.addCheck('embarkVersion', function (cb) {
|
2017-04-02 03:22:43 +00:00
|
|
|
return cb({name: 'Embark ' + self.version, status: 'on'});
|
2017-03-30 11:38:14 +00:00
|
|
|
}, 0);
|
2018-04-30 05:56:43 +00:00
|
|
|
|
|
|
|
if (this.interceptLogs || this.interceptLogs === undefined) {
|
2018-05-18 13:46:39 +00:00
|
|
|
// this.doInterceptLogs();
|
2018-04-30 05:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-07 18:30:30 +00:00
|
|
|
normalizeInput(input) {
|
|
|
|
let args = Object.values(input);
|
|
|
|
if (args.length === 0) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
if (args.length === 1) {
|
|
|
|
if (Array.isArray(args[0])) { return args[0].join(','); }
|
|
|
|
return args[0] || "";
|
|
|
|
}
|
|
|
|
return ('[' + args.map((x) => {
|
|
|
|
if (x === null) { return "null"; }
|
|
|
|
if (x === undefined) { return "undefined"; }
|
|
|
|
if (Array.isArray(x)) { return x.join(','); }
|
|
|
|
return x;
|
|
|
|
}).toString() + ']');
|
|
|
|
}
|
|
|
|
|
2018-04-30 05:56:43 +00:00
|
|
|
doInterceptLogs() {
|
|
|
|
var self = this;
|
|
|
|
let context = {};
|
|
|
|
context.console = console;
|
|
|
|
|
|
|
|
context.console.log = function() {
|
2018-05-07 18:30:30 +00:00
|
|
|
self.logger.info(self.normalizeInput(arguments));
|
2018-04-30 05:56:43 +00:00
|
|
|
};
|
|
|
|
context.console.warn = function() {
|
2018-05-07 18:30:30 +00:00
|
|
|
self.logger.warn(self.normalizeInput(arguments));
|
2018-04-30 05:56:43 +00:00
|
|
|
};
|
|
|
|
context.console.info = function() {
|
2018-05-07 18:30:30 +00:00
|
|
|
self.logger.info(self.normalizeInput(arguments));
|
2018-04-30 05:56:43 +00:00
|
|
|
};
|
|
|
|
context.console.debug = function() {
|
|
|
|
// TODO: ue JSON.stringify
|
2018-05-07 18:30:30 +00:00
|
|
|
self.logger.debug(self.normalizeInput(arguments));
|
2018-04-30 05:56:43 +00:00
|
|
|
};
|
|
|
|
context.console.trace = function() {
|
2018-05-07 18:30:30 +00:00
|
|
|
self.logger.trace(self.normalizeInput(arguments));
|
2018-04-30 05:56:43 +00:00
|
|
|
};
|
|
|
|
context.console.dir = function() {
|
2018-05-07 18:30:30 +00:00
|
|
|
self.logger.dir(self.normalizeInput(arguments));
|
2018-04-30 05:56:43 +00:00
|
|
|
};
|
2017-03-30 11:38:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
startMonitor() {
|
|
|
|
let self = this;
|
|
|
|
if (this.plugins) {
|
2017-12-18 14:37:16 +00:00
|
|
|
// --------
|
|
|
|
// TODO: this only works for services done on startup
|
|
|
|
// --------
|
2017-03-30 11:38:14 +00:00
|
|
|
let servicePlugins = this.plugins.getPluginsFor('serviceChecks');
|
|
|
|
servicePlugins.forEach(function (plugin) {
|
|
|
|
plugin.serviceChecks.forEach(function (pluginCheck) {
|
|
|
|
self.servicesMonitor.addCheck(pluginCheck.checkName, pluginCheck.checkFn, pluginCheck.time);
|
|
|
|
});
|
2017-03-16 11:31:52 +00:00
|
|
|
});
|
2017-03-30 11:38:14 +00:00
|
|
|
}
|
|
|
|
this.servicesMonitor.startMonitor();
|
|
|
|
}
|
|
|
|
|
2017-12-16 20:39:30 +00:00
|
|
|
registerModule(moduleName, options) {
|
|
|
|
this.plugins.loadInternalPlugin(moduleName, options);
|
|
|
|
}
|
|
|
|
|
2017-03-30 11:38:14 +00:00
|
|
|
startService(serviceName, _options) {
|
|
|
|
let options = _options || {};
|
|
|
|
|
|
|
|
let services = {
|
|
|
|
"pipeline": this.pipelineService,
|
2018-05-23 15:16:56 +00:00
|
|
|
"codeRunner": this.codeRunnerService,
|
2017-08-03 23:29:09 +00:00
|
|
|
"codeGenerator": this.codeGeneratorService,
|
2017-03-30 11:38:14 +00:00
|
|
|
"deployment": this.deploymentService,
|
|
|
|
"fileWatcher": this.fileWatchService,
|
|
|
|
"webServer": this.webServerService,
|
|
|
|
"ipfs": this.ipfsService,
|
2017-12-30 20:52:51 +00:00
|
|
|
"web3": this.web3Service,
|
2018-04-24 00:27:11 +00:00
|
|
|
"libraryManager": this.libraryManagerService,
|
|
|
|
"swarm": this.swarmService
|
2017-03-30 11:38:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let service = services[serviceName];
|
|
|
|
|
|
|
|
if (!service) {
|
|
|
|
throw new Error("unknown service: " + serviceName);
|
|
|
|
}
|
|
|
|
|
|
|
|
// need to be careful with circular references due to passing the web3 object
|
|
|
|
//this.logger.trace("calling: " + serviceName + "(" + JSON.stringify(options) + ")");
|
|
|
|
return service.apply(this, [options]);
|
|
|
|
}
|
|
|
|
|
2017-10-14 14:13:30 +00:00
|
|
|
pipelineService(_options) {
|
2018-05-10 14:10:09 +00:00
|
|
|
const self = this;
|
|
|
|
this.events.emit("status", "Building Assets");
|
|
|
|
const pipeline = new Pipeline({
|
|
|
|
buildDir: this.config.buildDir,
|
|
|
|
contractsFiles: this.config.contractsFiles,
|
|
|
|
assetFiles: this.config.assetFiles,
|
|
|
|
events: this.events,
|
|
|
|
logger: this.logger,
|
2018-05-10 15:14:25 +00:00
|
|
|
normalizeInput: this.normalizeInput,
|
2018-05-10 14:10:09 +00:00
|
|
|
plugins: this.plugins
|
|
|
|
});
|
2018-05-10 17:28:12 +00:00
|
|
|
|
2018-05-10 14:10:09 +00:00
|
|
|
this.events.on('code-generator-ready', function () {
|
|
|
|
self.events.request('code', function (abi, contractsJSON) {
|
2018-05-15 18:42:06 +00:00
|
|
|
pipeline.build(abi, contractsJSON, null, () => {
|
2018-04-30 13:29:31 +00:00
|
|
|
if (self.watch) {
|
|
|
|
self.watch.restart(); // Necessary because changing a file while it is writing can stop it from being watched
|
|
|
|
}
|
2018-05-10 14:10:09 +00:00
|
|
|
self.events.emit('outputDone');
|
2017-07-06 22:48:20 +00:00
|
|
|
});
|
2017-07-05 12:35:51 +00:00
|
|
|
});
|
2017-03-30 11:38:14 +00:00
|
|
|
});
|
2017-03-16 11:31:52 +00:00
|
|
|
}
|
2017-03-30 11:38:14 +00:00
|
|
|
|
2018-05-23 15:16:56 +00:00
|
|
|
codeRunnerService(_options) {
|
2018-05-21 21:22:19 +00:00
|
|
|
this.codeRunner = new CodeRunner({
|
2018-05-23 15:16:56 +00:00
|
|
|
plugins: this.plugins,
|
|
|
|
events: this.events,
|
|
|
|
logger: this.logger
|
2018-05-21 21:22:19 +00:00
|
|
|
});
|
2018-05-23 15:16:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
codeGeneratorService(_options) {
|
|
|
|
let self = this;
|
2018-05-21 21:22:19 +00:00
|
|
|
|
2018-05-23 15:16:13 +00:00
|
|
|
this.codeGenerator = new CodeGenerator({
|
|
|
|
blockchainConfig: self.config.blockchainConfig,
|
|
|
|
contractsConfig: self.config.contractsConfig,
|
|
|
|
contractsManager: this.contractsManager,
|
|
|
|
plugins: self.plugins,
|
|
|
|
storageConfig: self.config.storageConfig,
|
|
|
|
communicationConfig: self.config.communicationConfig,
|
|
|
|
events: self.events
|
|
|
|
});
|
|
|
|
this.codeGenerator.listenToCommands();
|
|
|
|
|
|
|
|
const generateCode = function () {
|
|
|
|
self.codeGenerator.buildEmbarkJS(function() {
|
2018-01-10 15:43:25 +00:00
|
|
|
self.events.emit('code-generator-ready');
|
|
|
|
});
|
2017-03-30 11:38:14 +00:00
|
|
|
};
|
2018-05-15 18:42:06 +00:00
|
|
|
const cargo = async.cargo((tasks, callback) => {
|
|
|
|
generateCode(tasks[tasks.length - 1].contractsManager);
|
|
|
|
self.events.once('outputDone', callback);
|
|
|
|
});
|
|
|
|
const addToCargo = function (contractsManager) {
|
|
|
|
cargo.push({contractsManager});
|
|
|
|
};
|
|
|
|
|
|
|
|
this.events.on('contractsDeployed', addToCargo);
|
|
|
|
this.events.on('blockchainDisabled', addToCargo);
|
|
|
|
this.events.on('asset-changed', addToCargo);
|
2017-03-03 06:22:12 +00:00
|
|
|
}
|
2017-03-04 02:48:32 +00:00
|
|
|
|
2017-03-30 11:38:14 +00:00
|
|
|
deploymentService(options) {
|
|
|
|
let self = this;
|
2017-12-16 20:39:30 +00:00
|
|
|
|
2018-05-19 03:19:08 +00:00
|
|
|
let compiler = new Compiler({plugins: self.plugins, logger: self.logger});
|
|
|
|
this.events.setCommandHandler("compiler:contracts", function(contractFiles, cb) {
|
|
|
|
compiler.compile_contracts(contractFiles, cb);
|
|
|
|
});
|
|
|
|
|
2017-12-16 20:39:30 +00:00
|
|
|
this.registerModule('solidity', {
|
|
|
|
contractDirectories: self.config.contractDirectories
|
|
|
|
});
|
2018-04-12 17:24:54 +00:00
|
|
|
this.registerModule('vyper', {
|
|
|
|
contractDirectories: self.config.contractDirectories
|
|
|
|
});
|
2018-05-08 15:30:46 +00:00
|
|
|
this.registerModule('profiler', {
|
|
|
|
events: this.events,
|
2018-05-08 15:53:34 +00:00
|
|
|
logger: this.logger
|
2018-05-08 15:30:46 +00:00
|
|
|
});
|
2017-12-16 20:39:30 +00:00
|
|
|
|
2018-05-19 02:40:47 +00:00
|
|
|
this.registerModule('deploytracker', {
|
|
|
|
});
|
|
|
|
|
2018-05-20 14:46:36 +00:00
|
|
|
this.registerModule('specialconfigs', {
|
|
|
|
});
|
|
|
|
|
2018-02-21 23:43:34 +00:00
|
|
|
this.contractsManager = new ContractsManager({
|
|
|
|
contractFiles: this.config.contractsFiles,
|
|
|
|
contractsConfig: this.config.contractsConfig,
|
|
|
|
logger: this.logger,
|
|
|
|
plugins: this.plugins,
|
2018-04-30 05:56:43 +00:00
|
|
|
gasLimit: false,
|
|
|
|
events: this.events
|
2018-02-21 23:43:34 +00:00
|
|
|
});
|
|
|
|
|
2017-03-30 11:38:14 +00:00
|
|
|
this.deployManager = new DeployManager({
|
2018-05-18 22:31:47 +00:00
|
|
|
blockchain: this.blockchain,
|
2017-03-30 11:38:14 +00:00
|
|
|
trackContracts: options.trackContracts,
|
|
|
|
config: this.config,
|
|
|
|
logger: this.logger,
|
|
|
|
plugins: this.plugins,
|
2018-02-21 23:43:34 +00:00
|
|
|
events: this.events,
|
2018-03-22 19:09:01 +00:00
|
|
|
contractsManager: this.contractsManager,
|
|
|
|
onlyCompile: options.onlyCompile
|
2017-03-04 02:48:32 +00:00
|
|
|
});
|
2017-03-30 11:38:14 +00:00
|
|
|
|
2018-04-30 05:56:43 +00:00
|
|
|
this.events.on('file-event', function (fileType) {
|
2018-05-15 19:41:24 +00:00
|
|
|
clearTimeout(self.fileTimeout);
|
|
|
|
self.fileTimeout = setTimeout(() => {
|
|
|
|
// TODO: still need to redeploy contracts because the original contracts
|
|
|
|
// config is being corrupted
|
|
|
|
if (fileType === 'asset') {
|
|
|
|
// Throttle file changes so we re-write only once for all files
|
2018-05-15 18:42:06 +00:00
|
|
|
self.events.emit('asset-changed', self.contractsManager);
|
2018-05-15 19:41:24 +00:00
|
|
|
}
|
|
|
|
// TODO: for now need to deploy on asset changes as well
|
|
|
|
// because the contractsManager config is corrupted after a deploy
|
|
|
|
if (fileType === 'contract' || fileType === 'config') {
|
|
|
|
self.config.reloadConfig();
|
|
|
|
self.deployManager.deployContracts(function () {
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, 50);
|
2017-03-30 11:12:39 +00:00
|
|
|
});
|
|
|
|
}
|
2017-03-11 03:00:30 +00:00
|
|
|
|
2017-10-14 14:13:30 +00:00
|
|
|
fileWatchService(_options) {
|
2018-02-27 20:49:21 +00:00
|
|
|
this.events.emit("status", "Watching for changes");
|
2018-04-30 05:56:43 +00:00
|
|
|
this.watch = new Watch({logger: this.logger, events: this.events});
|
|
|
|
this.watch.start();
|
2017-03-30 11:38:14 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 14:50:29 +00:00
|
|
|
webServerService() {
|
2017-12-18 14:37:16 +00:00
|
|
|
this.registerModule('webserver', {
|
|
|
|
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor)
|
2017-03-30 11:38:14 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-10-14 14:13:30 +00:00
|
|
|
ipfsService(_options) {
|
2017-12-27 01:32:51 +00:00
|
|
|
this.registerModule('ipfs', {
|
|
|
|
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
|
|
|
|
storageConfig: this.config.storageConfig,
|
|
|
|
host: _options.host,
|
|
|
|
port: _options.port
|
2017-03-11 03:00:30 +00:00
|
|
|
});
|
2017-03-11 15:29:45 +00:00
|
|
|
}
|
|
|
|
|
2018-04-24 00:27:11 +00:00
|
|
|
swarmService(_options) {
|
|
|
|
this.registerModule('swarm', {
|
|
|
|
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
|
|
|
|
storageConfig: this.config.storageConfig,
|
2018-05-19 01:05:39 +00:00
|
|
|
// TODO: this should not be needed and should be deducted from the config instead
|
|
|
|
// the eth provider is not necessary the same as the swarm one
|
|
|
|
bzz: this.blockchain.web3.bzz
|
2018-04-24 00:27:11 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-30 11:38:14 +00:00
|
|
|
web3Service(options) {
|
2018-05-18 21:15:49 +00:00
|
|
|
this.blockchain = new Blockchain({
|
|
|
|
contractsConfig: this.config.contractsConfig,
|
2018-05-20 13:08:03 +00:00
|
|
|
blockchainConfig: this.config.blockchainConfig,
|
2018-05-18 21:15:49 +00:00
|
|
|
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
|
|
|
|
events: this.events,
|
|
|
|
logger: this.logger,
|
2018-05-18 22:31:47 +00:00
|
|
|
web3: options.web3
|
2018-05-18 21:15:49 +00:00
|
|
|
});
|
2018-04-10 19:14:00 +00:00
|
|
|
|
2018-05-18 21:15:49 +00:00
|
|
|
this.registerModule('whisper', {
|
|
|
|
addCheck: this.servicesMonitor.addCheck.bind(this.servicesMonitor),
|
|
|
|
communicationConfig: this.config.communicationConfig,
|
2018-05-19 00:32:40 +00:00
|
|
|
// TODO: this should not be needed and should be deducted from the config instead
|
|
|
|
// the eth provider is not necessary the same as the whisper one
|
2018-05-19 01:05:39 +00:00
|
|
|
web3: this.blockchain.web3
|
2018-01-05 20:30:52 +00:00
|
|
|
});
|
2017-03-30 11:38:14 +00:00
|
|
|
}
|
2017-12-30 20:52:51 +00:00
|
|
|
|
2017-12-30 22:07:13 +00:00
|
|
|
libraryManagerService(_options) {
|
|
|
|
this.libraryManager = new LibraryManager({
|
2017-12-30 20:52:51 +00:00
|
|
|
plugins: this.plugins,
|
|
|
|
config: this.config
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-30 11:38:14 +00:00
|
|
|
}
|
2017-03-11 15:29:45 +00:00
|
|
|
|
2017-03-03 06:22:12 +00:00
|
|
|
module.exports = Engine;
|