embark/lib/contracts/code_generator.js

293 lines
10 KiB
JavaScript

let fs = require('../core/fs.js');
var utils = require('../utils/utils.js');
require('ejs');
const Templates = {
utils: require('./code_templates/utils.js.ejs'),
vanilla_contract: require('./code_templates/vanilla-contract.js.ejs'),
embarkjs_contract: require('./code_templates/embarkjs-contract.js.ejs'),
exec_when_ready: require('./code_templates/exec-when-ready.js.ejs'),
load_manager: require('./code_templates/load-manager.js.ejs'),
define_when_env_loaded: require('./code_templates/define-when-env-loaded.js.ejs'),
main_context: require('./code_templates/main-context.js.ejs'),
define_web3_simple: require('./code_templates/define-web3-simple.js.ejs'),
web3_connector: require('./code_templates/web3-connector.js.ejs'),
do_when_loaded: require('./code_templates/do-when-loaded.js.ejs'),
exec_when_env_loaded: require('./code_templates/exec-when-env-loaded.js.ejs')
};
class CodeGenerator {
constructor(options) {
this.blockchainConfig = options.blockchainConfig || {};
this.contractsConfig = options.contractsConfig || {};
this.storageConfig = options.storageConfig || {};
this.communicationConfig = options.communicationConfig || {};
this.contractsManager = options.contractsManager;
this.plugins = options.plugins;
this.events = options.events;
}
listenToCommands() {
let self = this;
this.events.setCommandHandlerOnce('provider-code', function(cb) {
let providerCode = self.generateProvider(false);
cb(providerCode);
});
// deprecated events; to remove in embark 2.7.0
this.events.setCommandHandlerOnce('abi-vanila', function(cb) {
let vanillaABI = self.generateABI({useEmbarkJS: false});
let contractsJSON = self.generateContractsJSON();
cb(vanillaABI, contractsJSON);
});
this.events.setCommandHandlerOnce('abi', function(cb) {
let embarkJSABI = self.generateABI({useEmbarkJS: true});
let contractsJSON = self.generateContractsJSON();
cb(embarkJSABI, contractsJSON);
});
this.events.setCommandHandlerOnce('abi-contracts-vanila', function(cb) {
let vanillaContractsABI = self.generateContracts(false, true, false);
let contractsJSON = self.generateContractsJSON();
cb(vanillaContractsABI, contractsJSON);
});
this.events.setCommandHandlerOnce('abi-vanila-deployment', function(cb) {
let vanillaABI = self.generateABI({useEmbarkJS: false, deployment: true});
let contractsJSON = self.generateContractsJSON();
cb(vanillaABI, contractsJSON);
});
// new events
this.events.setCommandHandlerOnce('code-vanila', function(cb) {
let vanillaABI = self.generateABI({useEmbarkJS: false});
let contractsJSON = self.generateContractsJSON();
cb(vanillaABI, contractsJSON);
});
this.events.setCommandHandlerOnce('code', function(cb) {
let embarkJSABI = self.generateABI({useEmbarkJS: true});
let contractsJSON = self.generateContractsJSON();
cb(embarkJSABI, contractsJSON);
});
this.events.setCommandHandlerOnce('code-contracts-vanila', function(cb) {
let vanillaContractsABI = self.generateContracts(false, true, false);
let contractsJSON = self.generateContractsJSON();
cb(vanillaContractsABI, contractsJSON);
});
this.events.setCommandHandlerOnce('code-vanila-deployment', function(cb) {
let vanillaABI = self.generateABI({useEmbarkJS: false, deployment: true});
let contractsJSON = self.generateContractsJSON();
cb(vanillaABI, contractsJSON);
});
}
generateProvider(isDeployment) {
let self = this;
let result = "";
let providerPlugins;
// TODO: check contractsConfig for enabled
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
return "";
}
result += Templates.utils();
result += Templates.main_context();
result += Templates.load_manager();
result += Templates.define_when_env_loaded();
if (this.plugins) {
providerPlugins = this.plugins.getPluginsFor('clientWeb3Provider');
}
if (this.plugins && providerPlugins.length > 0) {
providerPlugins.forEach(function(plugin) {
result += plugin.generateProvider(self) + "\n";
});
} else {
let web3Load;
if (isDeployment) {
let connection = "http://" + this.contractsConfig.deployment.host + ":" + this.contractsConfig.deployment.port;
web3Load = Templates.define_web3_simple({url: connection, done: 'done();'});
} else {
let connectionList = "[" + this.contractsConfig.dappConnection.map((x) => '"' + x + '"').join(',') + "]";
web3Load = Templates.web3_connector({connectionList: connectionList, done: 'done();'});
}
result += Templates.do_when_loaded({block: web3Load});
}
return result;
}
generateContracts(useEmbarkJS, isDeployment, useLoader) {
let self = this;
let result = "\n";
let contractsPlugins;
if (useLoader === false) {
for (let className in this.contractsManager.contracts) {
let contract = this.contractsManager.contracts[className];
let abi = JSON.stringify(contract.abiDefinition);
result += Templates.vanilla_contract({className: className, abi: abi, contract: contract});
}
return result;
}
if (self.blockchainConfig === {} || self.blockchainConfig.enabled === false) {
return "";
}
if (this.plugins) {
contractsPlugins = this.plugins.getPluginsFor('contractGeneration');
}
if (this.plugins && contractsPlugins.length > 0) {
contractsPlugins.forEach(function (plugin) {
result += plugin.generateContracts({contracts: self.contractsManager.contracts});
});
} else {
for (let className in this.contractsManager.contracts) {
let contract = this.contractsManager.contracts[className];
let abi = JSON.stringify(contract.abiDefinition);
let gasEstimates = JSON.stringify(contract.gasEstimates);
let block = "";
if (useEmbarkJS) {
let contractAddress = contract.deployedAddress ? ("'" + contract.deployedAddress + "'") : "undefined";
block += Templates.embarkjs_contract({className: className, abi: abi, contract: contract, contractAddress: contractAddress, gasEstimates: gasEstimates});
} else {
block += Templates.vanilla_contract({className: className, abi: abi, contract: contract});
}
result += Templates.exec_when_ready({block: block});
}
}
return result;
}
generateStorageInitialization(useEmbarkJS) {
let self = this;
let result = "\n";
if (!useEmbarkJS || self.storageConfig === {}) return "";
result += Templates.define_when_env_loaded();
if (self.storageConfig.provider === 'ipfs' && self.storageConfig.enabled === true) {
let block = "\nEmbarkJS.Storage.setProvider('" + self.storageConfig.provider + "', {server: '" + self.storageConfig.host + "', port: '" + self.storageConfig.port + "', getUrl: '" + self.storageConfig.getUrl + "'});";
result += Templates.exec_when_env_loaded({block: block});
}
return result;
}
generateCommunicationInitialization(useEmbarkJS) {
let self = this;
let result = "\n";
if (!useEmbarkJS || self.communicationConfig === {}) return "";
// TODO: don't repeat this twice; should have 'requirements' generator first
result += Templates.define_when_env_loaded();
let block;
// TODO: refactor this
if (self.communicationConfig.provider === 'whisper' && self.communicationConfig.enabled === true) {
if (self.communicationConfig.connection === undefined) {
block = "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "');";
} else {
block = "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "', {server: '" + self.communicationConfig.connection.host + "', port: '" + self.communicationConfig.connection.port + "', type: '" + self.communicationConfig.connection.type + "'});";
}
result += Templates.exec_when_env_loaded({block: block});
} else if (self.communicationConfig.provider === 'orbit' && self.communicationConfig.enabled === true) {
if (self.communicationConfig.connection === undefined) {
block = "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "');";
} else {
block = "\nEmbarkJS.Messages.setProvider('" + self.communicationConfig.provider + "', {server: '" + self.communicationConfig.connection.host + "', port: '" + self.communicationConfig.connection.port + "', type: '" + self.communicationConfig.connection.type + "'});";
}
result += Templates.exec_when_env_loaded({block: block});
}
return result;
}
generateABI(options) {
let result = "";
result += this.generateProvider(options.deployment);
result += this.generateContracts(options.useEmbarkJS, options.deployment, true);
result += this.generateStorageInitialization(options.useEmbarkJS);
result += this.generateCommunicationInitialization(options.useEmbarkJS);
return result;
}
generateContractsJSON() {
let contracts = {};
for (let className in this.contractsManager.contracts) {
let contract = this.contractsManager.contracts[className];
let contractJSON = {};
contractJSON.contract_name = className;
contractJSON.address = contract.deployedAddress;
contractJSON.code = contract.code;
contractJSON.runtime_bytecode = contract.runtimeBytecode;
contractJSON.real_runtime_bytecode = contract.realRuntimeBytecode;
contractJSON.swarm_hash = contract.swarmHash;
contractJSON.gas_estimates = contract.gasEstimates;
contractJSON.function_hashes = contract.functionHashes;
contractJSON.abi = contract.abiDefinition;
contracts[className] = contractJSON;
}
return contracts;
}
buildEmbarkJS() {
let embarkjsCode = fs.readFileSync(fs.embarkPath('js/embark.js')).toString();
let code = "";
code += "\nimport Web3 from '" + utils.joinPath(fs.embarkPath("js/web3-1.0.min.js")) + "'\n";
code += "\nimport web3 from 'Embark/web3';\n";
if (this.storageConfig !== {} && this.storageConfig.provider === 'ipfs' && this.storageConfig.enabled === true) {
code += "\nimport IpfsApi from 'ipfs-api';\n";
}
code += "\n" + embarkjsCode + "\n";
code += this.generateCommunicationInitialization(true);
code += this.generateStorageInitialization(true);
let filePath = utils.joinPath(fs.dappPath(), ".embark", 'embark.js');
fs.mkdirpSync(utils.joinPath(fs.dappPath(), ".embark"));
fs.writeFileSync(filePath, code);
}
}
module.exports = CodeGenerator;