mirror of
https://github.com/embarklabs/embark.git
synced 2025-02-10 12:46:29 +00:00
refactor
remove code not beloging to code runner & other core modules; disable code generator and move contract code to its own module cleanup pipeline; start preparing for plugin based pipeline file generation initial work to write pipeline files through an api add action events to pipeline; generate contracts json and js files move old pipeline to its own module; generate basic artifacts re-add missing plugins function add basic embarkjs provider registration refactor embark-whisper; move whisper api; execute whisper code in console add api to register help cmds in console; start moving hardcoded help cmds out cleanup embark-graph add todos
This commit is contained in:
parent
783b555dd2
commit
50c3525374
@ -20,7 +20,7 @@
|
||||
"ipfs-api": "17.2.7"
|
||||
},
|
||||
"plugins": {
|
||||
"embark-dapp-test-service": {}
|
||||
"embarkjs-connector-web3": {}
|
||||
},
|
||||
"options": {
|
||||
"solc": {
|
||||
|
@ -4,16 +4,12 @@ import VM from "./vm";
|
||||
export { fs, VM };
|
||||
|
||||
import { Callback, Embark, Events, Logger } /* supplied by @types/embark in packages/embark-typings */ from "embark";
|
||||
import Web3 from "web3";
|
||||
|
||||
// TODO: ideally shouldn't be needed or should be done through an API
|
||||
import Web3 from "web3";
|
||||
const EmbarkJS = require("embarkjs");
|
||||
|
||||
export enum ProviderEventType {
|
||||
ProviderRegistered = "providerRegistered",
|
||||
ProviderSet = "providerSet",
|
||||
}
|
||||
|
||||
export default class CodeRunner {
|
||||
class CodeRunner {
|
||||
private ready: boolean = false;
|
||||
private blockchainConnected: boolean = false;
|
||||
private logger: Logger;
|
||||
@ -31,6 +27,7 @@ export default class CodeRunner {
|
||||
fs,
|
||||
},
|
||||
},
|
||||
// TODO: ideally shouldn't be needed or should be done through an API
|
||||
sandbox: {
|
||||
EmbarkJS,
|
||||
Web3,
|
||||
@ -39,17 +36,7 @@ export default class CodeRunner {
|
||||
|
||||
this.registerEvents();
|
||||
this.registerCommands();
|
||||
}
|
||||
|
||||
private generateListener(provider: string, eventType: ProviderEventType) {
|
||||
const providerStateName = `${provider}:${eventType}`;
|
||||
const eventName = `runcode:${providerStateName}`;
|
||||
this.events.setCommandHandler(eventName, (cb) => {
|
||||
if (this.providerStates[providerStateName] === true) {
|
||||
return cb();
|
||||
}
|
||||
this.events.once(eventName, cb);
|
||||
});
|
||||
this.ready = true;
|
||||
}
|
||||
|
||||
private registerEvents() {
|
||||
@ -61,44 +48,6 @@ export default class CodeRunner {
|
||||
cb(this.vm.options.sandbox);
|
||||
});
|
||||
this.events.setCommandHandler("runcode:eval", this.evalCode.bind(this));
|
||||
this.events.setCommandHandler("runcode:embarkjs:reset", (cb) => {
|
||||
this.resetEmbarkJS(cb);
|
||||
});
|
||||
this.events.on("contractsDeployed", () => {
|
||||
this.events.on("code-generator-ready", (_modifiedAssets: any) => {
|
||||
this.resetEmbarkJS();
|
||||
});
|
||||
});
|
||||
|
||||
// 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;
|
||||
}
|
||||
if (cb) { cb(); }
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
private registerVar(varName: string, code: any, cb = () => { }) {
|
||||
@ -121,3 +70,5 @@ export default class CodeRunner {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default CodeRunner;
|
||||
|
@ -38,6 +38,7 @@ class VM {
|
||||
"@babel/runtime-corejs2/core-js/promise",
|
||||
"@babel/runtime-corejs2/helpers/interopRequireDefault",
|
||||
"embark-utils",
|
||||
// TODO: ideally this shouldnt' be needed/here or should be configurable by the modules themselves somehow
|
||||
"embarkjs-ens",
|
||||
"embarkjs-ipfs",
|
||||
"embarkjs-swarm",
|
||||
|
@ -28,6 +28,8 @@ class Console {
|
||||
private history: string[];
|
||||
private cmdHistoryFile: string;
|
||||
private suggestions?: Suggestions;
|
||||
private providerReady: boolean;
|
||||
private helpCmds: any;
|
||||
|
||||
constructor(embark: Embark, options: any) {
|
||||
this.embark = embark;
|
||||
@ -41,6 +43,7 @@ class Console {
|
||||
this.history = [];
|
||||
this.cmdHistoryFile = options.cmdHistoryFile || dappPath(".embark", "cmd_history");
|
||||
this.loadHistory();
|
||||
this.helpCmds = {};
|
||||
|
||||
if (this.ipc.isServer()) {
|
||||
this.ipc.on("console:executeCmd", (cmd: string, cb: any) => {
|
||||
@ -57,6 +60,15 @@ class Console {
|
||||
this.saveHistory(cmd, true);
|
||||
});
|
||||
}
|
||||
this.events.setCommandHandler("console:register:helpCmd", (options: any, cb: any) => {
|
||||
const {cmdName, cmdHelp} = options;
|
||||
this.helpCmds[cmdName] = cmdHelp;
|
||||
if (cb) { cb(); }
|
||||
});
|
||||
this.events.setCommandHandler("console:unregister:helpCmd", (cmdName: string, cb: any) => {
|
||||
delete this.helpCmds[cmdName];
|
||||
if (cb) { cb(); }
|
||||
});
|
||||
this.events.setCommandHandler("console:executeCmd", this.executeCmd.bind(this));
|
||||
this.events.setCommandHandler("console:history", (cb: any) => this.getHistory(this.cmdHistorySize(), cb));
|
||||
this.registerConsoleCommands();
|
||||
@ -106,14 +118,20 @@ class Console {
|
||||
__("Welcome to Embark") + " " + this.version,
|
||||
"",
|
||||
__("possible commands are:"),
|
||||
// TODO: only if the blockchain is actually active!
|
||||
// will need to pass te current embark state here
|
||||
// TODO: this help commands should be passed through an API
|
||||
|
||||
chalk.cyan("ipfs") + " - " + __("instantiated js-ipfs object configured to the current environment (available if ipfs is enabled)"),
|
||||
chalk.cyan("swarm") + " - " + __("instantiated swarm-api object configured to the current environment (available if swarm is enabled)"),
|
||||
chalk.cyan("web3") + " - " + __("instantiated web3.js object configured to the current environment"),
|
||||
chalk.cyan("EmbarkJS") + " - " + __("EmbarkJS static functions for Storage, Messages, Names, etc."),
|
||||
chalk.cyan("log [process] on/off") + " - " + __("Activate or deactivate the logs of a sub-process. Options: blockchain, ipfs, webserver"),
|
||||
];
|
||||
|
||||
for (let cmdName in this.helpCmds) {
|
||||
let helpCmd = this.helpCmds[cmdName];
|
||||
helpText.push(chalk.cyan(cmdName) + " - " + helpCmd);
|
||||
}
|
||||
|
||||
// TODO: remove old helpDescriptions
|
||||
helpDescriptions.forEach((helpDescription) => {
|
||||
let matches = [] as string[];
|
||||
if (Array.isArray(helpDescription.matches)) {
|
||||
|
@ -14,6 +14,13 @@ interface Suggestion {
|
||||
|
||||
type SuggestionsList = Suggestion[];
|
||||
|
||||
// =============================================
|
||||
// =============================================
|
||||
// TODO: this should be moved to its own module
|
||||
// it's a plugin not a core module
|
||||
// =============================================
|
||||
// =============================================
|
||||
|
||||
export default class Suggestions {
|
||||
private embark: Embark;
|
||||
private events: Events;
|
||||
|
@ -62,7 +62,7 @@ export class ProcessLauncher {
|
||||
return self.exitCallback(code);
|
||||
}
|
||||
if (code) {
|
||||
this.logger.info(`Child Process ${this.name} exited with code ${code}`);
|
||||
self.logger.info(`Child Process ${this.name} exited with code ${code}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ export class ProcessManager {
|
||||
|
||||
this._registerApiCalls();
|
||||
this._registerEvents();
|
||||
this.events.once("deploy:beforeAll", this._registerCommands.bind(this));
|
||||
// TODO: removed because Process Manager shouldn't care or have knoweldge about deployment
|
||||
// this.events.once("deploy:beforeAll", this._registerCommands.bind(this));
|
||||
}
|
||||
|
||||
_registerApiCalls() {
|
||||
|
@ -34,7 +34,8 @@ class DeployTracker {
|
||||
if (this.chainFile === false) return;
|
||||
const self = this;
|
||||
|
||||
this.embark.registerActionForEvent("deploy:beforeAll", this.setCurrentChain.bind(this));
|
||||
// TODO: re-add
|
||||
// this.embark.registerActionForEvent("deploy:beforeAll", this.setCurrentChain.bind(this));
|
||||
|
||||
this.events.on("deploy:contract:deployed", (contract) => {
|
||||
self.trackContract(contract.className, contract.realRuntimeBytecode, contract.realArgs, contract.deployedAddress);
|
||||
|
@ -85,6 +85,7 @@ class ContractDeployer {
|
||||
}
|
||||
|
||||
checkAndDeployContract(contract, params, callback, returnObject) {
|
||||
console.dir("= checkAndDeployContract: " + contract.className);
|
||||
let self = this;
|
||||
contract.error = false;
|
||||
let accounts = [];
|
||||
@ -176,6 +177,7 @@ class ContractDeployer {
|
||||
return self.deployContract(contract, next, returnObject);
|
||||
}
|
||||
|
||||
console.dir("== emitAndRunActionsForEvent / should Deploy");
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:shouldDeploy', {contract: contract, shouldDeploy: true}, function(_err, params) {
|
||||
let trackedContract = params.contract;
|
||||
if (!params.shouldDeploy) {
|
||||
@ -202,7 +204,9 @@ class ContractDeployer {
|
||||
});
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
], (err,results) => {
|
||||
callback(err, results);
|
||||
});
|
||||
}
|
||||
|
||||
willNotDeployContract(contract, trackedContract, callback) {
|
||||
@ -212,26 +216,13 @@ class ContractDeployer {
|
||||
}
|
||||
|
||||
contractAlreadyDeployed(contract, trackedContract, callback) {
|
||||
console.dir("--> contractAlreadyDeployed")
|
||||
this.logFunction(contract)(contract.className.bold.cyan + __(" already deployed at ").green + trackedContract.address.bold.cyan);
|
||||
contract.deployedAddress = trackedContract.address;
|
||||
this.events.emit("deploy:contract:deployed", contract);
|
||||
|
||||
this.registerContract(contract, callback);
|
||||
}
|
||||
|
||||
registerContract(contract, callback) {
|
||||
this.events.request('code-generator:contract:custom', contract, (contractCode) => {
|
||||
this.events.request('runcode:eval', contractCode, (err) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
this.events.request('runcode:eval', contract.className, (err, result) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
this.events.emit("runcode:register", contract.className, result, callback);
|
||||
});
|
||||
});
|
||||
this.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, (err) => {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
@ -240,11 +231,13 @@ class ContractDeployer {
|
||||
}
|
||||
|
||||
deployContract(contract, callback, returnObject) {
|
||||
console.dir("deployContract")
|
||||
let self = this;
|
||||
let deployObject;
|
||||
|
||||
async.waterfall([
|
||||
function doLinking(next) {
|
||||
console.dir("= doLinking")
|
||||
|
||||
if (!contract.linkReferences || !Object.keys(contract.linkReferences).length) {
|
||||
return next();
|
||||
@ -288,11 +281,13 @@ class ContractDeployer {
|
||||
});
|
||||
},
|
||||
function applyBeforeDeploy(next) {
|
||||
console.dir("= applyBeforeDeploy")
|
||||
self.plugins.emitAndRunActionsForEvent('deploy:contract:beforeDeploy', {contract: contract}, (_params) => {
|
||||
next();
|
||||
});
|
||||
},
|
||||
function getGasPriceForNetwork(next) {
|
||||
console.dir("= getGasPriceForNetwork")
|
||||
self.events.request("blockchain:gasPrice", (err, gasPrice) => {
|
||||
if (err) {
|
||||
return next(new Error(__("could not get the gas price")));
|
||||
@ -302,6 +297,7 @@ class ContractDeployer {
|
||||
});
|
||||
},
|
||||
function createDeployObject(next) {
|
||||
console.dir("= createDeployObject")
|
||||
let contractCode = contract.code;
|
||||
let contractObject = self.blockchain.ContractObject({abi: contract.abiDefinition});
|
||||
let contractParams = (contract.realArgs || contract.args).slice();
|
||||
@ -343,6 +339,7 @@ class ContractDeployer {
|
||||
});
|
||||
},
|
||||
function deployTheContract(next) {
|
||||
console.dir("= deployTheContract " + contract.className)
|
||||
let estimatedCost = contract.gas * contract.gasPrice;
|
||||
|
||||
self.blockchain.deployContractFromObject(deployObject, {
|
||||
@ -350,6 +347,9 @@ class ContractDeployer {
|
||||
gas: contract.gas,
|
||||
gasPrice: contract.gasPrice
|
||||
}, function(error, receipt) {
|
||||
console.dir("--> contract deployed")
|
||||
console.dir(error)
|
||||
console.dir(receipt)
|
||||
if (error) {
|
||||
contract.error = error.message;
|
||||
self.events.emit("deploy:contract:error", contract);
|
||||
@ -366,19 +366,25 @@ class ContractDeployer {
|
||||
if(receipt) self.events.emit("deploy:contract:receipt", receipt);
|
||||
self.events.emit("deploy:contract:deployed", contract);
|
||||
|
||||
self.registerContract(contract, () => {
|
||||
// console.dir("__registerContract")
|
||||
// self.registerContract(contract, () => {
|
||||
console.dir("__runActionsForEvent deploy:contract:deployed")
|
||||
self.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, (err) => {
|
||||
console.dir("result __runActionsForEvent deploy:contract:deployed")
|
||||
if (err) {
|
||||
console.dir(err)
|
||||
return next(err);
|
||||
}
|
||||
next(null, receipt);
|
||||
});
|
||||
});
|
||||
}, hash => {
|
||||
self.logFunction(contract)(__("deploying") + " " + contract.className.bold.cyan + " " + __("with").green + " " + contract.gas + " " + __("gas at the price of").green + " " + contract.gasPrice + " " + __("Wei, estimated cost:").green + " " + estimatedCost + " Wei".green + " (txHash: " + hash.bold.cyan + ")");
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
], (__err, __results) => {
|
||||
console.dir("--- deployed Contract")
|
||||
callback(__err, __results)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -54,9 +54,12 @@ class DeployManager {
|
||||
function (next) {
|
||||
self.logger.info(__('Executing pre-deploy actions...'));
|
||||
self.plugins.emitAndRunActionsForEvent("deploy:beforeAll", (err) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
// console.dir("== err")
|
||||
// console.dir(err)
|
||||
// TODO: err is a function for some reason
|
||||
// if (err) {
|
||||
// return next(err);
|
||||
// }
|
||||
self.logger.info(__('Pre-deploy actions done. Deploying contracts'));
|
||||
next();
|
||||
});
|
||||
@ -64,6 +67,8 @@ class DeployManager {
|
||||
function (next) {
|
||||
const contractDeploys = {};
|
||||
const errors = [];
|
||||
console.dir("=== contracts")
|
||||
console.dir(contracts.map((x) => x.className))
|
||||
contracts.forEach(contract => {
|
||||
function deploy(result, callback) {
|
||||
if (typeof result === 'function') {
|
||||
@ -71,7 +76,10 @@ class DeployManager {
|
||||
}
|
||||
contract._gasLimit = self.gasLimit;
|
||||
self.events.request('deploy:contract', contract, (err) => {
|
||||
console.dir("contract deployed " + contract.className)
|
||||
if (err) {
|
||||
console.dir("== err deploying contract");
|
||||
console.dir(err);
|
||||
contract.error = err.message || err;
|
||||
if (contract.error === constants.blockchain.gasAllowanceError) {
|
||||
self.logger.error(`[${contract.className}]: ${constants.blockchain.gasAllowanceErrorMessage}`);
|
||||
@ -93,7 +101,14 @@ class DeployManager {
|
||||
contractDeploys[className].push(deploy);
|
||||
});
|
||||
|
||||
console.dir("== async.auto");
|
||||
console.dir(Object.keys(contractDeploys));
|
||||
console.dir(contractDeploys);
|
||||
async.auto(contractDeploys, function(_err, _results) {
|
||||
if (_err) {
|
||||
console.dir("error deploying contracts")
|
||||
console.dir(_err)
|
||||
}
|
||||
if (errors.length) {
|
||||
_err = __("Error deploying contracts. Please fix errors to continue.");
|
||||
self.logger.error(_err);
|
||||
@ -109,6 +124,7 @@ class DeployManager {
|
||||
});
|
||||
}
|
||||
], (err) => {
|
||||
console.dir("==== finished deploying")
|
||||
if (err) {
|
||||
self.logger.error(err);
|
||||
}
|
||||
|
@ -150,6 +150,12 @@ class ENS {
|
||||
|
||||
registerEvents() {
|
||||
this.embark.registerActionForEvent("deploy:beforeAll", this.configureContractsAndRegister.bind(this));
|
||||
if (this.eventsRegistered) {
|
||||
return;
|
||||
}
|
||||
this.eventsRegistered = true;
|
||||
// TODO: re-add
|
||||
// this.embark.registerActionForEvent("deploy:beforeAll", this.configureContractsAndRegister.bind(this));
|
||||
this.events.on('blockchain:reseted', this.reset.bind(this));
|
||||
this.events.setCommandHandler("storage:ens:associate", this.associateStorageToEns.bind(this));
|
||||
this.events.setCommandHandler("ens:config", this.getEnsConfig.bind(this));
|
||||
|
@ -1,21 +1,16 @@
|
||||
const async = require('async');
|
||||
const Viz = require('viz.js');
|
||||
const fs = require('fs');
|
||||
|
||||
class GraphGenerator {
|
||||
constructor(embark, _options) {
|
||||
const self = this;
|
||||
this.embark = embark;
|
||||
this.events = embark.events;
|
||||
this.contracts = [];
|
||||
|
||||
this.events.setCommandHandler("graph:create", function(options, cb) {
|
||||
self.generate(options);
|
||||
cb();
|
||||
});
|
||||
this.events.setCommandHandler("graph:create", this.generate.bind(this));
|
||||
}
|
||||
|
||||
/*eslint complexity: ["error", 21]*/
|
||||
generate(options) {
|
||||
generate(options, cb) {
|
||||
const self = this;
|
||||
let id = 0;
|
||||
let contractString = "";
|
||||
@ -23,6 +18,7 @@ class GraphGenerator {
|
||||
let idMapping = {};
|
||||
let contractInheritance = {};
|
||||
let contractsDependencies = {};
|
||||
this.contracts = [];
|
||||
|
||||
async.waterfall([
|
||||
function getContractList(next) {
|
||||
@ -134,12 +130,13 @@ class GraphGenerator {
|
||||
|
||||
let svg = Viz(dot);
|
||||
|
||||
fs.writeFileSync(options.output, svg, (err) => {
|
||||
self.embark.fs.writeFileSync(options.output, svg, (err) => {
|
||||
if (err) throw err;
|
||||
next();
|
||||
});
|
||||
}
|
||||
], function(_err, _result) {
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ const ProcessLogsApi = require('embark-process-logs-api');
|
||||
|
||||
const EMBARK_PROCESS_NAME = 'embark';
|
||||
|
||||
// TODO: looks unnecessary, should be moved to a common module together with embark-process-logs-api
|
||||
|
||||
/**
|
||||
* EmbarkListener has two functions:
|
||||
* 1. Register API endpoints (HTTP GET and WS) to retrieve embark logs.
|
||||
|
@ -53,8 +53,7 @@
|
||||
"embark-i18n": "^4.1.0-beta.3",
|
||||
"embark-utils": "^4.1.0-beta.5",
|
||||
"find-up": "2.1.0",
|
||||
"fs-extra": "7.0.1",
|
||||
"webpack": "4.29.3"
|
||||
"fs-extra": "7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.2.3",
|
||||
|
119
packages/embark-pipeline/src/api.js
Normal file
119
packages/embark-pipeline/src/api.js
Normal file
@ -0,0 +1,119 @@
|
||||
const path = require('path');
|
||||
import { dappPath, fileTreeSort } from 'embark-utils';
|
||||
|
||||
class API {
|
||||
|
||||
constructor(embark, _options) {
|
||||
this.plugins = embark.config.plugins;
|
||||
}
|
||||
|
||||
registerAPIs() {
|
||||
let plugin = this.plugins.createPlugin('deployment', {});
|
||||
plugin.registerAPICall(
|
||||
'get',
|
||||
'/embark-api/file',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.query.path);
|
||||
} catch (error) {
|
||||
return res.send({ error: error.message });
|
||||
}
|
||||
|
||||
const name = path.basename(req.query.path);
|
||||
const content = this.fs.readFileSync(req.query.path, 'utf8');
|
||||
res.send({ name, content, path: req.query.path });
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'post',
|
||||
'/embark-api/folders',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.body.path);
|
||||
} catch (error) {
|
||||
return res.send({ error: error.message });
|
||||
}
|
||||
|
||||
this.fs.mkdirpSync(req.body.path);
|
||||
const name = path.basename(req.body.path);
|
||||
res.send({ name, path: req.body.path });
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'post',
|
||||
'/embark-api/files',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.body.path);
|
||||
} catch (error) {
|
||||
return res.send({ error: error.message });
|
||||
}
|
||||
|
||||
this.fs.writeFileSync(req.body.path, req.body.content, { encoding: 'utf8' });
|
||||
const name = path.basename(req.body.path);
|
||||
res.send({ name, path: req.body.path, content: req.body.content });
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'delete',
|
||||
'/embark-api/file',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.query.path, { ensureExists: true });
|
||||
} catch (error) {
|
||||
return res.send({ error: error.message });
|
||||
}
|
||||
this.fs.removeSync(req.query.path);
|
||||
res.send();
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'get',
|
||||
'/embark-api/files',
|
||||
(req, res) => {
|
||||
const rootPath = dappPath();
|
||||
|
||||
const walk = (dir, filelist = []) => this.fs.readdirSync(dir).map(name => {
|
||||
let isRoot = rootPath === dir;
|
||||
if (this.fs.statSync(path.join(dir, name)).isDirectory()) {
|
||||
return {
|
||||
isRoot,
|
||||
name,
|
||||
dirname: dir,
|
||||
path: path.join(dir, name),
|
||||
isHidden: (name.indexOf('.') === 0 || name === "node_modules"),
|
||||
children: fileTreeSort(walk(path.join(dir, name), filelist))
|
||||
};
|
||||
}
|
||||
return {
|
||||
name,
|
||||
isRoot,
|
||||
path: path.join(dir, name),
|
||||
dirname: dir,
|
||||
isHidden: (name.indexOf('.') === 0 || name === "node_modules")
|
||||
};
|
||||
});
|
||||
const files = fileTreeSort(walk(dappPath()));
|
||||
res.send(files);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
apiGuardBadFile(pathToCheck, options = {ensureExists: false}) {
|
||||
const dir = path.dirname(pathToCheck);
|
||||
const error = new Error('Path is invalid');
|
||||
if (options.ensureExists && !this.fs.existsSync(pathToCheck)) {
|
||||
throw error;
|
||||
}
|
||||
if (!dir.startsWith(dappPath())) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = API;
|
@ -1,402 +1,88 @@
|
||||
const path = require('path');
|
||||
const async = require('async');
|
||||
import { __ } from 'embark-i18n';
|
||||
import { dappPath, joinPath, LongRunningProcessTimer, fileTreeSort } from 'embark-utils';
|
||||
import { ProcessLauncher } from 'embark-core';
|
||||
const constants = require('embark-core/constants');
|
||||
const WebpackConfigReader = require('./webpackConfigReader');
|
||||
import { dappPath } from 'embark-utils';
|
||||
|
||||
const PipelineAPI = require('./api.js');
|
||||
|
||||
class Pipeline {
|
||||
constructor(embark, options) {
|
||||
this.embark = embark;
|
||||
this.env = embark.config.env;
|
||||
this.buildDir = embark.config.buildDir;
|
||||
this.contractsFiles = embark.config.contractsFiles;
|
||||
this.assetFiles = embark.config.assetFiles;
|
||||
this.embarkConfig = embark.config.embarkConfig;
|
||||
this.events = embark.events;
|
||||
this.logger = embark.config.logger;
|
||||
this.plugins = embark.config.plugins;
|
||||
this.fs = embark.fs;
|
||||
this.webpackConfigName = options.webpackConfigName;
|
||||
this.pipelinePlugins = this.plugins.getPluginsFor('pipeline');
|
||||
this.pipelineConfig = embark.config.pipelineConfig;
|
||||
this.isFirstBuild = true;
|
||||
this.useDashboard = options.useDashboard;
|
||||
this.files = {}
|
||||
|
||||
// track changes to the pipeline config in the filesystem
|
||||
this.events.on('config:load:pipeline', (pipelineConfig) => {
|
||||
this.pipelineConfig = pipelineConfig;
|
||||
this.api = new PipelineAPI(embark, options);
|
||||
this.api.registerAPIs();
|
||||
|
||||
this.events.setCommandHandler('pipeline:generateAll', this.generateAll.bind(this));
|
||||
|
||||
this.events.setCommandHandler('pipeline:register', (params, cb) => {
|
||||
this.files[dappPath(...params.path, params.file)] = params;
|
||||
if (cb) { cb(); }
|
||||
});
|
||||
|
||||
this.events.setCommandHandler('pipeline:build', (options, callback) => {
|
||||
if(!this.pipelineConfig.enabled) {
|
||||
return this.buildContracts([], callback);
|
||||
}
|
||||
this.build(options, callback);
|
||||
});
|
||||
this.events.setCommandHandler('pipeline:build:contracts', callback => this.buildContracts([], callback));
|
||||
this.fs.removeSync(this.buildDir);
|
||||
|
||||
let plugin = this.plugins.createPlugin('deployment', {});
|
||||
plugin.registerAPICall(
|
||||
'get',
|
||||
'/embark-api/file',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.query.path);
|
||||
} catch (error) {
|
||||
return res.send({error: error.message});
|
||||
}
|
||||
|
||||
const name = path.basename(req.query.path);
|
||||
const content = this.fs.readFileSync(req.query.path, 'utf8');
|
||||
res.send({name, content, path: req.query.path});
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'post',
|
||||
'/embark-api/folders',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.body.path);
|
||||
} catch (error) {
|
||||
return res.send({error: error.message});
|
||||
}
|
||||
|
||||
this.fs.mkdirpSync(req.body.path);
|
||||
const name = path.basename(req.body.path);
|
||||
res.send({name, path: req.body.path});
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'post',
|
||||
'/embark-api/files',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.body.path);
|
||||
} catch (error) {
|
||||
return res.send({error: error.message});
|
||||
}
|
||||
|
||||
this.fs.writeFileSync(req.body.path, req.body.content, {encoding: 'utf8'});
|
||||
const name = path.basename(req.body.path);
|
||||
res.send({name, path: req.body.path, content: req.body.content});
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'delete',
|
||||
'/embark-api/file',
|
||||
(req, res) => {
|
||||
try {
|
||||
this.apiGuardBadFile(req.query.path, {ensureExists: true});
|
||||
} catch (error) {
|
||||
return res.send({error: error.message});
|
||||
}
|
||||
this.fs.removeSync(req.query.path);
|
||||
res.send();
|
||||
}
|
||||
);
|
||||
|
||||
plugin.registerAPICall(
|
||||
'get',
|
||||
'/embark-api/files',
|
||||
(req, res) => {
|
||||
const rootPath = dappPath();
|
||||
|
||||
const walk = (dir, filelist = []) => this.fs.readdirSync(dir).map(name => {
|
||||
let isRoot = rootPath === dir;
|
||||
if (this.fs.statSync(path.join(dir, name)).isDirectory()) {
|
||||
return {
|
||||
isRoot,
|
||||
name,
|
||||
dirname: dir,
|
||||
path: path.join(dir, name),
|
||||
isHidden: (name.indexOf('.') === 0 || name === "node_modules"),
|
||||
children: fileTreeSort(walk(path.join(dir, name), filelist))
|
||||
};
|
||||
}
|
||||
return {
|
||||
name,
|
||||
isRoot,
|
||||
path: path.join(dir, name),
|
||||
dirname: dir,
|
||||
isHidden: (name.indexOf('.') === 0 || name === "node_modules")
|
||||
};
|
||||
});
|
||||
const files = fileTreeSort(walk(dappPath()));
|
||||
res.send(files);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
apiGuardBadFile(pathToCheck, options = {ensureExists: false}) {
|
||||
const dir = path.dirname(pathToCheck);
|
||||
const error = new Error('Path is invalid');
|
||||
if (options.ensureExists && !this.fs.existsSync(pathToCheck)) {
|
||||
throw error;
|
||||
}
|
||||
if (!dir.startsWith(dappPath())) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
build({modifiedAssets}, callback) {
|
||||
let self = this;
|
||||
const importsList = {};
|
||||
let placeholderPage;
|
||||
const contractsDir = dappPath(self.embarkConfig.generationDir, constants.dappArtifacts.contractsJs);
|
||||
|
||||
if (!self.assetFiles || !Object.keys(self.assetFiles).length) {
|
||||
return self.buildContracts([], callback);
|
||||
}
|
||||
generateAll(cb) {
|
||||
console.dir("generating all files");
|
||||
|
||||
async.waterfall([
|
||||
function createPlaceholderPage(next) {
|
||||
if (self.isFirstBuild) {
|
||||
self.isFirstBuild = false;
|
||||
return next();
|
||||
}
|
||||
self.events.request('placeholder:build', next);
|
||||
},
|
||||
(next) => self.buildContracts(importsList, next),
|
||||
function createImportList(next) {
|
||||
importsList["Embark/EmbarkJS"] = dappPath(self.embarkConfig.generationDir, constants.dappArtifacts.embarkjs);
|
||||
importsList["Embark/contracts"] = contractsDir;
|
||||
|
||||
self.plugins.getPluginsProperty('imports', 'imports').forEach(importObject => {
|
||||
let [importName, importLocation] = importObject;
|
||||
importsList[importName] = importLocation;
|
||||
(next) => {
|
||||
this.plugins.runActionsForEvent("pipeline:generateAll:before", {}, (err) => {
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
(next) => {
|
||||
// TODO: make this async
|
||||
for (let fileParams of Object.values(this.files)) {
|
||||
if (fileParams.format === 'json') {
|
||||
this.writeJSONFile(fileParams)
|
||||
} else {
|
||||
this.writeFile(fileParams)
|
||||
}
|
||||
}
|
||||
next();
|
||||
},
|
||||
function shouldRunWebpack(next) {
|
||||
// assuming we got here because an asset was changed, let's check our webpack config
|
||||
// to see if the changed asset requires webpack to run
|
||||
if (!(modifiedAssets && modifiedAssets.length)) return next(null, false);
|
||||
const configReader = new WebpackConfigReader({webpackConfigName: self.webpackConfigName});
|
||||
return configReader.readConfig((err, config) => {
|
||||
if (err) return next(err);
|
||||
|
||||
if (typeof config !== 'object' || config === null) {
|
||||
return next(__('Pipeline: bad webpack config, the resolved config was null or not an object'));
|
||||
}
|
||||
|
||||
const shouldRun = modifiedAssets.some(modifiedAsset => config.module.rules.some(rule => rule.test.test(modifiedAsset)));
|
||||
return next(null, !shouldRun);
|
||||
});
|
||||
},
|
||||
function runWebpack(shouldNotRun, next) {
|
||||
if (shouldNotRun) return next();
|
||||
const assets = Object.keys(self.assetFiles).filter(key => key.match(/\.js$/));
|
||||
if (!assets || !assets.length) {
|
||||
return next();
|
||||
}
|
||||
let strAssets = '';
|
||||
if (!self.useDashboard) {
|
||||
assets.forEach(key => {
|
||||
strAssets += ('\n ' + (joinPath(self.buildDir, key)).bold.dim);
|
||||
});
|
||||
}
|
||||
const timer = new LongRunningProcessTimer(
|
||||
self.logger,
|
||||
'webpack',
|
||||
'0',
|
||||
`${'Pipeline:'.cyan} Bundling dapp using '${self.webpackConfigName}' config...${strAssets}`,
|
||||
`${'Pipeline:'.cyan} Still bundling dapp using '${self.webpackConfigName}' config... ({{duration}})${strAssets}`,
|
||||
`${'Pipeline:'.cyan} Finished bundling dapp in {{duration}}${strAssets}`,
|
||||
{
|
||||
showSpinner: !self.useDashboard,
|
||||
interval: self.useDashboard ? 5000 : 1000,
|
||||
longRunningThreshold: 15000
|
||||
}
|
||||
);
|
||||
timer.start();
|
||||
let built = false;
|
||||
const webpackProcess = new ProcessLauncher({
|
||||
embark: self.embark,
|
||||
plugins: self.plugins,
|
||||
modulePath: joinPath(__dirname, 'webpackProcess.js'),
|
||||
logger: self.logger,
|
||||
events: self.events,
|
||||
exitCallback: code => {
|
||||
if (!built) {
|
||||
return next(`Webpack build exited with code ${code} before the process finished`);
|
||||
}
|
||||
if (code) {
|
||||
self.logger.error(__('Webpack build process exited with code ', code));
|
||||
}
|
||||
}
|
||||
});
|
||||
webpackProcess.send({
|
||||
action: constants.pipeline.init,
|
||||
options: {
|
||||
webpackConfigName: self.webpackConfigName,
|
||||
pipelineConfig: self.pipelineConfig,
|
||||
fs: self.embark.fs
|
||||
}
|
||||
});
|
||||
webpackProcess.send({action: constants.pipeline.build, assets: self.assetFiles, importsList});
|
||||
|
||||
webpackProcess.once('result', constants.pipeline.built, (msg) => {
|
||||
built = true;
|
||||
webpackProcess.kill();
|
||||
return next(msg.error);
|
||||
});
|
||||
webpackProcess.once('result', constants.pipeline.webpackDone, () => {
|
||||
timer.end();
|
||||
});
|
||||
},
|
||||
function assetFileWrite(next) {
|
||||
async.eachOf(
|
||||
// assetFileWrite should not process .js files
|
||||
Object.keys(self.assetFiles)
|
||||
.filter(key => !key.match(/\.js$/))
|
||||
.reduce((obj, key) => {
|
||||
obj[key] = self.assetFiles[key];
|
||||
return obj;
|
||||
}, {}),
|
||||
function (files, targetFile, cb) {
|
||||
const isDir = targetFile.slice(-1) === '/' || targetFile.slice(-1) === '\\' || targetFile.indexOf('.') === -1;
|
||||
// if it's not a directory
|
||||
if (!isDir) {
|
||||
self.logger.info('Pipeline: '.cyan + __("writing file") + " " + (joinPath(self.buildDir, targetFile)).bold.dim);
|
||||
}
|
||||
async.map(
|
||||
files,
|
||||
function (file, fileCb) {
|
||||
self.logger.trace("reading " + file.path);
|
||||
file.content.then((fileContent) => {
|
||||
self.runPlugins(file, fileContent, fileCb);
|
||||
}).catch(fileCb);
|
||||
},
|
||||
function (err, contentFiles) {
|
||||
if (err) {
|
||||
self.logger.error('Pipeline: '.cyan + __('errors found while generating') + ' ' + targetFile);
|
||||
}
|
||||
let dir = targetFile.split('/').slice(0, -1).join('/');
|
||||
self.logger.trace(`${'Pipeline:'.cyan} creating dir ` + joinPath(self.buildDir, dir));
|
||||
self.fs.mkdirpSync(joinPath(self.buildDir, dir));
|
||||
|
||||
// if it's a directory
|
||||
if (isDir) {
|
||||
let targetDir = targetFile;
|
||||
|
||||
if (targetDir.slice(-1) !== '/') {
|
||||
targetDir = targetDir + '/';
|
||||
}
|
||||
|
||||
async.each(contentFiles, function (file, eachCb) {
|
||||
let filename = file.path.replace(file.basedir + '/', '');
|
||||
self.logger.info(`${'Pipeline:'.cyan} writing file ` + (joinPath(self.buildDir, targetDir, filename)).bold.dim);
|
||||
|
||||
self.fs.copy(file.path, joinPath(self.buildDir, targetDir, filename), {overwrite: true}, eachCb);
|
||||
}, cb);
|
||||
return;
|
||||
}
|
||||
|
||||
let content = contentFiles.map(file => {
|
||||
if (file === undefined) {
|
||||
return "";
|
||||
}
|
||||
return file.content;
|
||||
}).join("\n");
|
||||
|
||||
if (new RegExp(/^index.html?/i).test(targetFile)) {
|
||||
targetFile = targetFile.replace('index', 'index-temp');
|
||||
placeholderPage = targetFile;
|
||||
}
|
||||
self.fs.writeFile(joinPath(self.buildDir, targetFile), content, cb);
|
||||
}
|
||||
);
|
||||
},
|
||||
next
|
||||
);
|
||||
},
|
||||
function removePlaceholderPage(next) {
|
||||
let placeholderFile = joinPath(self.buildDir, placeholderPage);
|
||||
self.fs.access(joinPath(self.buildDir, placeholderPage), (err) => {
|
||||
if (err) return next(); // index-temp doesn't exist, do nothing
|
||||
|
||||
// rename index-temp.htm/l to index.htm/l, effectively replacing our placeholder page
|
||||
// with the contents of the built index.html page
|
||||
self.fs.move(placeholderFile, placeholderFile.replace('index-temp', 'index'), {overwrite: true}, next);
|
||||
(next) => {
|
||||
this.plugins.runActionsForEvent("pipeline:generateAll:after", {}, (err) => {
|
||||
next(err);
|
||||
});
|
||||
}
|
||||
], callback);
|
||||
], () => {
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
buildContracts(importsList, cb) {
|
||||
writeJSONFile(params) {
|
||||
const self = this;
|
||||
const dir = dappPath(...params.path);
|
||||
const filename = dappPath(...params.path, params.file);
|
||||
const content = params.content;
|
||||
|
||||
async.waterfall([
|
||||
function makeDirectory(next) {
|
||||
self.fs.mkdirp(dappPath(self.buildDir, 'contracts'), err => next(err));
|
||||
self.fs.mkdirp(dir, err => next(err));
|
||||
},
|
||||
function getContracts(next) {
|
||||
self.events.request('contracts:list', next);
|
||||
},
|
||||
function writeContractsJSON(contracts, next) {
|
||||
async.each(contracts, (contract, eachCb) => {
|
||||
self.fs.writeJson(dappPath(
|
||||
self.buildDir,
|
||||
'contracts', contract.className + '.json'
|
||||
), contract, {spaces: 2}, eachCb);
|
||||
}, () => next(null, contracts));
|
||||
},
|
||||
function writeContractJS(contracts, next) {
|
||||
const contractsDir = dappPath(self.embarkConfig.generationDir, constants.dappArtifacts.contractsJs);
|
||||
self.fs.mkdirp(contractsDir, err => {
|
||||
if (err) return next(err);
|
||||
|
||||
// Create a file index.js that requires all contract files
|
||||
// Used to enable alternate import syntax:
|
||||
// e.g. import {Token} from 'Embark/contracts'
|
||||
// e.g. import * as Contracts from 'Embark/contracts'
|
||||
let importsHelperFile = self.fs.createWriteStream(joinPath(contractsDir, 'index.js'));
|
||||
importsHelperFile.write('module.exports = {\n');
|
||||
|
||||
async.eachOf(contracts, (contract, idx, eachCb) => {
|
||||
self.events.request('code-generator:contract', contract.className, (err, contractPath) => {
|
||||
if (err) {
|
||||
return eachCb(err);
|
||||
}
|
||||
importsList["Embark/contracts/" + contract.className] = dappPath(contractPath);
|
||||
|
||||
// add the contract to the exports list to support alternate import syntax
|
||||
importsHelperFile.write(`"${contract.className}": require('./${contract.className}').default,\n`);
|
||||
eachCb();
|
||||
});
|
||||
}, () => {
|
||||
importsHelperFile.write('\n};'); // close the module.exports = {}
|
||||
importsHelperFile.close(next); // close the write stream
|
||||
});
|
||||
});
|
||||
function writeContractsJSON(next) {
|
||||
self.fs.writeJson(filename, content, { spaces: 2 }, () => { next() });
|
||||
}
|
||||
], cb);
|
||||
], () => {
|
||||
});
|
||||
}
|
||||
|
||||
runPlugins(file, fileContent, fileCb) {
|
||||
// TODO: can be refactored by joining with method above
|
||||
writeFile(params) {
|
||||
const self = this;
|
||||
if (self.pipelinePlugins.length <= 0) {
|
||||
return fileCb(null, {content: fileContent, path: file.path, basedir: file.basedir, modified: true});
|
||||
}
|
||||
async.eachSeries(self.pipelinePlugins, (plugin, pluginCB) => {
|
||||
if (file.options && file.options.skipPipeline) {
|
||||
return pluginCB();
|
||||
}
|
||||
const dir = dappPath(...params.path);
|
||||
const filename = dappPath(...params.path, params.file);
|
||||
const content = params.content;
|
||||
|
||||
fileContent = plugin.runPipeline({targetFile: file.path, source: fileContent});
|
||||
file.modified = true;
|
||||
pluginCB();
|
||||
}, err => {
|
||||
if (err) {
|
||||
self.logger.error(err.message);
|
||||
async.waterfall([
|
||||
function makeDirectory(next) {
|
||||
self.fs.mkdirp(dir, err => next(err));
|
||||
},
|
||||
function writeFile(next) {
|
||||
self.fs.writeFile(filename, content, (err) => { next(err, true) });
|
||||
}
|
||||
return fileCb(null, {content: fileContent, path: file.path, basedir: file.basedir, modified: true});
|
||||
], () => {
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
const {escapeHtml, LogHandler} = require('embark-utils');
|
||||
|
||||
// TODO: looks unnecessary, should be moved to a common module together with embark-listener
|
||||
|
||||
class ProcessLogsApi {
|
||||
constructor({embark, processName, silent}) {
|
||||
this.embark = embark;
|
||||
|
@ -14,11 +14,11 @@ class SpecialConfigs {
|
||||
this.embark = embark;
|
||||
this.config = embark.config;
|
||||
|
||||
this.registerBeforeAllDeployAction();
|
||||
this.registerAfterDeployAction();
|
||||
this.registerBeforeDeployAction();
|
||||
this.registerOnDeployAction();
|
||||
this.registerDeployIfAction();
|
||||
// this.registerBeforeAllDeployAction();
|
||||
// this.registerAfterDeployAction();
|
||||
// this.registerBeforeDeployAction();
|
||||
// this.registerOnDeployAction();
|
||||
// this.registerDeployIfAction();
|
||||
}
|
||||
|
||||
replaceWithENSAddress(cmd, callback) {
|
||||
|
@ -69,9 +69,10 @@ class SolcTest extends Test {
|
||||
async.series(fns, next);
|
||||
},
|
||||
function resetEmbarkJs(file, next) {
|
||||
self.events.request("runcode:embarkjs:reset", (err) => {
|
||||
next(err, file);
|
||||
});
|
||||
// self.events.request("runcode:embarkjs:reset", (err) => {
|
||||
// next(err, file);
|
||||
// });
|
||||
next(err, file);
|
||||
}
|
||||
], cb);
|
||||
}
|
||||
|
@ -169,9 +169,8 @@ class Test {
|
||||
}
|
||||
this.firstRunConfig = false;
|
||||
this.events.request("blockchain:ready", () => {
|
||||
this.events.request("code-generator:embarkjs:build", () => {
|
||||
this.events.request("runcode:embarkjs:reset", callback);
|
||||
});
|
||||
// this.events.request("runcode:embarkjs:reset", callback);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class Watcher {
|
||||
this.events.setCommandHandler('watcher:restart', () => this.restart());
|
||||
}
|
||||
|
||||
// TODO: it needs to be more agnostic, the files to watch should be registered through the plugin api
|
||||
start() {
|
||||
let self = this;
|
||||
// TODO: should come from the config object instead of reading the file
|
||||
|
@ -20,21 +20,28 @@ class EmbarkWeb3 {
|
||||
async addWeb3ToEmbarkJS() {
|
||||
let blockchainConnectorReady = false;
|
||||
|
||||
const web3LocationPromise = this.getWeb3Location();
|
||||
code += "\nEmbarkJS.Blockchain.registerProvider('web3', embarkJSConnectorWeb3);";
|
||||
// code += "\nEmbarkJS.Blockchain.setProvider('web3', {});";
|
||||
|
||||
this.events.setCommandHandler('blockchain:connector:ready', (cb) => {
|
||||
if (blockchainConnectorReady) {
|
||||
return cb();
|
||||
code += "\nEmbarkJS.Blockchain.setProvider('web3', {web3});";
|
||||
|
||||
this.events.request('runcode:eval', code, (err) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
this.events.once("blockchain:connector:ready", () => {
|
||||
cb();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
web3LocationPromise.then((_web3Location) => {
|
||||
blockchainConnectorReady = true;
|
||||
this.events.emit('blockchain:connector:ready');
|
||||
});
|
||||
registerWeb3Help() {
|
||||
this.events.request('console:register:helpCmd', {
|
||||
cmdName: "web3",
|
||||
cmdHelp: __("instantiated web3.js object configured to the current environment")
|
||||
}, () => { })
|
||||
}
|
||||
|
||||
// ===============
|
||||
// ===============
|
||||
// ===============
|
||||
|
||||
let web3Location = await web3LocationPromise;
|
||||
web3Location = normalizePath(web3Location, true);
|
||||
|
88
packages/embark-whisper/src/api.js
Normal file
88
packages/embark-whisper/src/api.js
Normal file
@ -0,0 +1,88 @@
|
||||
const {parallel} = require('async');
|
||||
const {fromEvent} = require('rxjs');
|
||||
const {map, takeUntil} = require('rxjs/operators');
|
||||
|
||||
import whisper from 'embarkjs-whisper';
|
||||
|
||||
const sendMessage = whisper.real_sendMessage;
|
||||
const listenTo = whisper.real_listenTo;
|
||||
|
||||
class API {
|
||||
|
||||
constructor(embark, web3) {
|
||||
this.embark = embark;
|
||||
this.logger = embark.logger;
|
||||
this.web3 = web3;
|
||||
this.registerAPICalls();
|
||||
}
|
||||
|
||||
registerAPICalls() {
|
||||
const self = this;
|
||||
if (self.apiCallsRegistered) {
|
||||
return;
|
||||
}
|
||||
self.apiCallsRegistered = true;
|
||||
let symKeyID, sig;
|
||||
parallel([
|
||||
function(paraCb) {
|
||||
self.web3.shh.newSymKey((err, id) => {
|
||||
symKeyID = id;
|
||||
paraCb(err);
|
||||
});
|
||||
},
|
||||
function(paraCb) {
|
||||
self.web3.shh.newKeyPair((err, id) => {
|
||||
sig = id;
|
||||
paraCb(err);
|
||||
});
|
||||
}
|
||||
], (err) => {
|
||||
if (err) {
|
||||
self.logger.error('Error getting Whisper keys:', err.message || err);
|
||||
return;
|
||||
}
|
||||
self.embark.registerAPICall(
|
||||
'post',
|
||||
'/embark-api/communication/sendMessage',
|
||||
(req, res) => {
|
||||
sendMessage({
|
||||
topic: req.body.topic,
|
||||
data: req.body.message,
|
||||
sig,
|
||||
symKeyID,
|
||||
fromAscii: self.web3.utils.asciiToHex,
|
||||
toHex: self.web3.utils.toHex,
|
||||
post: self.web3.shh.post
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
return res.status(500).send({error: err});
|
||||
}
|
||||
res.send(result);
|
||||
});
|
||||
});
|
||||
|
||||
self.embark.registerAPICall(
|
||||
'ws',
|
||||
'/embark-api/communication/listenTo/:topic',
|
||||
(ws, req) => {
|
||||
const obs = listenTo({
|
||||
toAscii: self.web3.utils.hexToAscii,
|
||||
toHex: self.web3.utils.toHex,
|
||||
topic: req.params.topic,
|
||||
sig,
|
||||
subscribe: self.web3.shh.subscribe,
|
||||
symKeyID
|
||||
}).pipe(takeUntil(fromEvent(ws, 'close').pipe(map(() => (
|
||||
delete self.webSocketsChannels[req.params.topic]
|
||||
)))));
|
||||
self.webSocketsChannels[req.params.topic] = obs;
|
||||
obs.subscribe(data => {
|
||||
ws.send(JSON.stringify(data));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = API;
|
@ -1,21 +1,12 @@
|
||||
/* global __dirname module require setTimeout */
|
||||
|
||||
import { __ } from 'embark-i18n';
|
||||
import {dappPath, canonicalHost, defaultHost} from 'embark-utils';
|
||||
let Web3 = require('web3');
|
||||
const {parallel} = require('async');
|
||||
const {fromEvent} = require('rxjs');
|
||||
const {map, takeUntil} = require('rxjs/operators');
|
||||
const constants = require('embark-core/constants');
|
||||
import * as path from 'path';
|
||||
const API = require('./api.js');
|
||||
|
||||
const EMBARK_RESOURCE_ORIGIN = "http://embark";
|
||||
|
||||
import whisper from 'embarkjs-whisper';
|
||||
|
||||
const sendMessage = whisper.real_sendMessage;
|
||||
const listenTo = whisper.real_listenTo;
|
||||
|
||||
class Whisper {
|
||||
constructor(embark, options) {
|
||||
this.logger = embark.logger;
|
||||
@ -37,31 +28,49 @@ class Whisper {
|
||||
return;
|
||||
}
|
||||
|
||||
this.connectToProvider();
|
||||
this.api = new API(embark, this.web3);
|
||||
this.api.registerAPICalls();
|
||||
|
||||
this.events.request('processes:register', 'whisper', (cb) => {
|
||||
this.waitForWeb3Ready(() => {
|
||||
this.web3.shh.getInfo((err) => {
|
||||
if (err) {
|
||||
const message = err.message || err;
|
||||
if (message.indexOf('not supported') > -1) {
|
||||
this.logger.error('Whisper is not supported on your node. Are you using the simulator?');
|
||||
return this.logger.trace(message);
|
||||
}
|
||||
}
|
||||
this.setServiceCheck();
|
||||
this.addSetProvider();
|
||||
this.registerAPICalls();
|
||||
cb();
|
||||
});
|
||||
});
|
||||
// ================
|
||||
// TODO:
|
||||
// figure out best way to detect is a node exists or launch a whisper process or wait for the blockchain process
|
||||
// ================
|
||||
// this.events.on("blockchain:ready", this.executeEmbarkJSBlockchain.bind(this));
|
||||
|
||||
this.setServiceCheck();
|
||||
|
||||
// TODO: see above, not ideal to do this, need engine.start process
|
||||
// can also register service and instead react to it and connect
|
||||
// this.waitForWeb3Ready(() => {
|
||||
// this.registerAndSetWhisper();
|
||||
// });
|
||||
this.events.on("blockchain:ready", () => {
|
||||
this.registerAndSetWhisper();
|
||||
});
|
||||
|
||||
// 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.connectToProvider();
|
||||
|
||||
this.events.request('processes:launch', 'whisper');
|
||||
// this.events.request('processes:register', 'whisper', (cb) => {
|
||||
// this.waitForWeb3Ready(() => {
|
||||
// this.web3.shh.getInfo((err) => {
|
||||
// if (err) {
|
||||
// const message = err.message || err;
|
||||
// if (message.indexOf('not supported') > -1) {
|
||||
// this.logger.error('Whisper is not supported on your node. Are you using the simulator?');
|
||||
// return this.logger.trace(message);
|
||||
// }
|
||||
// }
|
||||
// this.setServiceCheck();
|
||||
// this.addWhisperToEmbarkJS();
|
||||
// this.addSetProvider();
|
||||
// this.registerAPICalls();
|
||||
// cb();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
// this.events.request('processes:launch', 'whisper');
|
||||
}
|
||||
|
||||
connectToProvider() {
|
||||
@ -75,6 +84,57 @@ class Whisper {
|
||||
this.web3.setProvider(new Web3.providers.WebsocketProvider(web3Endpoint, {headers: {Origin: EMBARK_RESOURCE_ORIGIN}}));
|
||||
}
|
||||
|
||||
registerAndSetWhisper() {
|
||||
if (this.communicationConfig === {}) {
|
||||
return;
|
||||
}
|
||||
if ((this.communicationConfig.available_providers.indexOf('whisper') < 0) && (this.communicationConfig.provider !== 'whisper' || this.communicationConfig.enabled !== true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// let linkedModulePath = path.join(this.modulesPath, 'embarkjs-whisper');
|
||||
// if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
|
||||
|
||||
// const code = `
|
||||
// const __embarkWhisperNewWeb3 = EmbarkJS.isNode ? require('${linkedModulePath}') : require('embarkjs-whisper');
|
||||
// EmbarkJS.Messages.registerProvider('whisper', __embarkWhisperNewWeb3.default || __embarkWhisperNewWeb3);
|
||||
// `;
|
||||
|
||||
let code = `
|
||||
const __embarkWhisperNewWeb3 = require('embarkjs-whisper');
|
||||
EmbarkJS.Messages.registerProvider('whisper', __embarkWhisperNewWeb3.default || __embarkWhisperNewWeb3);
|
||||
`;
|
||||
|
||||
let connection = this.communicationConfig.connection || {};
|
||||
|
||||
if (!(this.communicationConfig.provider === 'whisper' && this.communicationConfig.enabled === true)) {
|
||||
return this.events.request('runcode:eval', code, () => {
|
||||
});
|
||||
}
|
||||
|
||||
// todo: make the add code a function as well
|
||||
const config = {
|
||||
server: canonicalHost(connection.host || defaultHost),
|
||||
port: connection.port || '8546',
|
||||
type: connection.type || 'ws'
|
||||
};
|
||||
code += `\nEmbarkJS.Messages.setProvider('whisper', ${JSON.stringify(config)});`;
|
||||
|
||||
// this.embark.addCodeToEmbarkJS(code);
|
||||
this.events.request('runcode:eval', code, (err) => {
|
||||
// if (err) {
|
||||
// return cb(err);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// ===============================
|
||||
// ===============================
|
||||
// ===============================
|
||||
// ===============================
|
||||
// ===============================
|
||||
|
||||
waitForWeb3Ready(cb) {
|
||||
if (this.web3Ready) {
|
||||
return cb();
|
||||
@ -119,37 +179,6 @@ class Whisper {
|
||||
});
|
||||
}
|
||||
|
||||
addWhisperToEmbarkJS() {
|
||||
// TODO: make this a shouldAdd condition
|
||||
if (this.communicationConfig === {}) {
|
||||
return;
|
||||
}
|
||||
if ((this.communicationConfig.available_providers.indexOf('whisper') < 0) && (this.communicationConfig.provider !== 'whisper' || this.communicationConfig.enabled !== true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let linkedModulePath = path.join(this.modulesPath, 'embarkjs-whisper');
|
||||
if (process.platform === 'win32') linkedModulePath = linkedModulePath.replace(/\\/g, '\\\\');
|
||||
|
||||
this.events.request('version:downloadIfNeeded', 'embarkjs-whisper', (err, location) => {
|
||||
if (err) {
|
||||
this.logger.error(__('Error downloading embarkjs-whisper'));
|
||||
throw err;
|
||||
}
|
||||
|
||||
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() {
|
||||
let connection = this.communicationConfig.connection || {};
|
||||
const shouldInit = (communicationConfig) => {
|
||||
@ -162,13 +191,8 @@ class Whisper {
|
||||
port: connection.port || '8546',
|
||||
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)});`;
|
||||
|
||||
this.embark.addProviderInit('communication', code, shouldInit);
|
||||
|
||||
const consoleConfig = Object.assign({}, config, {providerOptions: {headers: {Origin: EMBARK_RESOURCE_ORIGIN}}});
|
||||
@ -176,72 +200,6 @@ class Whisper {
|
||||
this.embark.addConsoleProviderInit('communication', consoleCode, shouldInit);
|
||||
}
|
||||
|
||||
registerAPICalls() {
|
||||
const self = this;
|
||||
if (self.apiCallsRegistered) {
|
||||
return;
|
||||
}
|
||||
self.apiCallsRegistered = true;
|
||||
let symKeyID, sig;
|
||||
parallel([
|
||||
function(paraCb) {
|
||||
self.web3.shh.newSymKey((err, id) => {
|
||||
symKeyID = id;
|
||||
paraCb(err);
|
||||
});
|
||||
},
|
||||
function(paraCb) {
|
||||
self.web3.shh.newKeyPair((err, id) => {
|
||||
sig = id;
|
||||
paraCb(err);
|
||||
});
|
||||
}
|
||||
], (err) => {
|
||||
if (err) {
|
||||
self.logger.error('Error getting Whisper keys:', err.message || err);
|
||||
return;
|
||||
}
|
||||
self.embark.registerAPICall(
|
||||
'post',
|
||||
'/embark-api/communication/sendMessage',
|
||||
(req, res) => {
|
||||
sendMessage({
|
||||
topic: req.body.topic,
|
||||
data: req.body.message,
|
||||
sig,
|
||||
symKeyID,
|
||||
fromAscii: self.web3.utils.asciiToHex,
|
||||
toHex: self.web3.utils.toHex,
|
||||
post: self.web3.shh.post
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
return res.status(500).send({error: err});
|
||||
}
|
||||
res.send(result);
|
||||
});
|
||||
});
|
||||
|
||||
self.embark.registerAPICall(
|
||||
'ws',
|
||||
'/embark-api/communication/listenTo/:topic',
|
||||
(ws, req) => {
|
||||
const obs = listenTo({
|
||||
toAscii: self.web3.utils.hexToAscii,
|
||||
toHex: self.web3.utils.toHex,
|
||||
topic: req.params.topic,
|
||||
sig,
|
||||
subscribe: self.web3.shh.subscribe,
|
||||
symKeyID
|
||||
}).pipe(takeUntil(fromEvent(ws, 'close').pipe(map(() => (
|
||||
delete self.webSocketsChannels[req.params.topic]
|
||||
)))));
|
||||
self.webSocketsChannels[req.params.topic] = obs;
|
||||
obs.subscribe(data => {
|
||||
ws.send(JSON.stringify(data));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Whisper;
|
||||
|
@ -10,8 +10,8 @@ module.exports = (api) => {
|
||||
const node = cloneDeep(base);
|
||||
Object.assign(node, {
|
||||
ignore: [
|
||||
'src/lib/modules/pipeline/babel-loader-overrides.js',
|
||||
'src/lib/modules/pipeline/webpack.config.js'
|
||||
'src/lib/modules/basic-pipeline/babel-loader-overrides.js',
|
||||
'src/lib/modules/basic-pipeline/webpack.config.js'
|
||||
]
|
||||
});
|
||||
|
@ -135,17 +135,27 @@ class Engine {
|
||||
|
||||
pipelineService(_options) {
|
||||
const self = this;
|
||||
this.registerModulePackage('embark-pipeline', {
|
||||
this.registerModulePackage('embark-pipeline', { plugins: this.plugins });
|
||||
this.registerModule('basic-pipeline', {
|
||||
plugins: this.plugins,
|
||||
webpackConfigName: this.webpackConfigName,
|
||||
useDashboard: this.useDashboard
|
||||
});
|
||||
this.events.on('code-generator-ready', function (modifiedAssets) {
|
||||
self.events.request('code', function (abi, contractsJSON) {
|
||||
self.events.request('pipeline:build', {abi, contractsJSON, modifiedAssets}, () => {
|
||||
self.events.emit('outputDone');
|
||||
});
|
||||
// this.events.on('code-generator-ready', function (modifiedAssets) {
|
||||
// self.events.request('code', function (abi, contractsJSON) {
|
||||
// self.events.request('pipeline:build', {abi, contractsJSON, modifiedAssets}, () => {
|
||||
// self.events.emit('outputDone');
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
// TODO: move this to cmd_controller and define all such behaviour there
|
||||
this.events.on('contracts:deploy:afterAll', () => {
|
||||
self.events.request('pipeline:generateAll', () => {
|
||||
console.dir("outputDone")
|
||||
self.events.emit('outputDone');
|
||||
});
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
serviceMonitor() {
|
||||
@ -180,32 +190,30 @@ class Engine {
|
||||
}
|
||||
|
||||
codeGeneratorService(_options) {
|
||||
let self = this;
|
||||
|
||||
this.registerModulePackage('embark-code-generator', {plugins: self.plugins, env: self.env});
|
||||
|
||||
const generateCode = function (modifiedAssets, cb) {
|
||||
self.events.request("code-generator:embarkjs:build", () => {
|
||||
self.events.emit('code-generator-ready', modifiedAssets);
|
||||
cb();
|
||||
});
|
||||
};
|
||||
const cargo = async.cargo((tasks, callback) => {
|
||||
const modifiedAssets = tasks.map(task => task.modifiedAsset).filter(asset => asset); // filter null elements
|
||||
generateCode(modifiedAssets, () => {
|
||||
if (this.context.includes('test')) {
|
||||
return callback();
|
||||
}
|
||||
self.events.once('outputDone', callback);
|
||||
});
|
||||
});
|
||||
const addToCargo = function (modifiedAsset) {
|
||||
cargo.push({modifiedAsset});
|
||||
};
|
||||
|
||||
this.events.on('contractsDeployed', addToCargo);
|
||||
this.events.on('blockchainDisabled', addToCargo);
|
||||
this.events.on('asset-changed', addToCargo);
|
||||
return;
|
||||
// let self = this;
|
||||
//
|
||||
// this.registerModulePackage('embark-code-generator', {plugins: self.plugins, env: self.env});
|
||||
//
|
||||
// const generateCode = function (modifiedAssets) {
|
||||
// // self.events.request("module:storage:onReady", () => {
|
||||
// self.events.request("code-generator:embarkjs:build", () => {
|
||||
// self.events.emit('code-generator-ready', modifiedAssets);
|
||||
// });
|
||||
// // });
|
||||
// };
|
||||
// const cargo = async.cargo((tasks, callback) => {
|
||||
// const modifiedAssets = tasks.map(task => task.modifiedAsset).filter(asset => asset); // filter null elements
|
||||
// generateCode(modifiedAssets);
|
||||
// self.events.once('outputDone', callback);
|
||||
// });
|
||||
// const addToCargo = function (modifiedAsset) {
|
||||
// cargo.push({modifiedAsset});
|
||||
// };
|
||||
//
|
||||
// this.events.on('contractsDeployed', addToCargo);
|
||||
// this.events.on('blockchainDisabled', addToCargo);
|
||||
// this.events.on('asset-changed', addToCargo);
|
||||
}
|
||||
|
||||
setupCompilerAndContractsManagerService(options) {
|
||||
@ -269,23 +277,23 @@ class Engine {
|
||||
}
|
||||
|
||||
storageService(_options) {
|
||||
this.registerModulePackage('embark-ipfs');
|
||||
this.registerModulePackage('embark-swarm');
|
||||
this.registerModulePackage('embark-storage', {plugins: this.plugins});
|
||||
// this.registerModulePackage('embark-ipfs');
|
||||
// this.registerModulePackage('embark-swarm');
|
||||
// this.registerModulePackage('embark-storage', {plugins: this.plugins});
|
||||
|
||||
this.events.setCommandHandler("module:storage:reset", (cb) => {
|
||||
async.parallel([
|
||||
(paraCb) => {
|
||||
this.events.request("module:ipfs:reset", paraCb);
|
||||
},
|
||||
(paraCb) => {
|
||||
this.events.request("module:swarm:reset", paraCb);
|
||||
},
|
||||
(paraCb) => {
|
||||
this.events.request("module:storageJS:reset", paraCb);
|
||||
}
|
||||
], cb);
|
||||
});
|
||||
// this.events.setCommandHandler("module:storage:reset", (cb) => {
|
||||
// async.parallel([
|
||||
// (paraCb) => {
|
||||
// this.events.request("module:ipfs:reset", paraCb);
|
||||
// },
|
||||
// (paraCb) => {
|
||||
// this.events.request("module:swarm:reset", paraCb);
|
||||
// },
|
||||
// (paraCb) => {
|
||||
// this.events.request("module:storageJS:reset", paraCb);
|
||||
// }
|
||||
// ], cb);
|
||||
// });
|
||||
}
|
||||
|
||||
web3Service(options) {
|
||||
@ -307,6 +315,7 @@ class Engine {
|
||||
});
|
||||
|
||||
this.registerModulePackage('embark-whisper');
|
||||
this.registerModule('web3', { plugins: this.plugins });
|
||||
}
|
||||
|
||||
libraryManagerService(_options) {
|
||||
|
@ -55,8 +55,13 @@ EventEmitter.prototype.request = function() {
|
||||
|
||||
log("requesting: ", requestName);
|
||||
warnIfLegacy(requestName);
|
||||
if (this._events && !this._events['request:' + requestName]) {
|
||||
console.log("made request without listener: " + requestName)
|
||||
}
|
||||
const listenerName = 'request:' + requestName;
|
||||
|
||||
// TODO: remove this, it will lead to illusion of things working when this situatio shouldnt' hapepn in the first place
|
||||
|
||||
// if we don't have a command handler set for this event yet,
|
||||
// store it and fire it once a command handler is set
|
||||
if (!this.listeners(listenerName).length) {
|
||||
|
@ -161,6 +161,7 @@ Plugins.prototype.getPluginsProperty = function(pluginType, property, sub_proper
|
||||
return matchingProperties.reduce((a,b) => { return a.concat(b); }) || [];
|
||||
};
|
||||
|
||||
// TODO: because this is potentially hanging, we should issue a trace warning if the event does not exists
|
||||
Plugins.prototype.runActionsForEvent = function(eventName, args, cb) {
|
||||
if (typeof (args) === 'function') {
|
||||
cb = args;
|
||||
|
257
packages/embark/src/lib/modules/basic-pipeline/index.js
Normal file
257
packages/embark/src/lib/modules/basic-pipeline/index.js
Normal file
@ -0,0 +1,257 @@
|
||||
const async = require('async');
|
||||
import { __ } from 'embark-i18n';
|
||||
import { ProcessLauncher } from 'embark-core';
|
||||
import { dappPath, joinPath, LongRunningProcessTimer } from 'embark-utils';
|
||||
const constants = require('embark-core/constants');
|
||||
const WebpackConfigReader = require('./webpackConfigReader');
|
||||
|
||||
class BasicPipeline {
|
||||
|
||||
constructor(embark, options) {
|
||||
this.embark = embark;
|
||||
this.assetFiles = embark.config.assetFiles;
|
||||
this.isFirstBuild = true;
|
||||
this.embarkConfig = embark.config.embarkConfig;
|
||||
// TODO: why god why
|
||||
this.useDashboard = options.useDashboard;
|
||||
this.fs = embark.fs;
|
||||
this.webpackConfigName = options.webpackConfigName;
|
||||
this.env = embark.config.env;
|
||||
this.buildDir = embark.config.buildDir;
|
||||
this.contractsFiles = embark.config.contractsFiles;
|
||||
this.embarkConfig = embark.config.embarkConfig;
|
||||
|
||||
this.logger = embark.logger;
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
this.pipelinePlugins = this.plugins.getPluginsFor('pipeline');
|
||||
this.pipelineConfig = embark.config.pipelineConfig;
|
||||
let plugin = this.plugins.createPlugin('basic-pipeline', {});
|
||||
|
||||
plugin.registerActionForEvent("pipeline:generateAll:after", this.webpackAssets.bind(this));
|
||||
|
||||
// track changes to the pipeline config in the filesystem
|
||||
this.events.on('config:load:pipeline', (pipelineConfig) => {
|
||||
this.pipelineConfig = pipelineConfig;
|
||||
});
|
||||
}
|
||||
|
||||
webpackAssets(params, done) {
|
||||
console.dir("=======================> webpackAssets");
|
||||
let self = this;
|
||||
let placeholderPage;
|
||||
const importsList = {};
|
||||
|
||||
if (!self.assetFiles || !Object.keys(self.assetFiles).length) {
|
||||
return done(); // no assetFiles so nothing to do
|
||||
}
|
||||
|
||||
let modifiedAssets = self.assetFiles;
|
||||
|
||||
async.waterfall([
|
||||
(next) => {
|
||||
console.dir("=======================> importsList");
|
||||
importsList["Embark/EmbarkJS"] = dappPath(self.embarkConfig.generationDir, 'embarkjs.js');
|
||||
importsList["Embark/contracts"] = this.embarkConfig.generationDir;
|
||||
next();
|
||||
},
|
||||
function shouldRunWebpack(next) {
|
||||
console.dir("=======================> shouldRunWebpack");
|
||||
// assuming we got here because an asset was changed, let's check our webpack config
|
||||
// to see if the changed asset requires webpack to run
|
||||
if (!(modifiedAssets && modifiedAssets.length)) return next(null, false);
|
||||
const configReader = new WebpackConfigReader({webpackConfigName: self.webpackConfigName});
|
||||
return configReader.readConfig((err, config) => {
|
||||
if (err) return next(err);
|
||||
|
||||
if (typeof config !== 'object' || config === null) {
|
||||
return next(__('Pipeline: bad webpack config, the resolved config was null or not an object'));
|
||||
}
|
||||
|
||||
const shouldRun = modifiedAssets.some(modifiedAsset => config.module.rules.some(rule => rule.test.test(modifiedAsset)));
|
||||
return next(null, !shouldRun);
|
||||
});
|
||||
},
|
||||
function runWebpack(shouldNotRun, next) {
|
||||
console.dir("=======================> runWebpack");
|
||||
if (shouldNotRun) return next();
|
||||
const assets = Object.keys(self.assetFiles).filter(key => key.match(/\.js$/));
|
||||
if (!assets || !assets.length) {
|
||||
return next();
|
||||
}
|
||||
let strAssets = '';
|
||||
if (!self.useDashboard) {
|
||||
assets.forEach(key => {
|
||||
strAssets += ('\n ' + (joinPath(self.buildDir, key)).bold.dim);
|
||||
});
|
||||
}
|
||||
const timer = new LongRunningProcessTimer(
|
||||
self.logger,
|
||||
'webpack',
|
||||
'0',
|
||||
`${'Pipeline:'.cyan} Bundling dapp using '${self.webpackConfigName}' config...${strAssets}`,
|
||||
`${'Pipeline:'.cyan} Still bundling dapp using '${self.webpackConfigName}' config... ({{duration}})${strAssets}`,
|
||||
`${'Pipeline:'.cyan} Finished bundling dapp in {{duration}}${strAssets}`,
|
||||
{
|
||||
showSpinner: !self.useDashboard,
|
||||
interval: self.useDashboard ? 5000 : 1000,
|
||||
longRunningThreshold: 15000
|
||||
}
|
||||
);
|
||||
timer.start();
|
||||
let built = false;
|
||||
const webpackProcess = new ProcessLauncher({
|
||||
embark: self.embark,
|
||||
plugins: self.plugins,
|
||||
modulePath: joinPath(__dirname, 'webpackProcess.js'),
|
||||
logger: self.logger,
|
||||
events: self.events,
|
||||
exitCallback: code => {
|
||||
if (!built) {
|
||||
return next(`Webpack build exited with code ${code} before the process finished`);
|
||||
}
|
||||
if (code) {
|
||||
self.logger.error(__('Webpack build process exited with code ', code));
|
||||
}
|
||||
}
|
||||
});
|
||||
webpackProcess.send({
|
||||
action: constants.pipeline.init,
|
||||
options: {
|
||||
webpackConfigName: self.webpackConfigName,
|
||||
pipelineConfig: self.pipelineConfig,
|
||||
fs: self.embark.fs
|
||||
}
|
||||
});
|
||||
webpackProcess.send({action: constants.pipeline.build, assets: self.assetFiles, importsList});
|
||||
|
||||
webpackProcess.once('result', constants.pipeline.built, (msg) => {
|
||||
built = true;
|
||||
webpackProcess.kill();
|
||||
return next(msg.error);
|
||||
});
|
||||
webpackProcess.once('result', constants.pipeline.webpackDone, () => {
|
||||
timer.end();
|
||||
});
|
||||
},
|
||||
function assetFileWrite(next) {
|
||||
console.dir("=======================> assetFileWrite 136");
|
||||
async.eachOf(
|
||||
// assetFileWrite should not process .js files
|
||||
Object.keys(self.assetFiles)
|
||||
.filter(key => !key.match(/\.js$/))
|
||||
.reduce((obj, key) => {
|
||||
obj[key] = self.assetFiles[key];
|
||||
return obj;
|
||||
}, {}),
|
||||
function (files, targetFile, cb) {
|
||||
console.dir("== eachOf: " + targetFile);
|
||||
const isDir = targetFile.slice(-1) === '/' || targetFile.slice(-1) === '\\' || targetFile.indexOf('.') === -1;
|
||||
// if it's not a directory
|
||||
if (!isDir) {
|
||||
self.logger.info('Pipeline: '.cyan + __("_1_ writing file") + " " + (joinPath(self.buildDir, targetFile)).bold.dim);
|
||||
}
|
||||
console.dir("async.map")
|
||||
// async.map(
|
||||
async.mapLimit(
|
||||
files,
|
||||
1,
|
||||
function (file, fileCb) {
|
||||
self.logger.trace("reading " + file.path);
|
||||
console.dir(":::::::: reading " + file.path);
|
||||
file.content.then((fileContent) => {
|
||||
self.runPlugins(file, fileContent, fileCb);
|
||||
}).catch(fileCb);
|
||||
},
|
||||
function (err, contentFiles) {
|
||||
try {
|
||||
if (err) {
|
||||
self.logger.error('Pipeline: '.cyan + __('errors found while generating') + ' ' + targetFile);
|
||||
console.dir(err);
|
||||
}
|
||||
let dir = targetFile.split('/').slice(0, -1).join('/');
|
||||
self.logger.trace(`${'Pipeline:'.cyan} creating dir ` + joinPath(self.buildDir, dir));
|
||||
self.fs.mkdirpSync(joinPath(self.buildDir, dir));
|
||||
|
||||
// if it's a directory
|
||||
if (isDir) {
|
||||
console.dir("---> isDir")
|
||||
let targetDir = targetFile;
|
||||
|
||||
if (targetDir.slice(-1) !== '/') {
|
||||
targetDir = targetDir + '/';
|
||||
}
|
||||
|
||||
console.dir("===> contentFiles")
|
||||
console.dir(contentFiles)
|
||||
console.dir("----------")
|
||||
async.each(contentFiles, function (file, eachCb) {
|
||||
let filename = file.path.replace(file.basedir + '/', '');
|
||||
self.logger.info(`${'Pipeline:'.cyan} __ writing file ` + (joinPath(self.buildDir, targetDir, filename)).bold.dim);
|
||||
|
||||
self.fs.copy(file.path, joinPath(self.buildDir, targetDir, filename), {overwrite: true}, eachCb);
|
||||
}, cb);
|
||||
return;
|
||||
}
|
||||
|
||||
console.dir("---> not a dir")
|
||||
let content = contentFiles.map(file => {
|
||||
if (file === undefined) {
|
||||
return "";
|
||||
}
|
||||
return file.content;
|
||||
}).join("\n");
|
||||
|
||||
if (new RegExp(/^index.html?/i).test(targetFile)) {
|
||||
targetFile = targetFile.replace('index', 'index-temp');
|
||||
placeholderPage = targetFile;
|
||||
}
|
||||
console.dir("--> writing file")
|
||||
self.fs.writeFile(joinPath(self.buildDir, targetFile), content, cb);
|
||||
} catch(err) {
|
||||
console.dir(err)
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
next
|
||||
);
|
||||
},
|
||||
function removePlaceholderPage(next) {
|
||||
console.dir("=======================> removePlaceholderPage");
|
||||
let placeholderFile = joinPath(self.buildDir, placeholderPage);
|
||||
self.fs.access(joinPath(self.buildDir, placeholderPage), (err) => {
|
||||
if (err) return next(); // index-temp doesn't exist, do nothing
|
||||
|
||||
// rename index-temp.htm/l to index.htm/l, effectively replacing our placeholder page
|
||||
// with the contents of the built index.html page
|
||||
self.fs.move(placeholderFile, placeholderFile.replace('index-temp', 'index'), {overwrite: true}, next);
|
||||
});
|
||||
}
|
||||
], done);
|
||||
}
|
||||
|
||||
runPlugins(file, fileContent, fileCb) {
|
||||
const self = this;
|
||||
if (self.pipelinePlugins.length <= 0) {
|
||||
return fileCb(null, {content: fileContent, path: file.path, basedir: file.basedir, modified: true});
|
||||
}
|
||||
async.eachSeries(self.pipelinePlugins, (plugin, pluginCB) => {
|
||||
if (file.options && file.options.skipPipeline) {
|
||||
return pluginCB();
|
||||
}
|
||||
|
||||
fileContent = plugin.runPipeline({targetFile: file.path, source: fileContent});
|
||||
file.modified = true;
|
||||
pluginCB();
|
||||
}, err => {
|
||||
if (err) {
|
||||
self.logger.error(err.message);
|
||||
}
|
||||
return fileCb(null, {content: fileContent, path: file.path, basedir: file.basedir, modified: true});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BasicPipeline;
|
181
packages/embark/src/lib/modules/web3/index.js
Normal file
181
packages/embark/src/lib/modules/web3/index.js
Normal file
@ -0,0 +1,181 @@
|
||||
require('ejs');
|
||||
import { embarkPath } from "embark-utils";
|
||||
import { transform } from "@babel/core";
|
||||
|
||||
const Templates = {
|
||||
vanilla_contract: require('./vanilla-contract.js.ejs')
|
||||
};
|
||||
|
||||
// TODO: this should be moved to the embark-web3 module from master
|
||||
class Web3Plugin {
|
||||
|
||||
constructor(embark, options) {
|
||||
this.embarkConfig = embark.config.embarkConfig;
|
||||
this.logger = embark.logger;
|
||||
this.events = embark.events;
|
||||
this.plugins = options.plugins;
|
||||
let plugin = this.plugins.createPlugin('web3plugin', {});
|
||||
|
||||
plugin.registerActionForEvent("deploy:contract:deployed", this.registerInVm.bind(this));
|
||||
plugin.registerActionForEvent("deploy:contract:deployed", this.addContractJSONToPipeline.bind(this));
|
||||
plugin.registerActionForEvent("deploy:contract:deployed", this.addContractFileToPipeline.bind(this));
|
||||
plugin.registerActionForEvent("pipeline:generateAll:before", this.addEmbarkJSNode.bind(this));
|
||||
plugin.registerActionForEvent("pipeline:generateAll:before", this.addContractIndexToPipeline.bind(this));
|
||||
}
|
||||
|
||||
registerInVm(params, cb) {
|
||||
let contract = params.contract;
|
||||
let abi = JSON.stringify(contract.abiDefinition);
|
||||
let gasLimit = 6000000;
|
||||
let contractCode = Templates.vanilla_contract({ className: contract.className, abi: abi, contract: contract, gasLimit: gasLimit });
|
||||
|
||||
this.events.request('runcode:eval', contractCode, (err) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
this.events.request('runcode:eval', contract.className, (err, result) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
this.events.emit("runcode:register", contract.className, result, () => { cb() });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addContractJSONToPipeline(params, cb) {
|
||||
// TODO: check if this is correct json object to generate
|
||||
const contract = params.contract;
|
||||
|
||||
this.events.request("pipeline:register", {
|
||||
path: [this.embarkConfig.buildDir, 'contracts'],
|
||||
file: contract.className + '.json',
|
||||
format: 'json',
|
||||
content: contract
|
||||
}, cb);
|
||||
}
|
||||
|
||||
addContractFileToPipeline(params, cb) {
|
||||
const contract = params.contract;
|
||||
const contractName = contract.className;
|
||||
console.dir("--------------");
|
||||
console.dir("--------------");
|
||||
console.dir(contract.className);
|
||||
const contractJSON = contract.abiDefinition;
|
||||
|
||||
const contractCode = `
|
||||
"use strict";
|
||||
|
||||
const isNode = (typeof process !== 'undefined' && process.versions && process.versions.node);
|
||||
const lib = isNode ? '../embarkjs.node' : '../embarkjs';
|
||||
|
||||
const EmbarkJSNode = isNode && require('../embarkjs.node');
|
||||
let EmbarkJSBrowser;
|
||||
try {
|
||||
EmbarkJSBrowser = require('../embarkjs').default;
|
||||
} catch(e) {};
|
||||
|
||||
const EmbarkJS = isNode ? EmbarkJSNode : EmbarkJSBrowser;
|
||||
|
||||
let ${contractName}JSONConfig = ${JSON.stringify(contractJSON)};
|
||||
let ${contractName} = new EmbarkJS.Blockchain.Contract(${contractName}JSONConfig);
|
||||
module.exports = ${contractName};
|
||||
`.trim().replace(/^[\t\s]+/gm, '');
|
||||
|
||||
this.events.request("pipeline:register", {
|
||||
path: [this.embarkConfig.generationDir, 'contracts'],
|
||||
file: contract.className + '.js',
|
||||
format: 'js',
|
||||
content: contractCode
|
||||
}, cb);
|
||||
}
|
||||
|
||||
addContractIndexToPipeline(_params, cb) {
|
||||
this.events.request("contracts:list", (err, contracts) => {
|
||||
contracts.forEach(console.dir)
|
||||
let imports = contracts.filter(c => c.deployedAddress || c.deploy).map((c) => {
|
||||
return `"${c.className}": require('./${c.className}').default`;
|
||||
}).join(",\n");
|
||||
|
||||
let code = 'module.exports = {\n';
|
||||
code += imports;
|
||||
code += '\n};';
|
||||
|
||||
this.events.request("pipeline:register", {
|
||||
path: [this.embarkConfig.generationDir, 'contracts'],
|
||||
file: 'index.js',
|
||||
format: 'js',
|
||||
content: code
|
||||
}, cb);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: ideally shouldn't be done here
|
||||
addEmbarkJSNode(_params, cb) {
|
||||
let embarkjsCode = '';
|
||||
|
||||
// TODO: the symblink is unclear at this point, but if needed, it should be done at the pipeline through a request
|
||||
// TODO: embarkjs stuff should also be in a embark-embarkjs module
|
||||
// self.generateSymlink(location, 'embarkjs', (err, symlinkDest) => {
|
||||
// if (err) {
|
||||
// self.logger.error(__('Error creating a symlink to EmbarkJS'));
|
||||
// return next(err);
|
||||
// }
|
||||
// embarkjsCode += `\nconst EmbarkJS = require("${symlinkDest}").default || require("${symlinkDest}");`;
|
||||
embarkjsCode += `\nconst EmbarkJS = require("embarkjs").default;`;
|
||||
// embarkjsCode += `\nEmbarkJS.environment = '${self.env}';`;
|
||||
embarkjsCode += "\nglobal.EmbarkJS = EmbarkJS;";
|
||||
// next();
|
||||
// });
|
||||
|
||||
let code = "";
|
||||
code += "\n" + embarkjsCode + "\n";
|
||||
|
||||
code += "\nexport default EmbarkJS;";
|
||||
code += "\nif (typeof module !== 'undefined' && module.exports) {" +
|
||||
"\n\tmodule.exports = EmbarkJS;" +
|
||||
"\n}";
|
||||
code += '\n/* eslint-enable */\n';
|
||||
|
||||
// TODO: should be done in async.waterfall
|
||||
this.events.request("pipeline:register", {
|
||||
path: [this.embarkConfig.generationDir],
|
||||
file: 'embarkjs.js',
|
||||
format: 'js',
|
||||
content: code
|
||||
});
|
||||
|
||||
// embark.js
|
||||
// self.generateArtifact(code, constants.dappArtifacts.embarkjs, '', next);
|
||||
|
||||
transform(code, {
|
||||
cwd: embarkPath(),
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env", {
|
||||
"targets": {
|
||||
"node": "8.11.3"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}, (err, result) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
this.events.request("pipeline:register", {
|
||||
path: [this.embarkConfig.generationDir],
|
||||
file: 'embarkjs.node.js',
|
||||
format: 'js',
|
||||
content: code
|
||||
}, cb);
|
||||
|
||||
// self.generateArtifact(result.code, constants.dappArtifacts.embarkjsnode, '', next);
|
||||
});
|
||||
|
||||
// embark.node.js
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Web3Plugin;
|
@ -0,0 +1,9 @@
|
||||
<%- className %>Abi = <%- abi %>;
|
||||
<%- className %> = new web3.eth.Contract(<%- className %>Abi);
|
||||
<%- className %>.options.address = '<%- contract.deployedAddress %>';
|
||||
<%- className %>.address = '<%- contract.deployedAddress %>';
|
||||
<%- className %>.options.from = web3.eth.defaultAccount;
|
||||
<% if (gasLimit != false) { %>
|
||||
<%- className %>.options.gas = <%- gasLimit %>;
|
||||
<%- className %>.options.gasLimit = <%- gasLimit %>;
|
||||
<% } %>
|
40
packages/embarkjs-connector-web3/package.json
Normal file
40
packages/embarkjs-connector-web3/package.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "embarkjs-connector-web3",
|
||||
"version": "4.1.0-beta.2",
|
||||
"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.2",
|
||||
"embark-i18n": "^4.1.0-beta.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"rimraf": "2.6.3"
|
||||
}
|
||||
}
|
@ -51,24 +51,6 @@ Blockchain.connect = function(options, callback) {
|
||||
return connect(options);
|
||||
};
|
||||
|
||||
Blockchain.connectConsole = function(doneCb) {
|
||||
this.doFirst((cb) => {
|
||||
this.blockchainConnector.getAccounts(async (err, accounts) => {
|
||||
if (accounts) {
|
||||
this.blockchainConnector.setDefaultAccount(accounts[0]);
|
||||
}
|
||||
let _err = err;
|
||||
try {
|
||||
await cb(_err);
|
||||
} catch (e) {
|
||||
_err = e;
|
||||
} finally {
|
||||
doneCb(_err);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Blockchain.doFirst = function(todo) {
|
||||
todo((err) => {
|
||||
this.done = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user