fix: alleviate races re: embarkjs by introducing Plugin#addGeneratedCode and related refactors

This commit is contained in:
Iuri Matias 2019-06-20 19:39:31 -04:00 committed by Michael Bradley
parent d684b9af0f
commit fc4faa8ba9
22 changed files with 258 additions and 564 deletions

View File

@ -80,6 +80,10 @@ class CodeGenerator {
cb(this.getEmbarkJsProviderCode()); cb(this.getEmbarkJsProviderCode());
}); });
this.events.setCommandHandler('code-generator:embarkjs:set-provider-code', (cb) => {
cb(this.getSetProviderCode());
});
this.events.setCommandHandler('code-generator:embarkjs:init-provider-code', (cb) => { this.events.setCommandHandler('code-generator:embarkjs:init-provider-code', (cb) => {
cb(this.getInitProviderCode()); cb(this.getInitProviderCode());
}); });
@ -100,6 +104,14 @@ class CodeGenerator {
}); });
} }
getSetProviderCode() {
let code = "\n";
code += this.generateCommunicationInitialization(true);
code += this.generateStorageInitialization(true);
code += this.generateNamesInitialization(true);
return code;
}
generateContracts(contractsList, useEmbarkJS, isDeployment, useLoader) { generateContracts(contractsList, useEmbarkJS, isDeployment, useLoader) {
let self = this; let self = this;
let result = "\n"; let result = "\n";
@ -313,7 +325,6 @@ class CodeGenerator {
const self = this; const self = this;
let embarkjsCode = ''; let embarkjsCode = '';
let code = "/* eslint-disable */"; let code = "/* eslint-disable */";
const deps = ['web3', 'ens', 'ipfs', 'swarm', 'whisper'];
async.waterfall([ async.waterfall([
// TODO: here due to a race condition when running embark build // TODO: here due to a race condition when running embark build
@ -342,30 +353,36 @@ class CodeGenerator {
embarkjsCode += `\nconst EmbarkJS = require("${symlinkDest}").default || require("${symlinkDest}");`; embarkjsCode += `\nconst EmbarkJS = require("${symlinkDest}").default || require("${symlinkDest}");`;
embarkjsCode += `\nEmbarkJS.environment = '${self.env}';`; embarkjsCode += `\nEmbarkJS.environment = '${self.env}';`;
embarkjsCode += "\nglobal.EmbarkJS = EmbarkJS;"; embarkjsCode += "\nglobal.EmbarkJS = EmbarkJS;";
code += "\n" + embarkjsCode + "\n";
next(); next();
}); });
}, },
...deps.map((dep) => { function addCodeFromDependencies(next) {
return function(next) { async.eachSeries(
self.events.request('version:downloadIfNeeded', `embarkjs-${dep}`, (err, location) => { self.plugins.getPluginsFor('generatedCode'),
if (err) { (plugin, callback) => {
self.logger.error(__(`Error downloading embarkjs-${dep}`)); async.eachSeries(
return next(err); plugin.generated_code,
} (codeCall, callback) => {
codeCall((err, generatedCode, packageName, location) => {
self.generateSymlink(location, `embarkjs-${dep}`, (err, _symlinkDest) => { if (err) return callback(err);
if (err) { self.generateSymlink(location, packageName, (err, _symlinkDest) => {
self.logger.error(__(`Error creating a symlink to embarkjs-${dep}`)); if (err) {
return next(err); self.logger.error(__(`Error creating a symlink to ${packageName}`));
} return callback(err);
return next(); }
}); code += generatedCode;
}); callback();
}; });
}), });
},
(err) => { callback(err); }
);
},
(err) => { next(err); }
);
},
function getJSCode(next) { function getJSCode(next) {
code += "\n" + embarkjsCode + "\n";
code += self.getEmbarkJsProviderCode(); code += self.getEmbarkJsProviderCode();
code += self.generateCommunicationInitialization(true); code += self.generateCommunicationInitialization(true);
code += self.generateStorageInitialization(true); code += self.generateStorageInitialization(true);

View File

@ -37,8 +37,6 @@ export default class CodeRunner {
this.registerEvents(); this.registerEvents();
this.registerCommands(); this.registerCommands();
this.events.emit("runcode:ready");
this.ready = true;
} }
private generateListener(provider: string, eventType: ProviderEventType) { private generateListener(provider: string, eventType: ProviderEventType) {
@ -52,101 +50,64 @@ export default class CodeRunner {
}); });
} }
private fireEmbarkJSEvents(code: string) { private registerEvents() {
const regexRegister = /EmbarkJS\.(.*)\.registerProvider/gm; this.events.on("runcode:register", this.registerVar.bind(this));
const regexSet = /EmbarkJS\.(.*)\.setProvider/gm;
let matches = regexRegister.exec(code);
if (matches) {
let [, provider] = matches;
provider = provider.toLowerCase();
this.providerStates[`${provider}:${ProviderEventType.ProviderRegistered}`] = true;
this.events.emit(`runcode:${provider}:${ProviderEventType.ProviderRegistered}`);
}
matches = regexSet.exec(code);
if (matches) {
let [, provider] = matches;
provider = provider.toLowerCase();
this.providerStates[`${provider}:${ProviderEventType.ProviderSet}`] = true;
this.events.emit(`runcode:${provider}:${ProviderEventType.ProviderSet}`);
}
} }
private registerEvents() { private registerCommands() {
this.events.on("runcode:register", this.registerVar.bind(this)); this.events.setCommandHandler("runcode:getContext", (cb) => {
cb(this.vm.options.sandbox);
this.events.on("runcode:init-console-code:updated", (code: string, cb: Callback<null>) => {
this.evalCode(code, (err, _result) => {
if (err) {
this.logger.error("Error running init console code: ", err.message || err);
}
this.fireEmbarkJSEvents(code);
cb();
}); });
}); this.events.setCommandHandler("runcode:eval", this.evalCode.bind(this));
this.events.setCommandHandler("runcode:embarkjs:reset", (cb) => {
this.events.on("runcode:embarkjs-code:updated", (code: string, cb: Callback<any>) => { this.resetEmbarkJS(cb);
this.evalCode(code, (err, _result) => {
if (err) {
this.logger.error("Error running embarkjs code: ", err.message || err);
}
this.fireEmbarkJSEvents(code);
cb();
}); });
}); this.events.on("contractsDeployed", () => {
} this.events.on("code-generator-ready", (_modifiedAssets: any) => {
this.resetEmbarkJS();
private registerCommands() {
this.events.setCommandHandler("runcode:getContext", (cb) => {
cb(this.vm.options.sandbox);
});
this.events.setCommandHandler("runcode:eval", this.evalCode.bind(this));
this.events.setCommandHandler("runcode:ready", (cb) => {
if (this.ready) {
return cb();
}
this.events.once("runcode:ready", cb);
});
this.events.setCommandHandler("runcode:embarkjs:reset", this.resetEmbarkJS.bind(this));
// register listeners for when EmbarkJS runs registerProvider through the console.
// For example, when `EmbarkJS.Storage.registerProvider(...)` is run through the console,
// emit the `runcode:storage:providerRegistered` event, and fire any requests attached to it
Object.keys(EmbarkJS)
.filter((propName) => EmbarkJS[propName].hasOwnProperty("registerProvider"))
.forEach((providerName) => {
this.generateListener(providerName.toLowerCase(), ProviderEventType.ProviderRegistered);
});
// register listeners for when EmbarkJS runs setProvider through the console.
// For example, when `EmbarkJS.Storage.setProvider(...)` is run through the console,
// emit the `runcode:storage:providerSet` event, and fire any requests attached to it
Object.keys(EmbarkJS)
.filter((propName) => EmbarkJS[propName].hasOwnProperty("setProvider"))
.forEach((providerName) => {
this.generateListener(providerName.toLowerCase(), ProviderEventType.ProviderSet);
});
}
private resetEmbarkJS(cb: Callback<null>) {
this.events.request("code-generator:embarkjs:provider-code", (code: string) => {
this.evalCode(code, (err) => {
if (err) {
return cb(err);
}
this.events.request("code-generator:embarkjs:init-provider-code", (providerCode: string) => {
this.evalCode(providerCode, (errInitProvider, _result) => {
cb(errInitProvider);
}, true);
}); });
}, true); });
});
} // register listeners for when EmbarkJS runs registerProvider through the console.
// For example, when `EmbarkJS.Storage.registerProvider(...)` is run through the console,
// emit the `runcode:storage:providerRegistered` event, and fire any requests attached to it
Object.keys(EmbarkJS)
.filter((propName) => EmbarkJS[propName].hasOwnProperty("registerProvider"))
.forEach((providerName) => {
this.generateListener(providerName.toLowerCase(), ProviderEventType.ProviderRegistered);
});
// register listeners for when EmbarkJS runs setProvider through the console.
// For example, when `EmbarkJS.Storage.setProvider(...)` is run through the console,
// emit the `runcode:storage:providerSet` event, and fire any requests attached to it
Object.keys(EmbarkJS)
.filter((propName) => EmbarkJS[propName].hasOwnProperty("setProvider"))
.forEach((providerName) => {
this.generateListener(providerName.toLowerCase(), ProviderEventType.ProviderSet);
});
}
private resetEmbarkJS(cb?: Callback<null>) {
this.events.request("code-generator:embarkjs:init-provider-code", (code: string) => {
this.evalCode(code, (err) => {
if (err) {
console.dir(err);
return;
}
this.events.request("code-generator:embarkjs:set-provider-code", (providerCode: string) => {
this.evalCode(providerCode, (errInitProvider, _result) => {
if (cb) { cb(errInitProvider); }
}, false);
});
}, false);
});
}
private registerVar(varName: string, code: any, cb = () => { }) { private registerVar(varName: string, code: any, cb = () => { }) {
this.vm.registerVar(varName, code, cb); this.vm.registerVar(varName, code, cb);
} }
private evalCode(code: string, cb: Callback < any >, tolerateError = false) { private evalCode(code: string, cb: Callback<any>, tolerateError = false) {
cb = cb || (() => { }); cb = cb || (() => { });
if (!code) { if (!code) {

View File

@ -27,7 +27,6 @@ class Console {
private history: string[]; private history: string[];
private cmdHistoryFile: string; private cmdHistoryFile: string;
private suggestions?: Suggestions; private suggestions?: Suggestions;
private providerReady: boolean;
constructor(embark: Embark, options: any) { constructor(embark: Embark, options: any) {
this.embark = embark; this.embark = embark;
@ -40,7 +39,6 @@ class Console {
this.config = options.config; this.config = options.config;
this.history = []; this.history = [];
this.cmdHistoryFile = options.cmdHistoryFile || dappPath(".embark", "cmd_history"); this.cmdHistoryFile = options.cmdHistoryFile || dappPath(".embark", "cmd_history");
this.providerReady = false;
this.loadHistory(); this.loadHistory();
if (this.ipc.isServer()) { if (this.ipc.isServer()) {
@ -60,24 +58,11 @@ class Console {
} }
this.events.setCommandHandler("console:executeCmd", this.executeCmd.bind(this)); this.events.setCommandHandler("console:executeCmd", this.executeCmd.bind(this));
this.events.setCommandHandler("console:history", (cb: any) => this.getHistory(this.cmdHistorySize(), cb)); this.events.setCommandHandler("console:history", (cb: any) => this.getHistory(this.cmdHistorySize(), cb));
this.events.setCommandHandler("console:provider:ready", (cb: any) => {
if (this.providerReady || this.isEmbarkConsole) {
return cb();
}
this.events.once("console:provider:done", cb);
});
this.registerConsoleCommands(); this.registerConsoleCommands();
if (this.isEmbarkConsole) { if (this.isEmbarkConsole) {
return; return;
} }
this.registerEmbarkJs((err?: Error | null) => {
if (err) {
return this.logger.error(err);
}
this.providerReady = true;
this.events.emit("console:provider:done");
});
this.registerApi(); this.registerApi();
this.suggestions = new Suggestions(embark, options); this.suggestions = new Suggestions(embark, options);
@ -202,43 +187,6 @@ class Console {
}, true); }, true);
} }
private registerEmbarkJs(cb: Callback<null>) {
waterfall([
// wait for the VM to be setup
(next: any) => {
this.events.request("runcode:ready", next);
},
(next: any) => {
const waitingForReady = setTimeout(() => {
this.logger.warn(__("Waiting for the blockchain connector to be ready..."));
// TODO add docs link to how to install one
this.logger.warn(__("If you did not install a blockchain connector, stop this process and install one"));
}, 5000);
this.events.request("blockchain:connector:ready", () => {
clearTimeout(waitingForReady);
next();
});
},
(next: any) => {
if (this.isEmbarkConsole) {
return next();
}
this.events.request("runcode:blockchain:providerSet", next);
},
(next: any) => {
if (this.isEmbarkConsole) {
return next();
}
const connectCode = `EmbarkJS.Blockchain.connectConsole((err) => {
if(err) throw new Error("[VM]: Error connecting to blockchain. " + err);
});`;
this.events.request("runcode:eval", connectCode, (err: Error, _result: any) => {
cb(err);
});
},
], cb);
}
private registerConsoleCommands() { private registerConsoleCommands() {
this.embark.registerConsoleCommand({ this.embark.registerConsoleCommand({
description: __("display console commands history"), description: __("display console commands history"),

View File

@ -384,18 +384,31 @@ class ENS {
return this.logger.error(err.message || err); return this.logger.error(err.message || err);
} }
this.events.emit('runcode:register', 'namehash', require('eth-ens-namehash'), () => { this.events.emit('runcode:register', 'namehash', require('eth-ens-namehash'), () => {
let linkedModulePath = path.join(this.modulesPath, 'embarkjs-ens');
if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
const code = `
const __embarkENS = require('${linkedModulePath}');
EmbarkJS.Names.registerProvider('ens', __embarkENS.default || __embarkENS);
`;
this.embark.addCodeToEmbarkJS(code);
}); });
}); });
}); });
let linkedModulePath = path.join(this.modulesPath, 'embarkjs-ens');
if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
const code = `
const __embarkENS = require('${linkedModulePath}');
EmbarkJS.Names.registerProvider('ens', __embarkENS.default || __embarkENS);
`;
this.events.request('version:downloadIfNeeded', 'embarkjs-ens', (err, location) => {
if (err) {
this.logger.error(__('Error downloading embarkjs-ens'));
throw err;
}
this.embark.addProviderInit("names", code, () => { return true; });
this.embark.addConsoleProviderInit("names", code, () => { return true; });
this.embark.addGeneratedCode((cb) => {
return cb(null, code, `embarkjs-ens`, location);
});
});
}); });
} }
@ -406,6 +419,7 @@ class ENS {
return (namesConfig.provider === 'ens' && namesConfig.enabled === true); return (namesConfig.provider === 'ens' && namesConfig.enabled === true);
}; };
// TODO This stacks the setProviders making it so that we call it multiple times
this.embark.addProviderInit('names', code, shouldInit); this.embark.addProviderInit('names', code, shouldInit);
this.embark.addConsoleProviderInit('names', code, shouldInit); this.embark.addConsoleProviderInit('names', code, shouldInit);
} }

