refactor(@embark/whisper): Remove unneeded whisper layer

1. get rid of the whisper layer and handle everything in the communication layer
2. Create a gethWhisper and a parityWhisper plugin that has the same files as packages/embark/src/lib/modules/geth, except with a whisperClient instead of gethClient, and will include most of https://github.com/embark-framework/embark/blob/master/packages/plugins/whisper/src/index.js.
3. Get rid of any whisper registration in geth.
4. In the whisperGeth and whisperParity plugins, modify the request for communication:node:register, to end up calling `startWhisperNode`
This commit is contained in:
emizzle 2019-10-01 18:41:39 +10:00 committed by Pascal Precht
parent eb77e8e4e0
commit 4a10476e85
23 changed files with 1115 additions and 235 deletions

View File

@ -303,7 +303,8 @@ export class Engine {
}
communicationComponents() {
this.registerModulePackage('embark-whisper');
this.registerModulePackage('embark-whisper-geth');
this.registerModulePackage('embark-whisper-parity');
}
namesystemComponents() {

View File

@ -118,7 +118,8 @@
"embark-watcher": "^5.0.0-alpha.1",
"embark-web3": "^5.0.0-alpha.1",
"embark-webserver": "^5.0.0-alpha.1",
"embark-whisper": "^5.0.0-alpha.1",
"embark-whisper-geth": "^5.0.0-alpha.1",
"embark-whisper-parity": "^5.0.0-alpha.1",
"embarkjs-ens": "^5.0.0-alpha.1",
"embarkjs-ipfs": "^5.0.0-alpha.1",
"embarkjs-swarm": "^5.0.0-alpha.1",

View File

@ -1,28 +1,27 @@
import { __ } from 'embark-i18n';
const fs = require('fs-extra');
const async = require('async');
const {spawn, exec} = require('child_process');
const { spawn, exec } = require('child_process');
const path = require('path');
const constants = require('embark-core/constants');
const GethClient = require('./gethClient.js');
const WhisperGethClient = require('./whisperClient.js');
// const ParityClient = require('./parityClient.js');
import { IPC } from 'embark-core';
import { compact, dappPath, defaultHost, dockerHostSwap, embarkPath} from 'embark-utils';
import { compact, dappPath, defaultHost, dockerHostSwap, embarkPath } from 'embark-utils';
import { Logger } from 'embark-logger';
// time between IPC connection attempts (in ms)
const IPC_CONNECT_INTERVAL = 2000;
/*eslint complexity: ["error", 50]*/
var Blockchain = function(userConfig, clientClass, communicationConfig) {
var Blockchain = function (userConfig, clientClass, communicationConfig) {
this.userConfig = userConfig;
this.env = userConfig.env || 'development';
this.isDev = userConfig.isDev;
this.onReadyCallback = userConfig.onReadyCallback || (() => {});
this.onReadyCallback = userConfig.onReadyCallback || (() => { });
this.onExitCallback = userConfig.onExitCallback;
this.logger = userConfig.logger || new Logger({logLevel: 'debug', context: constants.contexts.blockchain}); // do not pass in events as we don't want any log events emitted
this.logger = userConfig.logger || new Logger({ logLevel: 'debug', context: constants.contexts.blockchain }); // do not pass in events as we don't want any log events emitted
this.events = userConfig.events;
this.isStandalone = userConfig.isStandalone;
this.certOptions = userConfig.certOptions;
@ -103,7 +102,7 @@ var Blockchain = function(userConfig, clientClass, communicationConfig) {
this.logger.error(__(spaceMessage, 'genesisBlock'));
process.exit(1);
}
this.client = new clientClass({config: this.config, env: this.env, isDev: this.isDev, communicationConfig: communicationConfig});
this.client = new clientClass({ config: this.config, env: this.env, isDev: this.isDev, communicationConfig: communicationConfig });
if (this.isStandalone) {
this.initStandaloneProcess();
@ -118,20 +117,20 @@ var Blockchain = function(userConfig, clientClass, communicationConfig) {
*
* @returns {void}
*/
Blockchain.prototype.initStandaloneProcess = function() {
Blockchain.prototype.initStandaloneProcess = function () {
let logQueue = [];
// on every log logged in logger (say that 3x fast), send the log
// to the IPC serve listening (only if we're connected of course)
this.logger.events.on('log', (logLevel, message) => {
if (this.ipc.connected) {
this.ipc.request('blockchain:log', {logLevel, message});
this.ipc.request('blockchain:log', { logLevel, message });
} else {
logQueue.push({logLevel, message});
logQueue.push({ logLevel, message });
}
});
this.ipc = new IPC({ipcRole: 'client'});
this.ipc = new IPC({ ipcRole: 'client' });
// Wait for an IPC server to start (ie `embark run`) by polling `.connect()`.
// Do not kill this interval as the IPC server may restart (ie restart
@ -177,7 +176,7 @@ Blockchain.prototype.run = function () {
function checkInstallation(next) {
self.isClientInstalled((err) => {
if (err) {
return next({message: err});
return next({ message: err });
}
next();
});
@ -198,7 +197,7 @@ Blockchain.prototype.run = function () {
next(null, cmd, args);
}, true);
}
], function(err, cmd, args) {
], function (err, cmd, args) {
if (err) {
self.logger.error(err.message || err);
process.exit(1);
@ -207,7 +206,7 @@ Blockchain.prototype.run = function () {
let full_cmd = cmd + " " + args.join(' ');
self.logger.info(__(">>>>>>>>>>>>>>>> running: %s", full_cmd.underline).green);
self.child = spawn(cmd, args, {cwd: process.cwd()});
self.child = spawn(cmd, args, { cwd: process.cwd() });
self.child.on('error', (err) => {
err = err.toString();
@ -291,15 +290,15 @@ Blockchain.prototype.isClientInstalled = function (callback) {
const parsedVersion = this.client.parseVersion(stdout);
const supported = this.client.isSupportedVersion(parsedVersion);
if (supported === undefined) {
this.logger.error((__('WARNING! Ethereum client version could not be determined or compared with version range') + ' ' + this.client.versSupported + __(', for best results please use a supported version')).yellow);
this.logger.warn((__('WARNING! Ethereum client version could not be determined or compared with version range') + ' ' + this.client.versSupported + __(', for best results please use a supported version')));
} else if (!supported) {
this.logger.error((__('WARNING! Ethereum client version unsupported, for best results please use a version in range') + ' ' + this.client.versSupported).yellow);
this.logger.warn((__('WARNING! Ethereum client version unsupported, for best results please use a version in range') + ' ' + this.client.versSupported));
}
callback();
});
};
Blockchain.prototype.initDevChain = function(callback) {
Blockchain.prototype.initDevChain = function (callback) {
const self = this;
const ACCOUNTS_ALREADY_PRESENT = 'accounts_already_present';
// Init the dev chain
@ -337,10 +336,10 @@ Blockchain.prototype.initDevChain = function(callback) {
if (!newAccountCommand) return next();
var accountNumber = 0;
async.whilst(
function() {
function () {
return accountNumber < accountsToCreate;
},
function(callback) {
function (callback) {
accountNumber++;
self.runCommand(newAccountCommand, {}, (err, stdout, _stderr) => {
if (err) {
@ -350,7 +349,7 @@ Blockchain.prototype.initDevChain = function(callback) {
callback(null, accountNumber);
});
},
function(err) {
function (err) {
next(err);
}
);
@ -430,14 +429,6 @@ export function BlockchainClient(userConfig, options, communicationConfig) {
if (!userConfig.client) userConfig.client = constants.blockchain.clients.geth;
// if clientName is set, it overrides preferences
if (options.clientName) userConfig.client = options.clientName;
// Choose correct client instance based on clientName
let clientClass;
if (communicationConfig) {
clientClass = WhisperGethClient;
} else {
clientClass = GethClient;
}
userConfig.isDev = (userConfig.isDev || userConfig.default);
userConfig.env = options.env;
@ -446,5 +437,5 @@ export function BlockchainClient(userConfig, options, communicationConfig) {
userConfig.logger = options.logger;
userConfig.certOptions = options.certOptions;
userConfig.isStandalone = options.isStandalone;
return new Blockchain(userConfig, clientClass, communicationConfig);
return new Blockchain(userConfig, GethClient, communicationConfig);
}

View File

@ -50,24 +50,6 @@ class Geth {
cb();
}
});
this.events.request("whisper:node:register", constants.blockchain.clients.geth, readyCb => {
this.events.request('processes:register', 'communication', {
launchFn: cb => {
this.startWhisperNode(cb);
},
stopFn: cb => {
this.stopWhisperNode(cb);
}
});
this.events.request("processes:launch", "communication", (err) => {
if (err) {
this.logger.error(`Error launching whisper process: ${err.message || err}`);
}
readyCb();
});
});
}
shouldInit() {
@ -132,31 +114,6 @@ class Geth {
this.blockchainProcess.startBlockchainNode(callback);
}
startWhisperNode(callback) {
this.whisperProcess = new BlockchainProcessLauncher({
events: this.events,
logger: this.logger,
normalizeInput,
blockchainConfig: this.blockchainConfig,
communicationConfig: this.communicationConfig,
locale: this.locale,
client: this.client,
isDev: this.isDev,
embark: this.embark
});
this.whisperProcess.startBlockchainNode(callback);
}
stopWhisperNode(cb) {
if (!this.whisperProcess) {
return cb();
}
this.whisperProcess.stopBlockchainNode(() => {
this.logger.info(`The whisper process has been stopped.`);
cb();
});
}
stopBlockchainNode(cb) {
const message = __(`The blockchain process has been stopped. It can be restarted by running ${"service blockchain on".bold} in the Embark console.`);

View File

@ -303,9 +303,9 @@ Blockchain.prototype.isClientInstalled = function (callback) {
const parsedVersion = this.client.parseVersion(stdout);
const supported = this.client.isSupportedVersion(parsedVersion);
if (supported === undefined) {
this.logger.error((__('WARNING! Ethereum client version could not be determined or compared with version range') + ' ' + this.client.versSupported + __(', for best results please use a supported version')).yellow);
this.logger.warn((__('WARNING! Ethereum client version could not be determined or compared with version range') + ' ' + this.client.versSupported + __(', for best results please use a supported version')));
} else if (!supported) {
this.logger.error((__('WARNING! Ethereum client version unsupported, for best results please use a version in range') + ' ' + this.client.versSupported).yellow);
this.logger.warn((__('WARNING! Ethereum client version unsupported, for best results please use a version in range') + ' ' + this.client.versSupported));
}
callback();
});

View File

@ -7,6 +7,9 @@ const parseAndRespond = (data, cb) => {
let resp;
try {
resp = JSON.parse(data);
if (resp.error) {
return cb(resp.error);
}
} catch (e) {
return cb('Version data is not valid JSON');
}

View File

@ -1,6 +1,6 @@
# `embark-whisper`
# `embark-whisper-geth`
> Module to add Whisper support to Embark
> Module to add Whisper support to Embark for the Geth blockchain
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).

View File

@ -1,10 +1,10 @@
{
"name": "embark-whisper",
"name": "embark-whisper-geth",
"version": "5.0.0-alpha.1",
"author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [],
"description": "Module to add Whisper support to Embark",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/plugins/whisper#readme",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/plugins/whisper-geth#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"keywords": [
"blockchain",
@ -20,7 +20,7 @@
],
"license": "MIT",
"repository": {
"directory": "packages/plugins/whisper",
"directory": "packages/plugins/whisper-geth",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},

View File

@ -1,5 +1,5 @@
import EmbarkJS from 'embarkjs';
import EmbarkJSWhisper from 'embarkjs-whisper';
import EmbarkJS from "embarkjs";
import EmbarkJSWhisper from "embarkjs-whisper";
class API {
@ -11,8 +11,8 @@ class API {
async initEmbarkJSWhisper() {
if (Object.keys(EmbarkJS.Messages.Providers).includes("whisper")) return;
EmbarkJS.Messages.registerProvider('whisper', EmbarkJSWhisper);
EmbarkJS.Messages.setProvider('whisper', this.communicationConfig.connection);
EmbarkJS.Messages.registerProvider("whisper", EmbarkJSWhisper);
EmbarkJS.Messages.setProvider("whisper", this.communicationConfig.connection);
}
async registerAPICalls() {
@ -23,8 +23,8 @@ class API {
async registerSendMessageCall() {
this.embark.registerAPICall(
'post',
'/embark-api/communication/sendMessage',
"post",
"/embark-api/communication/sendMessage",
(req, res) => {
EmbarkJS.Messages.sendMessage({ topic: req.body.topic, data: req.body.message }, (err, result) => {
if (err) {
@ -37,8 +37,8 @@ class API {
async registerListenToCall() {
this.embark.registerAPICall(
'ws',
'/embark-api/communication/listenTo/:topic',
"ws",
"/embark-api/communication/listenTo/:topic",
(ws, req) => {
EmbarkJS.Messages.listenTo({ topic: req.params.topic }).subscribe(data => {
ws.send(JSON.stringify(data));

View File

@ -0,0 +1,301 @@
import { __ } from "embark-i18n";
const async = require("async");
// eslint-disable-next-line security/detect-child-process
const {spawn, exec} = require("child_process");
const path = require("path");
const constants = require("embark-core/constants");
const WhisperGethClient = require("./whisperGethClient.js");
import { IPC } from "embark-core";
import { compact, dappPath, defaultHost, dockerHostSwap, embarkPath} from "embark-utils";
const Logger = require("embark-logger");
// time between IPC connection attempts (in ms)
const IPC_CONNECT_INTERVAL = 2000;
/*eslint complexity: ["error", 50]*/
var Blockchain = function(userConfig, clientClass, communicationConfig) {
this.userConfig = userConfig;
this.env = userConfig.env || "development";
this.isDev = userConfig.isDev;
this.onReadyCallback = userConfig.onReadyCallback || (() => {});
this.onExitCallback = userConfig.onExitCallback;
this.logger = userConfig.logger || new Logger({logLevel: "debug", context: constants.contexts.blockchain}); // do not pass in events as we don't want any log events emitted
this.events = userConfig.events;
this.isStandalone = userConfig.isStandalone;
this.certOptions = userConfig.certOptions;
let defaultWsApi = clientClass.DEFAULTS.WS_API;
if (this.isDev) defaultWsApi = clientClass.DEFAULTS.DEV_WS_API;
this.config = {
silent: this.userConfig.silent,
client: this.userConfig.client,
ethereumClientBin: this.userConfig.ethereumClientBin || this.userConfig.client,
networkType: this.userConfig.networkType || clientClass.DEFAULTS.NETWORK_TYPE,
networkId: this.userConfig.networkId || clientClass.DEFAULTS.NETWORK_ID,
genesisBlock: this.userConfig.genesisBlock || false,
datadir: this.userConfig.datadir,
mineWhenNeeded: this.userConfig.mineWhenNeeded || false,
rpcHost: dockerHostSwap(this.userConfig.rpcHost) || defaultHost,
rpcPort: this.userConfig.rpcPort || 8545,
rpcCorsDomain: this.userConfig.rpcCorsDomain || false,
rpcApi: this.userConfig.rpcApi || clientClass.DEFAULTS.RPC_API,
port: this.userConfig.port || 30303,
nodiscover: this.userConfig.nodiscover || false,
mine: this.userConfig.mine || false,
account: {},
whisper: (this.userConfig.whisper !== false),
maxpeers: ((this.userConfig.maxpeers === 0) ? 0 : (this.userConfig.maxpeers || 25)),
bootnodes: this.userConfig.bootnodes || "",
wsRPC: (this.userConfig.wsRPC !== false),
wsHost: dockerHostSwap(this.userConfig.wsHost) || defaultHost,
wsPort: this.userConfig.wsPort || 8546,
wsOrigins: this.userConfig.wsOrigins || false,
wsApi: this.userConfig.wsApi || defaultWsApi,
vmdebug: this.userConfig.vmdebug || false,
targetGasLimit: this.userConfig.targetGasLimit || false,
syncMode: this.userConfig.syncMode || this.userConfig.syncmode,
verbosity: this.userConfig.verbosity
};
this.devFunds = null;
if (this.userConfig.accounts) {
const nodeAccounts = this.userConfig.accounts.find((account) => account.nodeAccounts);
if (nodeAccounts) {
this.config.account = {
numAccounts: nodeAccounts.numAddresses || 1,
password: nodeAccounts.password,
balance: nodeAccounts.balance
};
}
}
if (this.userConfig.default || JSON.stringify(this.userConfig) === "{'client':'geth'}") {
if (this.env === "development") {
this.isDev = true;
} else {
this.config.genesisBlock = embarkPath("templates/boilerplate/config/privatenet/genesis.json");
}
this.config.datadir = dappPath(".embark/development/datadir");
this.config.wsOrigins = this.config.wsOrigins || "http://localhost:8000";
this.config.rpcCorsDomain = this.config.rpcCorsDomain || "http://localhost:8000";
this.config.targetGasLimit = 8000000;
}
this.config.account.devPassword = path.join(this.config.datadir, "devPassword");
const spaceMessage = "The path for %s in blockchain config contains spaces, please remove them";
if (this.config.datadir && this.config.datadir.indexOf(" ") > 0) {
this.logger.error(__(spaceMessage, "datadir"));
process.exit(1);
}
if (this.config.account.password && this.config.account.password.indexOf(" ") > 0) {
this.logger.error(__(spaceMessage, "accounts.password"));
process.exit(1);
}
if (this.config.genesisBlock && this.config.genesisBlock.indexOf(" ") > 0) {
this.logger.error(__(spaceMessage, "genesisBlock"));
process.exit(1);
}
this.client = new clientClass({config: this.config, env: this.env, isDev: this.isDev, communicationConfig: communicationConfig});
if (this.isStandalone) {
this.initStandaloneProcess();
}
};
/**
* Polls for a connection to an IPC server (generally this is set up
* in the Embark process). Once connected, any logs logged to the
* Logger will be shipped off to the IPC server. In the case of `embark
* run`, the BlockchainListener module is listening for these logs.
*
* @return {void}
*/
Blockchain.prototype.initStandaloneProcess = function() {
let logQueue = [];
// on every log logged in logger (say that 3x fast), send the log
// to the IPC serve listening (only if we're connected of course)
this.logger.events.on("log", (logLevel, message) => {
if (this.ipc.connected) {
this.ipc.request("blockchain:log", {logLevel, message});
} else {
logQueue.push({logLevel, message});
}
});
this.ipc = new IPC({ipcRole: "client"});
// Wait for an IPC server to start (ie `embark run`) by polling `.connect()`.
// Do not kill this interval as the IPC server may restart (ie restart
// `embark run` without restarting `embark blockchain`)
setInterval(() => {
if (!this.ipc.connected) {
this.ipc.connect(() => {
if (this.ipc.connected) {
logQueue.forEach((message) => {
this.ipc.request("blockchain:log", message);
});
logQueue = [];
this.ipc.client.on("process:blockchain:stop", () => {
this.kill();
process.exit(0);
});
}
});
}
}, IPC_CONNECT_INTERVAL);
};
Blockchain.prototype.runCommand = function (cmd, options, callback) {
this.logger.info(__("running: %s", cmd.underline).green);
if (this.config.silent) {
options.silent = true;
}
return exec(cmd, options, callback);
};
Blockchain.prototype.run = function () {
var self = this;
this.logger.info("===============================================================================".magenta);
this.logger.info("===============================================================================".magenta);
this.logger.info(__("Embark Whisper using %s", self.client.prettyName.underline).magenta);
this.logger.info("===============================================================================".magenta);
this.logger.info("===============================================================================".magenta);
if (self.client.name === constants.blockchain.clients.geth) this.checkPathLength();
let address = "";
async.waterfall([
function checkInstallation(next) {
self.isClientInstalled((err) => {
if (err) {
return next({ message: err });
}
next();
});
},
function getMainCommand(next) {
self.client.mainCommand(address, function (cmd, args) {
next(null, cmd, args);
}, true);
}
], function(err, cmd, args) {
if (err) {
self.logger.error(err.message);
return;
}
args = compact(args);
let full_cmd = cmd + " " + args.join(" ");
self.logger.info(__(">>>>>>>>>>>>>>>> running: %s", full_cmd.underline).green);
self.child = spawn(cmd, args, {cwd: process.cwd()});
self.child.on("error", (err) => {
err = err.toString();
self.logger.error("Blockchain error: ", err);
if (self.env === "development" && err.indexOf("Failed to unlock") > 0) {
self.logger.error("\n" + __("Development blockchain has changed to use the --dev option.").yellow);
self.logger.error(__("You can reset your workspace to fix the problem with").yellow + " embark reset".cyan);
self.logger.error(__("Otherwise, you can change your data directory in blockchain.json (datadir)").yellow);
}
});
// TOCHECK I don't understand why stderr and stdout are reverted.
// This happens with Geth and Parity, so it does not seems a client problem
self.child.stdout.on("data", (data) => {
self.logger.info(`${self.client.name} error: ${data}`);
});
self.child.stderr.on("data", async (data) => {
data = data.toString();
if (!self.readyCalled && self.client.isReady(data)) {
self.readyCalled = true;
self.readyCallback();
}
self.logger.info(`${self.client.name}: ${data}`);
});
self.child.on("exit", (code) => {
let strCode;
if (code) {
strCode = "with error code " + code;
} else {
strCode = "with no error code (manually killed?)";
}
self.logger.error(self.client.name + " exited " + strCode);
if (self.onExitCallback) {
self.onExitCallback();
}
});
self.child.on("uncaughtException", (err) => {
self.logger.error("Uncaught " + self.client.name + " exception", err);
if (self.onExitCallback) {
self.onExitCallback();
}
});
});
};
Blockchain.prototype.readyCallback = function () {
if (this.onReadyCallback) {
this.onReadyCallback();
}
};
Blockchain.prototype.kill = function () {
if (this.child) {
this.child.kill();
}
};
Blockchain.prototype.checkPathLength = function () {
let _dappPath = dappPath("");
if (_dappPath.length > 66) {
// this.logger.error is captured and sent to the console output regardless of silent setting
this.logger.error("===============================================================================".yellow);
this.logger.error("===========> ".yellow + __("WARNING! ÐApp path length is too long: ").yellow + _dappPath.yellow);
this.logger.error("===========> ".yellow + __("This is known to cause issues with starting geth, please consider reducing your ÐApp path\'s length to 66 characters or less.").yellow);
this.logger.error("===============================================================================".yellow);
}
};
Blockchain.prototype.isClientInstalled = function (callback) {
let versionCmd = this.client.determineVersionCommand();
this.runCommand(versionCmd, {}, (err, stdout, stderr) => {
if (err || !stdout || stderr.indexOf("not found") >= 0 || stdout.indexOf("not found") >= 0) {
return callback(__("Ethereum client bin not found:") + " " + this.client.getBinaryPath());
}
const parsedVersion = this.client.parseVersion(stdout);
const supported = this.client.isSupportedVersion(parsedVersion);
if (supported === undefined) {
this.logger.warn((__("WARNING! Ethereum client version could not be determined or compared with version range") + " " + this.client.versSupported + __(", for best results please use a supported version")));
} else if (!supported) {
this.logger.warn((__("WARNING! Ethereum client version unsupported, for best results please use a version in range") + " " + this.client.versSupported));
}
callback();
});
};
export function BlockchainClient(userConfig, options, communicationConfig) {
if ((JSON.stringify(userConfig) === "{'enabled':true}") && options.env !== "development") {
options.logger.info("===> " + __("warning: running default config on a non-development environment"));
}
// if client is not set in preferences, default is geth
if (!userConfig.client) userConfig.client = constants.blockchain.clients.geth;
// if clientName is set, it overrides preferences
if (options.clientName) userConfig.client = options.clientName;
userConfig.isDev = (userConfig.isDev || userConfig.default);
userConfig.env = options.env;
userConfig.onReadyCallback = options.onReadyCallback;
userConfig.onExitCallback = options.onExitCallback;
userConfig.logger = options.logger;
userConfig.certOptions = options.certOptions;
userConfig.isStandalone = options.isStandalone;
return new Blockchain(userConfig, WhisperGethClient, communicationConfig);
}

View File

@ -0,0 +1,59 @@
import * as i18n from "embark-i18n";
import { ProcessWrapper } from "embark-core";
const constants = require("embark-core/constants");
import { BlockchainClient as blockchainClient } from "./blockchain";
let blockchainProcess;
class BlockchainProcess extends ProcessWrapper {
constructor(options) {
super();
this.blockchainConfig = options.blockchainConfig;
this.communicationConfig = options.communicationConfig;
this.client = options.client;
this.env = options.env;
this.isDev = options.isDev;
this.certOptions = options.certOptions;
i18n.setOrDetectLocale(options.locale);
this.blockchainConfig.silent = true;
this.blockchain = blockchainClient(
this.blockchainConfig,
{
clientName: this.client,
env: this.env,
certOptions: this.certOptions,
onReadyCallback: this.blockchainReady.bind(this),
onExitCallback: this.blockchainExit.bind(this),
logger: console
},
this.communicationConfig
);
this.blockchain.run();
}
blockchainReady() {
blockchainProcess.send({result: constants.blockchain.blockchainReady});
}
blockchainExit() {
// tell our parent process that ethereum client has exited
blockchainProcess.send({result: constants.blockchain.blockchainExit});
}
kill() {
this.blockchain.kill();
}
}
process.on("message", (msg) => {
if (msg === "exit") {
return blockchainProcess.kill();
}
if (msg.action === constants.blockchain.init) {
blockchainProcess = new BlockchainProcess(msg.options);
return blockchainProcess.send({result: constants.blockchain.initiated});
}
});

View File

@ -0,0 +1,84 @@
import { __ } from "embark-i18n";
import { ProcessLauncher } from "embark-core";
import { joinPath } from "embark-utils";
const constants = require("embark-core/constants");
export class BlockchainProcessLauncher {
constructor(options) {
this.events = options.events;
this.logger = options.logger;
this.normalizeInput = options.normalizeInput;
this.blockchainConfig = options.blockchainConfig;
this.communicationConfig = options.communicationConfig;
this.locale = options.locale;
this.isDev = options.isDev;
this.client = options.client;
this.embark = options.embark;
}
processEnded(code) {
this.logger.error(__("Blockchain process ended before the end of this process. Try running blockchain in a separate process using `$ embark blockchain`. Code: %s", code));
}
startBlockchainNode(readyCb) {
this.logger.info(__("Starting Whisper node in another process").cyan);
this.blockchainProcess = new ProcessLauncher({
name: "blockchain",
modulePath: joinPath(__dirname, "./blockchainProcess.js"),
logger: this.logger,
events: this.events,
silent: this.logger.logLevel !== "trace",
exitCallback: this.processEnded.bind(this),
embark: this.embark
});
this.blockchainProcess.send({
action: constants.blockchain.init, options: {
blockchainConfig: this.blockchainConfig,
communicationConfig: this.communicationConfig,
client: this.client,
env: this.env,
isDev: this.isDev,
locale: this.locale,
certOptions: this.embark.config.webServerConfig.certOptions,
events: this.events
}
});
this.blockchainProcess.once("result", constants.blockchain.blockchainReady, () => {
this.logger.info(__("Whisper blockchain node is ready").cyan);
readyCb();
});
this.blockchainProcess.once("result", constants.blockchain.blockchainExit, () => {
// tell everyone that our blockchain process (ie geth) died
this.events.emit(constants.blockchain.blockchainExit);
// then kill off the blockchain process
this.blockchainProcess.kill();
});
this.events.on("logs:ethereum:enable", () => {
this.blockchainProcess.silent = false;
});
this.events.on("logs:ethereum:disable", () => {
this.blockchainProcess.silent = true;
});
this.events.on("exit", () => {
this.blockchainProcess.send("exit");
});
}
stopBlockchainNode(cb) {
if (this.blockchainProcess) {
this.events.once(constants.blockchain.blockchainExit, cb);
this.blockchainProcess.exitCallback = () => { }; // don"t show error message as the process was killed on purpose
this.blockchainProcess.send("exit");
}
}
}

View File

@ -0,0 +1,63 @@
const WebSocket = require("ws");
const http = require("http");
const LIVENESS_CHECK = JSON.stringify({
jsonrpc:'2.0',
method: 'shh_version',
params:[],
id:42
});
// eslint-disable-next-line complexity
const parseAndRespond = (data, cb) => {
let resp;
try {
resp = JSON.parse(data);
if (resp.error) {
return cb(resp.error);
}
} catch (e) {
return cb("Version data is not valid JSON");
}
if (!resp || !resp.result) {
return cb("No version returned");
}
cb(null, resp.result);
};
const rpc = (host, port, cb) => {
const options = {
hostname: host, // TODO(andremedeiros): get from config
port, // TODO(andremedeiros): get from config
method: "POST",
timeout: 1000,
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(LIVENESS_CHECK)
}
};
const req = http.request(options, (res) => {
let data = "";
res.on("data", (chunk) => { data += chunk; });
res.on("end", () => parseAndRespond(data, cb));
});
req.on("error", (e) => cb(e));
req.write(LIVENESS_CHECK);
req.end();
};
const ws = (host, port, cb) => {
const conn = new WebSocket("ws://" + host + ":" + port);
conn.on("message", (data) => {
parseAndRespond(data, cb);
conn.close();
});
conn.on("open", () => conn.send(LIVENESS_CHECK));
conn.on("error", (e) => cb(e));
};
module.exports = {
ws,
rpc
};

View File

@ -0,0 +1,115 @@
import { __ } from "embark-i18n";
import { dappPath, canonicalHost, defaultHost } from "embark-utils";
const constants = require("embark-core/constants");
const API = require("./api.js");
import { BlockchainProcessLauncher } from "./blockchainProcessLauncher";
import { ws, rpc } from "./check.js";
const { normalizeInput } = require("embark-utils");
class Whisper {
constructor(embark, _options) {
this.logger = embark.logger;
this.events = embark.events;
this.fs = embark.fs;
this.blockchainConfig = embark.config.blockchainConfig;
this.communicationConfig = embark.config.communicationConfig;
this.embarkConfig = embark.config.embarkConfig;
this.embark = embark;
this.webSocketsChannels = {};
this.modulesPath = dappPath(embark.config.embarkConfig.generationDir, constants.dappArtifacts.symlinkDir);
if (!this.communicationConfig.enabled || this.blockchainConfig.client !== constants.blockchain.clients.geth) {
return;
}
this.api = new API(embark);
this.whisperNodes = {};
this.events.request("embarkjs:plugin:register", "messages", "whisper", "embarkjs-whisper");
this.events.request("embarkjs:console:register", "messages", "whisper", "embarkjs-whisper");
this.events.request("communication:node:register", "whisper", (readyCb) => {
this.events.request("processes:register", "communication", {
launchFn: (cb) => {
this.startWhisperNode(cb);
},
stopFn: (cb) => {
this.stopWhisperNode(cb);
}
});
this.events.request("processes:launch", "communication", (err) => {
if (err) {
this.logger.error(`Error launching whisper process: ${err.message || err}`);
}
readyCb();
});
this.registerServiceCheck();
});
this.events.on("communication:started", () => {
this.api = new API(embark);
this.api.registerAPICalls();
this.connectEmbarkJSProvider();
});
}
_getNodeState(err, version, cb) {
if (err) return cb({ name: "Whisper node not found", status: "off" });
const name = `Whisper v${version} (Geth)`;
return cb({ name, status: "on" });
}
registerServiceCheck() {
this.events.request("services:register", "Whisper", (cb) => {
const { host, port, type } = this.communicationConfig.connection;
if (type === "ws") {
return ws(host, port, (err, version) => this._getNodeState(err, version, cb));
}
rpc(host, port, (err, version) => this._getNodeState(err, version, cb));
}, 5000, "off");
}
startWhisperNode(callback) {
this.whisperProcess = new BlockchainProcessLauncher({
events: this.events,
logger: this.logger,
normalizeInput,
blockchainConfig: this.blockchainConfig,
communicationConfig: this.communicationConfig,
locale: this.locale,
client: constants.blockchain.clients.whisper,
isDev: this.isDev,
embark: this.embark
});
this.whisperProcess.startBlockchainNode(callback);
}
stopWhisperNode(cb) {
if (!this.whisperProcess) {
return cb();
}
this.whisperProcess.stopBlockchainNode(() => {
this.logger.info(`The whisper process has been stopped.`);
cb();
});
}
// esline-disable-next-line complexity
async connectEmbarkJSProvider() {
let connection = this.communicationConfig.connection || {};
const config = {
server: canonicalHost(connection.host || defaultHost),
port: connection.port || "8546",
type: connection.type || "ws"
};
this.events.request("embarkjs:console:setProvider", "messages", "whisper", config);
}
}
module.exports = Whisper;

View File

@ -1,17 +1,16 @@
import { __ } from 'embark-i18n';
const async = require('async');
const GethMiner = require('./miner');
const semver = require('semver');
const constants = require('embark-core/constants');
import { __ } from "embark-i18n";
const async = require("async");
const semver = require("semver");
const constants = require("embark-core/constants");
const DEFAULTS = {
"BIN": "geth",
"VERSIONS_SUPPORTED": ">=1.9.7",
"NETWORK_TYPE": "custom",
"NETWORK_ID": 1337,
"RPC_API": ['web3'],
"WS_API": ['web3', 'shh'],
"DEV_WS_API": ['web3', 'shh'],
"RPC_API": ["web3"],
"WS_API": ["web3", "shh"],
"DEV_WS_API": ["web3", "shh"],
"TARGET_GAS_LIMIT": 8000000
};
@ -21,11 +20,12 @@ class WhisperGethClient {
return DEFAULTS;
}
// eslint-disable-next-line complexity
constructor(options) {
this.config = options && options.hasOwnProperty('config') ? options.config : {};
this.config = options && options.hasOwnProperty("config") ? options.config : {};
this.communicationConfig = options.communicationConfig;
this.env = options && options.hasOwnProperty('env') ? options.env : 'development';
this.isDev = options && options.hasOwnProperty('isDev') ? options.isDev : (this.env === 'development');
this.env = options && options.hasOwnProperty("env") ? options.env : "development";
this.isDev = options && options.hasOwnProperty("isDev") ? options.isDev : (this.env === "development");
this.name = constants.blockchain.clients.geth;
this.prettyName = "Go-Ethereum (https://github.com/ethereum/go-ethereum)";
this.bin = this.config.ethereumClientBin || DEFAULTS.BIN;
@ -35,26 +35,14 @@ class WhisperGethClient {
}
isReady(data) {
if (data.indexOf('WebSocket endpoint opened') > -1) {
if (data.indexOf("WebSocket endpoint opened") > -1) {
this.wsReady = true;
}
return this.wsReady;
}
/**
* Check if the client needs some sort of 'keep alive' transactions to avoid freezing by inactivity
* @returns {boolean} if keep alive is needed
*/
needKeepAlive() {
return false;
}
commonOptions() {
return ['--ipcdisable'];
}
getMiner() {
return new GethMiner({datadir: this.config.datadir});
return [];
}
getBinaryPath() {
@ -79,8 +67,10 @@ class WhisperGethClient {
try {
let v = semver(parsedVersion);
v = `${v.major}.${v.minor}.${v.patch}`;
// eslint-disable-next-line no-cap
test = semver.Range(this.versSupported).test(semver(v));
if (typeof test !== 'boolean') {
if (typeof test !== "boolean") {
// eslint-disable-next-line no-undefined
test = undefined;
}
} finally {
@ -91,11 +81,11 @@ class WhisperGethClient {
determineNetworkType(config) {
let cmd;
if (config.networkType === 'testnet') {
if (config.networkType === "testnet") {
cmd = "--testnet";
} else if (config.networkType === 'rinkeby') {
} else if (config.networkType === "rinkeby") {
cmd = "--rinkeby";
} else if (config.networkType === 'custom') {
} else if (config.networkType === "custom") {
cmd = "--networkid=" + config.networkId;
}
return cmd;
@ -109,38 +99,6 @@ class WhisperGethClient {
return "";
}
newAccountCommand() {
return "";
}
parseNewAccountCommandResultToAddress(data = "") {
if (data.match(/{(\w+)}/)) return "0x" + data.match(/{(\w+)}/)[1];
return "";
}
listAccountsCommand() {
return "";
}
parseListAccountsCommandResultToAddress(data = "") {
if (data.match(/{(\w+)}/)) return "0x" + data.match(/{(\w+)}/)[1];
return "";
}
parseListAccountsCommandResultToAddressList(data = "") {
const regex = RegExp(/{(\w+)}/g);
let match;
const accounts = [];
while ((match = regex.exec(data)) !== null) {
accounts.push('0x' + match[1]);
}
return accounts;
}
parseListAccountsCommandResultToAddressCount(_data = "") {
return 0;
}
determineRpcOptions(config) {
let cmd = [];
cmd.push("--port=30304");
@ -149,21 +107,22 @@ class WhisperGethClient {
cmd.push("--rpcaddr=" + config.rpcHost);
if (config.rpcCorsDomain) {
if (config.rpcCorsDomain === '*') {
console.warn('==================================');
console.warn(__('rpcCorsDomain set to *'));
console.warn(__('make sure you know what you are doing'));
console.warn('==================================');
if (config.rpcCorsDomain === "*") {
console.warn("==================================");
console.warn(__("rpcCorsDomain set to *"));
console.warn(__("make sure you know what you are doing"));
console.warn("==================================");
}
cmd.push("--rpccorsdomain=" + config.rpcCorsDomain);
} else {
console.warn('==================================');
console.warn(__('warning: cors is not set'));
console.warn('==================================');
console.warn("==================================");
console.warn(__("warning: cors is not set"));
console.warn("==================================");
}
return cmd;
}
// eslint-disable-next-line complexity
determineWsOptions(config, communicationConfig) {
let cmd = [];
if (config.wsRPC) {
@ -173,17 +132,17 @@ class WhisperGethClient {
cmd.push(`--wsaddr=${communicationConfig.connection.host || config.wsHost++}`);
if (config.wsOrigins) {
if (config.wsOrigins === '*') {
console.warn('==================================');
console.warn(__('wsOrigins set to *'));
console.warn(__('make sure you know what you are doing'));
console.warn('==================================');
if (config.wsOrigins === "*") {
console.warn("==================================");
console.warn(__("wsOrigins set to *"));
console.warn(__("make sure you know what you are doing"));
console.warn("==================================");
}
cmd.push("--wsorigins=" + config.wsOrigins);
} else {
console.warn('==================================');
console.warn(__('warning: wsOrigins is not set'));
console.warn('==================================');
console.warn("==================================");
console.warn(__("warning: wsOrigins is not set"));
console.warn("==================================");
}
}
return cmd;
@ -196,8 +155,8 @@ class WhisperGethClient {
mainCommand(address, done) {
let self = this;
let config = this.config;
let rpc_api = this.config.rpcApi;
let ws_api = this.config.wsApi;
let rpcApi = this.config.rpcApi;
let wsApi = this.config.wsApi;
let args = [];
async.series([
function commonOptions(callback) {
@ -217,7 +176,7 @@ class WhisperGethClient {
}
callback(null, "");
},
function maxPeers(callback) {
function maxPeers(callback) {
let cmd = "--maxpeers=" + config.maxpeers;
args.push(cmd);
callback(null, cmd);
@ -230,22 +189,22 @@ class WhisperGethClient {
callback("");
},
function whisper(callback) {
rpc_api.push('shh');
if (ws_api.indexOf('shh') === -1) {
ws_api.push('shh');
rpcApi.push("shh");
if (wsApi.indexOf("shh") === -1) {
wsApi.push("shh");
}
args.push("--shh");
return callback(null, "--shh ");
},
function rpcApi(callback) {
args.push('--rpcapi=' + rpc_api.join(','));
callback(null, '--rpcapi=' + rpc_api.join(','));
function rpcApiArgs(callback) {
args.push("--rpcapi=" + rpcApi.join(","));
callback(null, "--rpcapi=" + rpcApi.join(","));
},
function wsApi(callback) {
args.push('--wsapi=' + ws_api.join(','));
callback(null, '--wsapi=' + ws_api.join(','));
function wsApiArgs(callback) {
args.push("--wsapi=" + wsApi.join(","));
callback(null, "--wsapi=" + wsApi.join(","));
}
], function(err) {
], function (err) {
if (err) {
throw new Error(err.message);
}

View File

@ -0,0 +1,115 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [5.0.0-alpha.1](https://github.com/embark-framework/embark/compare/v5.0.0-alpha.0...v5.0.0-alpha.1) (2019-11-05)
**Note:** Version bump only for package embark-whisper
# [5.0.0-alpha.0](https://github.com/embark-framework/embark/compare/v4.1.1...v5.0.0-alpha.0) (2019-10-28)
### Build System
* bump all packages' engines settings ([#1985](https://github.com/embark-framework/embark/issues/1985)) ([ed02cc8](https://github.com/embark-framework/embark/commit/ed02cc8))
### BREAKING CHANGES
* node: >=10.17.0 <12.0.0
npm: >=6.11.3
yarn: >=1.19.1
node v10.17.0 is the latest in the 10.x series and is still in the Active LTS
lifecycle. Embark is still not compatible with node's 12.x and 13.x
series (because of some dependencies), otherwise it would probably make sense
to bump our minimum supported node version all the way to the most recent 12.x
release.
npm v6.11.3 is the version that's bundled with node v10.17.0.
yarn v1.19.1 is the most recent version as of the time node v10.17.0 was
released.
## [4.1.1](https://github.com/embark-framework/embark/compare/v4.1.0...v4.1.1) (2019-08-28)
**Note:** Version bump only for package embark-whisper
# [4.1.0](https://github.com/embark-framework/embark/compare/v4.1.0-beta.6...v4.1.0) (2019-08-12)
**Note:** Version bump only for package embark-whisper
# [4.1.0-beta.6](https://github.com/embark-framework/embark/compare/v4.1.0-beta.5...v4.1.0-beta.6) (2019-08-09)
**Note:** Version bump only for package embark-whisper
# [4.1.0-beta.5](https://github.com/embark-framework/embark/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2019-07-10)
**Note:** Version bump only for package embark-whisper
# [4.1.0-beta.4](https://github.com/embark-framework/embark/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2019-06-27)
### Bug Fixes
* alleviate races re: embarkjs by introducing Plugin#addGeneratedCode and related refactors ([fc4faa8](https://github.com/embark-framework/embark/commit/fc4faa8))
# [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)
### Bug Fixes
* **@embarkjs:** unconditionally require symlinked embarkjs-* modules ([b45b2e2](https://github.com/embark-framework/embark/commit/b45b2e2))
# [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 embark-whisper
# [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 embark-whisper
# [4.1.0-beta.0](https://github.com/embark-framework/embark/compare/v4.0.0...v4.1.0-beta.0) (2019-04-17)
**Note:** Version bump only for package embark-whisper

View File

@ -0,0 +1,6 @@
# `embark-whisper-parity`
> Module to add Whisper support to Embark for the Parity blockchain
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).

View File

@ -0,0 +1,65 @@
{
"name": "embark-whisper-parity",
"version": "5.0.0-alpha.1",
"author": "Iuri Matias <iuri.matias@gmail.com>",
"contributors": [],
"description": "Module to add Whisper support to Embark",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/plugins/whisper-parity#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"keywords": [
"blockchain",
"dapps",
"ethereum",
"ipfs",
"serverless",
"solc",
"solidity"
],
"files": [
"dist"
],
"license": "MIT",
"repository": {
"directory": "packages/plugins/whisper-parity",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"main": "./dist/index.js",
"embark-collective": {
"build:node": true
},
"scripts": {
"_build": "npm run solo -- build",
"ci": "npm run qa",
"clean": "npm run reset",
"lint": "eslint src/",
"qa": "npm-run-all lint _build",
"reset": "npx rimraf dist embark-*.tgz package",
"solo": "embark-solo"
},
"eslintConfig": {
"extends": "../../../.eslintrc.json"
},
"dependencies": {
"@babel/runtime-corejs3": "7.6.3",
"async": "2.6.1",
"core-js": "3.3.5",
"embark-core": "^5.0.0-alpha.1",
"embark-i18n": "^5.0.0-alpha.1",
"embark-utils": "^5.0.0-alpha.1",
"embarkjs-whisper": "^5.0.0-alpha.1",
"rxjs": "6.4.0"
},
"devDependencies": {
"embark-solo": "^5.0.0-alpha.0",
"eslint": "5.7.0",
"npm-run-all": "4.1.5",
"rimraf": "3.0.0",
"web3": "1.2.1"
},
"engines": {
"node": ">=10.17.0 <12.0.0",
"npm": ">=6.11.3",
"yarn": ">=1.19.1"
}
}

View File

@ -0,0 +1,51 @@
import EmbarkJS from "embarkjs";
import EmbarkJSWhisper from "embarkjs-whisper";
class API {
constructor(embark) {
this.embark = embark;
this.communicationConfig = embark.config.communicationConfig;
}
async initEmbarkJSWhisper() {
if (Object.keys(EmbarkJS.Messages.Providers).includes("whisper")) return;
EmbarkJS.Messages.registerProvider("whisper", EmbarkJSWhisper);
EmbarkJS.Messages.setProvider("whisper", this.communicationConfig.connection);
}
async registerAPICalls() {
this.initEmbarkJSWhisper();
this.registerSendMessageCall();
this.registerListenToCall();
}
async registerSendMessageCall() {
this.embark.registerAPICall(
"post",
"/embark-api/communication/sendMessage",
(req, res) => {
EmbarkJS.Messages.sendMessage({ topic: req.body.topic, data: req.body.message }, (err, result) => {
if (err) {
return res.status(500).send({ error: err });
}
res.send(result);
});
});
}
async registerListenToCall() {
this.embark.registerAPICall(
"ws",
"/embark-api/communication/listenTo/:topic",
(ws, req) => {
EmbarkJS.Messages.listenTo({ topic: req.params.topic }).subscribe(data => {
ws.send(JSON.stringify(data));
});
});
}
}
module.exports = API;

View File

@ -0,0 +1,65 @@
const WebSocket = require("ws");
const http = require("http");
const LIVENESS_CHECK = JSON.stringify({
jsonrpc: '2.0',
method: 'web3_clientVersion',
params:[],
id:42
});
// eslint-disable-next-line complexity
const parseAndRespond = (data, cb) => {
let resp;
try {
resp = JSON.parse(data);
if (resp.error) {
return cb(resp.error);
}
} catch (e) {
return cb("Version data is not valid JSON");
}
if (!resp || !resp.result) {
return cb("No version returned");
}
const result = resp.result.replace("//", "/");
const [_, version, __] = result.split("/");
cb(null, version);
};
const rpc = (host, port, cb) => {
const options = {
hostname: host, // TODO(andremedeiros): get from config
port, // TODO(andremedeiros): get from config
method: "POST",
timeout: 1000,
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(LIVENESS_CHECK)
}
};
const req = http.request(options, (res) => {
let data = "";
res.on("data", (chunk) => { data += chunk; });
res.on("end", () => parseAndRespond(data, cb));
});
req.on("error", (e) => cb(e));
req.write(LIVENESS_CHECK);
req.end();
};
const ws = (host, port, cb) => {
const conn = new WebSocket("ws://" + host + ":" + port);
conn.on("message", (data) => {
parseAndRespond(data, cb);
conn.close();
});
conn.on("open", () => conn.send(LIVENESS_CHECK));
conn.on("error", (e) => cb(e));
};
module.exports = {
ws,
rpc
};

View File

@ -0,0 +1,100 @@
import { __ } from "embark-i18n";
import { dappPath, canonicalHost, defaultHost } from "embark-utils";
const constants = require("embark-core/constants");
const API = require("./api.js");
import { ws, rpc } from "./check.js";
class Whisper {
constructor(embark, _options) {
this.logger = embark.logger;
this.events = embark.events;
this.fs = embark.fs;
this.blockchainConfig = embark.config.blockchainConfig;
this.communicationConfig = embark.config.communicationConfig;
this.embarkConfig = embark.config.embarkConfig;
this.embark = embark;
this.webSocketsChannels = {};
this.modulesPath = dappPath(embark.config.embarkConfig.generationDir, constants.dappArtifacts.symlinkDir);
if (!this.communicationConfig.enabled || this.blockchainConfig.client !== constants.blockchain.clients.parity) {
return;
}
this.api = new API(embark);
this.whisperNodes = {};
this.events.request("embarkjs:plugin:register", "messages", "whisper", "embarkjs-whisper");
this.events.request("embarkjs:console:register", "messages", "whisper", "embarkjs-whisper");
this.events.request("communication:node:register", "whisper", (readyCb) => {
this.events.request("processes:register", "communication", {
launchFn: (cb) => {
this.startWhisperNode(cb);
},
stopFn: (cb) => {
this.stopWhisperNode(cb);
}
});
this.events.request("processes:launch", "communication", (err) => {
if (err) {
this.logger.error(`Error launching whisper process: ${err.message || err}`);
}
readyCb();
});
this.registerServiceCheck();
});
this.events.on("communication:started", () => {
this.api = new API(embark);
this.api.registerAPICalls();
this.connectEmbarkJSProvider();
});
}
_getNodeState(err, version, cb) {
if (err) return cb({ name: "Whisper node not found", status: "off" });
let nodeName = "Parity";
let versionNumber = version.split("-")[0];
let name = nodeName + " " + versionNumber + " (Whisper)";
return cb({ name, status: "on" });
}
registerServiceCheck() {
this.events.request("services:register", "Whisper", (cb) => {
const { host, port, type } = this.communicationConfig.connection;
if (type === "ws") {
return ws(host, port, (err, version) => this._getNodeState(err, version, cb));
}
rpc(host, port, (err, version) => this._getNodeState(err, version, cb));
}, 5000, "off");
}
startWhisperNode(callback) {
this.logger.info(`Whisper node has already been started with the Parity blockchain.`);
callback();
}
stopWhisperNode(cb) {
this.logger.warn(`Cannot stop Whisper process as it has been started with the Parity blockchain.`);
cb();
}
// esline-disable-next-line complexity
async connectEmbarkJSProvider() {
let connection = this.communicationConfig.connection || {};
const config = {
server: canonicalHost(connection.host || defaultHost),
port: connection.port || "8546",
type: connection.type || "ws"
};
this.events.request("embarkjs:console:setProvider", "messages", "whisper", config);
}
}
module.exports = Whisper;

View File

@ -1,56 +0,0 @@
import { __ } from 'embark-i18n';
import {canonicalHost, defaultHost} from 'embark-utils';
const API = require('./api.js');
class Whisper {
constructor(embark, _options) {
this.logger = embark.logger;
this.events = embark.events;
this.fs = embark.fs;
this.communicationConfig = embark.config.communicationConfig;
this.embarkConfig = embark.config.embarkConfig;
this.embark = embark;
this.api = new API(embark);
this.whisperNodes = {};
this.events.request("embarkjs:plugin:register", 'messages', 'whisper', 'embarkjs-whisper');
this.events.request("embarkjs:console:register", 'messages', 'whisper', 'embarkjs-whisper');
this.events.setCommandHandler("whisper:node:register", (clientName, startCb) => {
this.whisperNodes[clientName] = startCb;
});
this.events.request("communication:node:register", "whisper", (readyCb) => {
if (this.communicationConfig.connection.port === this.embark.config.blockchainConfig.wsPort) {
this.logger.warn(__('Communication connection set to open on port %s, which is the same as your blockchain node. It will probably conflict', this.communicationConfig.connection.port));
this.logger.warn(__('You can change that port in your communication config file as `connection.port`'));
}
let clientName = this.communicationConfig.client || "geth";
let registerCb = this.whisperNodes[clientName];
if (!registerCb) return readyCb("whisper client " + clientName + " not found");
registerCb.apply(registerCb, [readyCb]);
});
this.events.on("communication:started", () => {
this.api = new API(embark);
this.api.registerAPICalls();
this.connectEmbarkJSProvider();
});
}
async connectEmbarkJSProvider() {
let connection = this.communicationConfig.connection || {};
const config = {
server: canonicalHost(connection.host || defaultHost),
port: connection.port || '8557',
type: connection.type || 'ws'
};
this.events.request("embarkjs:console:setProvider", 'messages', 'whisper', config);
}
}
module.exports = Whisper;