View File

@ -35,9 +35,6 @@ class Test {
init(callback) { init(callback) {
async.waterfall([ async.waterfall([
(next) => {
this.events.request('runcode:ready', next);
},
(next) => { (next) => {
this.gasLimit = GAS_LIMIT; this.gasLimit = GAS_LIMIT;
this.events.request('deploy:setGasLimit', this.gasLimit); this.events.request('deploy:setGasLimit', this.gasLimit);
@ -181,7 +178,9 @@ class Test {
} }
self.firstRunConfig = false; self.firstRunConfig = false;
self.events.request("blockchain:ready", () => { self.events.request("blockchain:ready", () => {
self.events.request("runcode:embarkjs:reset", callback); self.events.request("code-generator:embarkjs:build", () => {
self.events.request("runcode:embarkjs:reset", callback);
});
}); });
}); });
}); });
@ -316,11 +315,6 @@ class Test {
next(err, accounts, web3); next(err, accounts, web3);
}); });
}, },
function waitForProvidersReady(accounts, web3, next) {
self.events.request('console:provider:ready', () => {
next(null, accounts, web3);
});
},
function createContractObject(accounts, web3, next) { function createContractObject(accounts, web3, next) {
self.events.request('contracts:all', (err, contracts) => { self.events.request('contracts:all', (err, contracts) => {
async.each(contracts, (contract, eachCb) => { async.each(contracts, (contract, eachCb) => {

View File

@ -1,5 +1,6 @@
/* global __dirname module process require */ /* global __dirname module process require */
const { __ } = require('embark-i18n');
const { dappPath, embarkPath, normalizePath, toForwardSlashes } = require('embark-utils'); const { dappPath, embarkPath, normalizePath, toForwardSlashes } = require('embark-utils');
const constants = require('embark-core/constants'); const constants = require('embark-core/constants');
const path = require('path'); const path = require('path');
@ -18,7 +19,6 @@ class EmbarkWeb3 {
async addWeb3ToEmbarkJS() { async addWeb3ToEmbarkJS() {
let blockchainConnectorReady = false; let blockchainConnectorReady = false;
await this.whenRuncodeReady();
const web3LocationPromise = this.getWeb3Location(); const web3LocationPromise = this.getWeb3Location();
@ -61,22 +61,24 @@ class EmbarkWeb3 {
code += `\n const web3ConnectionConfig = require('${configPath}');`; code += `\n const web3ConnectionConfig = require('${configPath}');`;
code += `\n EmbarkJS.Blockchain.connect(web3ConnectionConfig, (err) => {if (err) { console.error(err); } });`; code += `\n EmbarkJS.Blockchain.connect(web3ConnectionConfig, (err) => {if (err) { console.error(err); } });`;
code += `\n}`; code += `\n}`;
this.events.request('version:downloadIfNeeded', 'embarkjs-web3', (err, location) => {
if (err) {
this.logger.error(__('Error downloading embarkjs-web3'));
throw err;
}
this.embark.addCodeToEmbarkJS(code); this.embark.addProviderInit("blockchain", code, () => { return true; });
code = "EmbarkJS.Blockchain.setProvider('web3', {web3});"; // Make sure that we use our web3 for the console and the tests
code += `if (typeof web3 === 'undefined') {
throw new Error('Global web3 is not present');
}
EmbarkJS.Blockchain.setProvider('web3', {web3});`;
const shouldInit = (_config) => { this.embark.addConsoleProviderInit("blockchain", code, () => { return true; });
return true;
};
this.embark.addConsoleProviderInit('blockchain', code, shouldInit); this.embark.addGeneratedCode((cb) => {
} return cb(null, code, 'embarkjs-web3', location);
whenRuncodeReady() {
return new Promise((resolve) => {
this.events.on('runcode:ready', () => {
resolve();
}); });
}); });
} }

View File

@ -50,7 +50,6 @@ class Whisper {
} }
} }
this.setServiceCheck(); this.setServiceCheck();
this.addWhisperToEmbarkJS();
this.addSetProvider(); this.addSetProvider();
this.registerAPICalls(); this.registerAPICalls();
cb(); cb();
@ -58,6 +57,10 @@ class Whisper {
}); });
}); });
// TODO: it will have the issue of waiting for the ipfs to start when the code is generator
// TODO: could be solved by having a list of services to wait on before attempting to execute code in the console
this.addWhisperToEmbarkJS();
this.events.request('processes:launch', 'whisper'); this.events.request('processes:launch', 'whisper');
} }
@ -117,7 +120,6 @@ class Whisper {
} }
addWhisperToEmbarkJS() { addWhisperToEmbarkJS() {
const self = this;
// TODO: make this a shouldAdd condition // TODO: make this a shouldAdd condition
if (this.communicationConfig === {}) { if (this.communicationConfig === {}) {
return; return;
@ -129,12 +131,23 @@ class Whisper {
let linkedModulePath = path.join(this.modulesPath, 'embarkjs-whisper'); let linkedModulePath = path.join(this.modulesPath, 'embarkjs-whisper');
if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\'); if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
const code = ` this.events.request('version:downloadIfNeeded', 'embarkjs-whisper', (err, location) => {
const __embarkWhisperNewWeb3 = require('${linkedModulePath}'); if (err) {
EmbarkJS.Messages.registerProvider('whisper', __embarkWhisperNewWeb3.default || __embarkWhisperNewWeb3); this.logger.error(__('Error downloading embarkjs-whisper'));
`; throw err;
}
self.embark.addCodeToEmbarkJS(code); const code = `
const __embarkWhisperNewWeb3 = require('${linkedModulePath}');
EmbarkJS.Messages.registerProvider('whisper', __embarkWhisperNewWeb3.default || __embarkWhisperNewWeb3);
`;
this.embark.addProviderInit("communication", code, () => { return true; });
this.embark.addConsoleProviderInit("communication", code, () => { return true; });
this.embark.addGeneratedCode((cb) => {
return cb(null, code, `embarkjs-whisper`, location);
});
});
} }
addSetProvider() { addSetProvider() {
@ -149,6 +162,12 @@ class Whisper {
port: connection.port || '8546', port: connection.port || '8546',
type: connection.type || 'ws' type: connection.type || 'ws'
}; };
// TODO: fix storage to also use addProviderInit
// execute code called addProviderInit WHEN contracts have been deployed etc..
// TODO: diff between addConsoleProviderInit and addProviderInit
// or maybe best way is todo everything in the module
const code = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(config)});`; const code = `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(config)});`;
this.embark.addProviderInit('communication', code, shouldInit); this.embark.addProviderInit('communication', code, shouldInit);

View File

@ -107,6 +107,7 @@
"embark-deploy-tracker": "^4.1.0-beta.3", "embark-deploy-tracker": "^4.1.0-beta.3",
"embark-deployment": "^4.1.0-beta.3", "embark-deployment": "^4.1.0-beta.3",
"embark-ens": "^4.1.0-beta.3", "embark-ens": "^4.1.0-beta.3",
"embark-graph": "^4.1.0-beta.3",
"embark-i18n": "^4.1.0-beta.3", "embark-i18n": "^4.1.0-beta.3",
"embark-library-manager": "^4.1.0-beta.3", "embark-library-manager": "^4.1.0-beta.3",
"embark-listener": "^4.1.0-beta.3", "embark-listener": "^4.1.0-beta.3",

View File

@ -165,9 +165,7 @@ class EmbarkController {
} }
engine.startService("fileWatcher"); engine.startService("fileWatcher");
engine.events.request('code-generator:embarkjs:build', () => { callback();
callback();
});
}, },
function startDashboard(callback) { function startDashboard(callback) {
if (!options.useDashboard) { if (!options.useDashboard) {
@ -242,9 +240,7 @@ class EmbarkController {
engine.startService('compiler'); engine.startService('compiler');
} }
engine.events.request('code-generator:embarkjs:build', () => { callback();
callback();
});
}, },
function buildOrBuildAndDeploy(callback) { function buildOrBuildAndDeploy(callback) {
if (options.onlyCompile) { if (options.onlyCompile) {
@ -329,18 +325,10 @@ class EmbarkController {
engine.startService("cockpit"); engine.startService("cockpit");
engine.startService("pluginCommand"); engine.startService("pluginCommand");
engine.events.request('code-generator:embarkjs:build', () => { engine.events.request('blockchain:ready', callback);
engine.events.request('blockchain:ready', callback);
});
}, },
function ipcConnect(callback) { function ipcConnect(callback) {
// Do specific work in case we are connected to a socket: return callback();
// - Setup Web3
// - Apply history
if(isSecondaryProcess(engine)) {
return callback();
}
engine.events.request("console:provider:ready", callback);
}, },
function deploy(callback) { function deploy(callback) {
// Skip if we are connected to a websocket, the server will do it // Skip if we are connected to a websocket, the server will do it
@ -413,9 +401,7 @@ class EmbarkController {
engine.startService("codeGenerator"); engine.startService("codeGenerator");
engine.startService("graph"); engine.startService("graph");
engine.events.request('code-generator:embarkjs:build', () => { engine.events.request('contracts:build', {}, callback);
engine.events.request('contracts:build', {}, callback);
});
} }
], (err) => { ], (err) => {
if (err) { if (err) {
@ -591,9 +577,7 @@ class EmbarkController {
engine.startService("storage"); engine.startService("storage");
engine.startService("codeGenerator"); engine.startService("codeGenerator");
engine.events.request('code-generator:embarkjs:build', () => { callback();
callback();
});
}, },
function listLoadedPlugin(callback) { function listLoadedPlugin(callback) {
let pluginList = engine.plugins.listPlugins(); let pluginList = engine.plugins.listPlugins();
@ -688,9 +672,7 @@ class EmbarkController {
} }
engine.startService("testRunner"); engine.startService("testRunner");
engine.events.request('code-generator:embarkjs:build', () => { callback();
callback();
});
}, },
function runTests(callback) { function runTests(callback) {
engine.events.request('tests:run', options, callback); engine.events.request('tests:run', options, callback);

View File

@ -191,17 +191,20 @@ class Engine {
this.registerModulePackage('embark-code-generator', {plugins: self.plugins, env: self.env}); this.registerModulePackage('embark-code-generator', {plugins: self.plugins, env: self.env});
const generateCode = function (modifiedAssets) { const generateCode = function (modifiedAssets, cb) {
self.events.request("module:storage:onReady", () => { self.events.request("code-generator:embarkjs:build", () => {
self.events.request("code-generator:embarkjs:build", () => { self.events.emit('code-generator-ready', modifiedAssets);
self.events.emit('code-generator-ready', modifiedAssets); cb();
});
}); });
}; };
const cargo = async.cargo((tasks, callback) => { const cargo = async.cargo((tasks, callback) => {
const modifiedAssets = tasks.map(task => task.modifiedAsset).filter(asset => asset); // filter null elements const modifiedAssets = tasks.map(task => task.modifiedAsset).filter(asset => asset); // filter null elements
generateCode(modifiedAssets); generateCode(modifiedAssets, () => {
self.events.once('outputDone', callback); if (this.context.includes('test')) {
return callback();
}
self.events.once('outputDone', callback);
});
}); });
const addToCargo = function (modifiedAsset) { const addToCargo = function (modifiedAsset) {
cargo.push({modifiedAsset}); cargo.push({modifiedAsset});
@ -297,6 +300,8 @@ class Engine {
} }
web3Service(options) { web3Service(options) {
this.registerModulePackage('embark-web3');
this.registerModulePackage('embark-blockchain-process', { this.registerModulePackage('embark-blockchain-process', {
client: this.client, client: this.client,
locale: this.locale, locale: this.locale,
@ -312,7 +317,6 @@ class Engine {
wait: options.wait wait: options.wait
}); });
this.registerModulePackage('embark-web3');
this.registerModulePackage('embark-whisper'); this.registerModulePackage('embark-whisper');
} }

View File

@ -31,6 +31,7 @@ var Plugin = function(options) {
this.apiCalls = []; this.apiCalls = [];
this.imports = []; this.imports = [];
this.embarkjs_code = []; this.embarkjs_code = [];
this.generated_code = [];
this.embarkjs_init_code = {}; this.embarkjs_init_code = {};
this.embarkjs_init_console_code = {}; this.embarkjs_init_console_code = {};
this.fs = fs; this.fs = fs;
@ -229,14 +230,17 @@ Plugin.prototype.registerUploadCommand = function(cmd, cb) {
Plugin.prototype.addCodeToEmbarkJS = function(code) { Plugin.prototype.addCodeToEmbarkJS = function(code) {
this.addPluginType('embarkjsCode'); this.addPluginType('embarkjsCode');
// TODO: what is this/why
if (!this.embarkjs_code.some((existingCode) => deepEqual(existingCode, code))) { if (!this.embarkjs_code.some((existingCode) => deepEqual(existingCode, code))) {
this.embarkjs_code.push(code); this.embarkjs_code.push(code);
this.events.request('blockchain:ready', () => {
this.events.emit('runcode:embarkjs-code:updated', code, () => {});
});
} }
}; };
Plugin.prototype.addGeneratedCode = function(codeCb) {
this.addPluginType('generatedCode');
this.generated_code.push(codeCb);
};
Plugin.prototype.addProviderInit = function(providerType, code, initCondition) { Plugin.prototype.addProviderInit = function(providerType, code, initCondition) {
this.embarkjs_init_code[providerType] = this.embarkjs_init_code[providerType] || []; this.embarkjs_init_code[providerType] = this.embarkjs_init_code[providerType] || [];
this.embarkjs_init_code[providerType].push([code, initCondition]); this.embarkjs_init_code[providerType].push([code, initCondition]);
@ -249,9 +253,6 @@ Plugin.prototype.addConsoleProviderInit = function(providerType, code, initCondi
const toAdd = [code, initCondition]; const toAdd = [code, initCondition];
if (!this.embarkjs_init_console_code[providerType].some((initConsoleCode) => deepEqual(initConsoleCode, toAdd))) { if (!this.embarkjs_init_console_code[providerType].some((initConsoleCode) => deepEqual(initConsoleCode, toAdd))) {
this.embarkjs_init_console_code[providerType].push(toAdd); this.embarkjs_init_console_code[providerType].push(toAdd);
this.events.request('blockchain:ready', () => {
this.events.emit('runcode:init-console-code:updated', code, () => {});
});
} }
}; };

View File

@ -20,7 +20,6 @@ class IPFS {
this.embark = embark; this.embark = embark;
this.fs = embark.fs; this.fs = embark.fs;
this.isServiceRegistered = false; this.isServiceRegistered = false;
this.addedToEmbarkJs = false;
this.addedToConsole = false; this.addedToConsole = false;
this.storageProcessesLauncher = null; this.storageProcessesLauncher = null;
this.usingRunningNode = false; this.usingRunningNode = false;
@ -43,7 +42,6 @@ class IPFS {
return cb(__("IPFS process is running in a separate process and cannot be started by Embark.")); return cb(__("IPFS process is running in a separate process and cannot be started by Embark."));
} }
this.startProcess((err, newProcessStarted) => { this.startProcess((err, newProcessStarted) => {
this.addStorageProviderToEmbarkJS();
this.addObjectToConsole(); this.addObjectToConsole();
this.events.emit("ipfs:process:started", err, newProcessStarted); this.events.emit("ipfs:process:started", err, newProcessStarted);
cb(); cb();
@ -64,6 +62,10 @@ class IPFS {
this.logger.info(msg); this.logger.info(msg);
} }
}); });
// TODO: it will have the issue of waiting for the ipfs to start when the code is generator
// TODO: could be solved by having a list of services to wait on before attempting to execute code in the console
this.addStorageProviderToEmbarkJS();
} }
downloadIpfsApi(cb) { downloadIpfsApi(cb) {
@ -131,8 +133,6 @@ class IPFS {
} }
addStorageProviderToEmbarkJS() { addStorageProviderToEmbarkJS() {
if(this.addedToEmbarkJs) return;
this.addedToEmbarkJs = true;
this.events.request('version:downloadIfNeeded', 'ipfs-api', (err, location) => { this.events.request('version:downloadIfNeeded', 'ipfs-api', (err, location) => {
if (err) { if (err) {
this.logger.error(__('Error downloading IPFS API')); this.logger.error(__('Error downloading IPFS API'));
@ -146,19 +146,30 @@ class IPFS {
} }
this.events.emit('runcode:register', 'IpfsApi', require('ipfs-api'), () => { this.events.emit('runcode:register', 'IpfsApi', require('ipfs-api'), () => {
let linkedModulePath = path.join(this.modulesPath, 'embarkjs-ipfs');
if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
const code = `
const __embarkIPFS = require('${linkedModulePath}');
EmbarkJS.Storage.registerProvider('ipfs', __embarkIPFS.default || __embarkIPFS);
`;
this.embark.addCodeToEmbarkJS(code);
this.embark.addConsoleProviderInit("storage", code, (storageConfig) => storageConfig.enabled);
}); });
}); });
}); });
let linkedModulePath = path.join(this.modulesPath, 'embarkjs-ipfs');
if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
const code = `
const __embarkIPFS = require('${linkedModulePath}');
EmbarkJS.Storage.registerProvider('ipfs', __embarkIPFS.default || __embarkIPFS);
`;
this.events.request('version:downloadIfNeeded', 'embarkjs-ipfs', (err, location) => {
if (err) {
this.logger.error(__('Error downloading embarkjs-ipfs'));
throw err;
}
this.embark.addProviderInit("storage", code, () => { return true; });
this.embark.addConsoleProviderInit("storage", code, () => { return true; });
this.embark.addGeneratedCode((cb) => {
return cb(null, code, `embarkjs-ipfs`, location);
});
});
}); });
} }

View File

@ -20,7 +20,6 @@ class Swarm {
this.embark = embark; this.embark = embark;
this.fs = embark.fs; this.fs = embark.fs;
this.isServiceRegistered = false; this.isServiceRegistered = false;
this.addedToEmbarkJs = false;
this.addedToConsole = false; this.addedToConsole = false;
this.storageProcessesLauncher = null; this.storageProcessesLauncher = null;
this.usingRunningNode = false; this.usingRunningNode = false;
@ -63,7 +62,6 @@ class Swarm {
return cb(__("Swarm process is running in a separate process and cannot be started by Embark.")); return cb(__("Swarm process is running in a separate process and cannot be started by Embark."));
} }
this.startProcess((err, newProcessStarted) => { this.startProcess((err, newProcessStarted) => {
this.addProviderToEmbarkJS();
this.addObjectToConsole(); this.addObjectToConsole();
this.events.emit("swarm:process:started", err, newProcessStarted); this.events.emit("swarm:process:started", err, newProcessStarted);
cb(); cb();
@ -84,6 +82,10 @@ class Swarm {
this.logger.info(msg); this.logger.info(msg);
} }
}); });
// TODO: it will have the issue of waiting for the ipfs to start when the code is generator
// TODO: could be solved by having a list of services to wait on before attempting to execute code in the console
this.addProviderToEmbarkJS();
} }
addObjectToConsole() { addObjectToConsole() {
@ -123,18 +125,27 @@ class Swarm {
} }
addProviderToEmbarkJS() { addProviderToEmbarkJS() {
if(this.addedToEmbarkJs) return;
this.addedToEmbarkJs = true;
let linkedModulePath = path.join(this.modulesPath, 'embarkjs-swarm'); let linkedModulePath = path.join(this.modulesPath, 'embarkjs-swarm');
if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\'); if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
const code = ` this.events.request('version:downloadIfNeeded', 'embarkjs-swarm', (err, location) => {
const __embarkSwarm = require('${linkedModulePath}'); if (err) {
EmbarkJS.Storage.registerProvider('swarm', __embarkSwarm.default || __embarkSwarm); this.logger.error(__('Error downloading embarkjs-swarm'));
`; throw err;
}
this.embark.addCodeToEmbarkJS(code); const code = `
const __embarkSwarm = require('${linkedModulePath}');
EmbarkJS.Storage.registerProvider('swarm', __embarkSwarm.default || __embarkSwarm);
`;
this.embark.addProviderInit("storage", code, () => { return true; });
this.embark.addConsoleProviderInit("storage", code, () => { return true; });
this.embark.addGeneratedCode((cb) => {
return cb(null, code, 'embarkjs-swarm', location);
});
});
} }
startProcess(callback) { startProcess(callback) {

View File

@ -183,6 +183,7 @@ class TemplateGenerator {
delete pkgJson.devDependencies['rimraf']; delete pkgJson.devDependencies['rimraf'];
} }
delete pkgJson.files; delete pkgJson.files;
delete pkgJson.gitHead;
pkgJson.name = name; pkgJson.name = name;
if (!pkgJson.scripts) pkgJson.scripts = {}; if (!pkgJson.scripts) pkgJson.scripts = {};
delete pkgJson.scripts.ci; delete pkgJson.scripts.ci;

View File

@ -1,4 +0,0 @@
engine-strict = true
package-lock = false
save-exact = true
scripts-prepend-node-path = true

View File

@ -1,44 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [4.1.0-beta.3](https://github.com/embark-framework/embark/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2019-06-07)
**Note:** Version bump only for package embarkjs-connector-web3
# [4.1.0-beta.2](https://github.com/embark-framework/embark/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2019-05-22)
**Note:** Version bump only for package embarkjs-connector-web3
# [4.1.0-beta.1](https://github.com/embark-framework/embark/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2019-05-15)
**Note:** Version bump only for package embarkjs-connector-web3
# [4.0.0](https://github.com/embark-framework/embark/compare/v4.0.0-beta.2...v4.0.0) (2019-03-18)
**Note:** Version bump only for package embarkjs-connector-web3
# [4.0.0-beta.1](https://github.com/embark-framework/embark/compare/v4.0.0-beta.0...v4.0.0-beta.1) (2019-03-18)
### Features
* add repository.directory field to package.json ([a9c5e1a](https://github.com/embark-framework/embark/commit/a9c5e1a))
* normalize README and package.json bugs, homepage, description ([5418f16](https://github.com/embark-framework/embark/commit/5418f16))

View File

@ -1,6 +0,0 @@
# `embarkjs-connector-web3`
> Web3.js Connector for EmbarkJS
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).

View File

@ -1,58 +0,0 @@
/*global Web3*/
const embarkJSConnectorWeb3 = {};
embarkJSConnectorWeb3.init = function(config) {
global.web3 = config.web3 || global.web3;
// Check if the global web3 object uses the old web3 (0.x)
if (global.web3 && typeof global.web3.version !== 'string') {
// If so, use a new instance using 1.0, but use its provider
this.web3 = new Web3(global.web3.currentProvider);
} else {
this.web3 = global.web3 || new Web3();
}
global.web3 = this.web3;
};
embarkJSConnectorWeb3.getInstance = function () {
return this.web3;
};
embarkJSConnectorWeb3.getAccounts = function () {
return this.web3.eth.getAccounts(...arguments);
};
embarkJSConnectorWeb3.getNewProvider = function (providerName, ...args) {
return new Web3.providers[providerName](...args);
};
embarkJSConnectorWeb3.setProvider = function (provider) {
return this.web3.setProvider(provider);
};
embarkJSConnectorWeb3.getCurrentProvider = function () {
return this.web3.currentProvider;
};
embarkJSConnectorWeb3.getDefaultAccount = function () {
return this.web3.eth.defaultAccount;
};
embarkJSConnectorWeb3.setDefaultAccount = function (account) {
this.web3.eth.defaultAccount = account;
};
embarkJSConnectorWeb3.newContract = function (options) {
return new this.web3.eth.Contract(options.abi, options.address);
};
embarkJSConnectorWeb3.send = function () {
return this.web3.eth.sendTransaction(...arguments);
};
embarkJSConnectorWeb3.toWei = function () {
return this.web3.toWei(...arguments);
};
embarkJSConnectorWeb3.getNetworkId = function () {
return this.web3.eth.net.getId();
};

View File

@ -1,115 +0,0 @@
const { dappPath, embarkPath, normalizePath, toForwardSlashes } = require('embark-utils');
const path = require('path');
class EmbarkJSConnectorWeb3 {
constructor(embark, _options) {
this.embark = embark;
this.events = embark.events;
this.fs = embark.fs;
this.config = embark.config;
this.constants = embark.constants;
this.registerProvider();
}
async registerProvider() {
let blockchainConnectorReady = false;
await this.whenRuncodeReady();
const web3LocationPromise = this.getWeb3Location();
this.events.setCommandHandler('blockchain:connector:ready', (cb) => {
if (blockchainConnectorReady) {
return cb();
}
this.events.once("blockchain:connector:ready", () => {
cb();
});
});
web3LocationPromise.then((_web3Location) => {
blockchainConnectorReady = true;
this.events.emit('blockchain:connector:ready');
});
let web3Location = await web3LocationPromise;
web3Location = normalizePath(web3Location, true);
await this.registerVar('__Web3', require(web3Location));
const symlinkLocation = await this.generateSymlink(web3Location);
let code = `\nconst Web3 = global.__Web3 || require('${symlinkLocation}');`;
code += `\nglobal.Web3 = Web3;`;
const connectorCode = this.fs.readFileSync(path.join(__dirname, 'embarkJSConnectorWeb3.js'), 'utf8');
code += connectorCode;
code += "\nEmbarkJS.Blockchain.registerProvider('web3', embarkJSConnectorWeb3);";
code += "\nEmbarkJS.Blockchain.setProvider('web3', {});";
const configPath = toForwardSlashes(dappPath(this.config.embarkConfig.generationDir, this.constants.dappArtifacts.dir, this.constants.dappArtifacts.blockchain));
code += `\nif (!global.__Web3) {`; // Only connect when in the Dapp
code += `\n const web3ConnectionConfig = require('${configPath}');`;
code += `\n EmbarkJS.Blockchain.connect(web3ConnectionConfig, (err) => {if (err) { console.error(err); } });`;
code += `\n}`;
this.embark.addCodeToEmbarkJS(code);
code = "EmbarkJS.Blockchain.setProvider('web3', {web3});";
const shouldInit = (_config) => {
return true;
};
this.embark.addConsoleProviderInit('blockchain', code, shouldInit);
}
whenRuncodeReady() {
return new Promise((resolve) => {
this.events.on('runcode:ready', () => {
resolve();
});
});
}
getWeb3Location() {
return new Promise((resolve, reject) => {
this.events.request("version:get:web3", (web3Version) => {
if (web3Version === "1.0.0-beta") {
const nodePath = embarkPath('node_modules');
const web3Path = require.resolve("web3", {paths: [nodePath]});
return resolve(web3Path);
}
this.events.request("version:getPackageLocation", "web3", web3Version, (err, location) => {
if (err) {
return reject(err);
}
const locationPath = embarkPath(location);
resolve(locationPath);
});
});
});
}
generateSymlink(location) {
return new Promise((resolve, reject) => {
this.events.request('code-generator:symlink:generate', location, 'web3', (err, symlinkDest) => {
if (err) {
return reject(err);
}
resolve(symlinkDest);
});
});
}
registerVar(name, code) {
return new Promise((resolve) => {
this.events.emit('runcode:register', name, code, () => {
resolve();
});
});
}
}
module.exports = EmbarkJSConnectorWeb3;

View File

@ -1,39 +0,0 @@
{
"name": "embarkjs-connector-web3",
"version": "4.1.0-beta.3",
"author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [],
"description": "Web3.js Connector for EmbarkJS",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/embarkjs-connector-web3#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"keywords": [
"embark",
"web3",
"node",
"ethereum",
"smart-contract"
],
"license": "MIT",
"repository": {
"directory": "packages/embarkjs-connector-web3",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"main": "index.js",
"files": [
"embarkJSConnectorWeb3.js"
],
"scripts": {
"ci": "npm run qa",
"clean": "npm run reset",
"package": "npm pack",
"qa": "npm run package",
"reset": "npx rimraf embark-*.tgz package"
},
"dependencies": {
"embark-utils": "^4.1.0-beta.3"
},
"devDependencies": {
"rimraf": "2.6.3"
}
}

View File

@ -153,40 +153,39 @@ __embarkENS.registryAddresses = {
"4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A" "4": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
}; };
__embarkENS.setProvider = function (config) { __embarkENS.setProvider = function(config) {
const self = this; const self = this;
const ERROR_MESSAGE = 'ENS is not available in this chain'; const ERROR_MESSAGE = 'ENS is not available in this chain';
self.registration = config.registration; self.registration = config.registration;
self.env = config.env; self.env = config.env;
EmbarkJS.onReady(() => { // FIXME EmbarkJS.onReady odesn't work. Possibility of a race condition
EmbarkJS.Blockchain.blockchainConnector.getNetworkId() EmbarkJS.Blockchain.blockchainConnector.getNetworkId()
.then((id) => { .then((id) => {
const registryAddress = self.registryAddresses[id] || config.registryAddress; const registryAddress = self.registryAddresses[id] || config.registryAddress;
self._isAvailable = true; self._isAvailable = true;
self.ens = new EmbarkJS.Blockchain.Contract({ self.ens = new EmbarkJS.Blockchain.Contract({
abi: config.registryAbi, abi: config.registryAbi,
address: registryAddress, address: registryAddress,
web3: EmbarkJS.Blockchain.blockchainConnector.getInstance() web3: EmbarkJS.Blockchain.blockchainConnector.getInstance()
});
self.registrar = new EmbarkJS.Blockchain.Contract({
abi: config.registrarAbi,
address: config.registrarAddress,
web3: EmbarkJS.Blockchain.blockchainConnector.getInstance()
});
self.resolver = new EmbarkJS.Blockchain.Contract({
abi: config.resolverAbi,
address: config.resolverAddress,
web3: EmbarkJS.Blockchain.blockchainConnector.getInstance()
});
})
.catch(err => {
if (err.message.indexOf('Provider not set or invalid') > -1) {
console.warn(ERROR_MESSAGE);
return;
}
console.error(err);
}); });
}); self.registrar = new EmbarkJS.Blockchain.Contract({
abi: config.registrarAbi,
address: config.registrarAddress,
web3: EmbarkJS.Blockchain.blockchainConnector.getInstance()
});
self.resolver = new EmbarkJS.Blockchain.Contract({
abi: config.resolverAbi,
address: config.resolverAddress,
web3: EmbarkJS.Blockchain.blockchainConnector.getInstance()
});
})
.catch(err => {
if (err.message.indexOf('Provider not set or invalid') > -1) {
console.warn(ERROR_MESSAGE);
return;
}
console.error(err);
});
}; };
__embarkENS.resolve = function (name, callback) { __embarkENS.resolve = function (name, callback) {

View File

@ -5164,15 +5164,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2" lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000887, caniuse-lite@^1.0.30000929: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000887, caniuse-lite@^1.0.30000899, caniuse-lite@^1.0.30000929:
version "1.0.30000932" version "1.0.30000978"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz#d01763e9ce77810962ca7391ff827b5949ce4272" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000978.tgz#1e3346c27fc46bce9ac1ccd77863153a263dde56"
integrity sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A== integrity sha512-H6gK6kxUzG6oAwg/Jal279z8pHw0BzrpZfwo/CA9FFm/vA0l8IhDfkZtepyJNE2Y4V6Dp3P3ubz6czby1/Mgsw==
caniuse-lite@^1.0.30000899:
version "1.0.30000912"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000912.tgz#08e650d4090a9c0ab06bfd2b46b7d3ad6dcaea28"
integrity sha512-M3zAtV36U+xw5mMROlTXpAHClmPAor6GPKAMD5Yi7glCB5sbMPFtnQ3rGpk4XqPdUrrTIaVYSJZxREZWNy8QJg==
capture-exit@^1.2.0: capture-exit@^1.2.0:
version "1.2.0" version "1.2.0"