diff --git a/dapps/templates/boilerplate/config/communication.js b/dapps/templates/boilerplate/config/communication.js index 584fe7ef5..9dd9dfaf4 100644 --- a/dapps/templates/boilerplate/config/communication.js +++ b/dapps/templates/boilerplate/config/communication.js @@ -4,6 +4,7 @@ module.exports = { enabled: true, provider: "whisper", // Communication provider. Currently, Embark only supports whisper available_providers: ["whisper"], // Array of available providers + client: "geth" }, // default environment, merges with the settings in default @@ -35,12 +36,12 @@ module.exports = { // "embark run custom_name" //custom_name: { //} - // Use this section when you need a specific symmetric or private keys in whisper - /* - ,keys: { - symmetricKey: "your_symmetric_key",// Symmetric key for message decryption - privateKey: "your_private_key" // Private Key to be used as a signing key and for message decryption - } - */ + // Use this section when you need a specific symmetric or private keys in whisper + /* + ,keys: { + symmetricKey: "your_symmetric_key",// Symmetric key for message decryption + privateKey: "your_private_key" // Private Key to be used as a signing key and for message decryption + } + */ //} }; diff --git a/dapps/templates/demo/config/communication.js b/dapps/templates/demo/config/communication.js index 77f13987c..c7226403e 100644 --- a/dapps/templates/demo/config/communication.js +++ b/dapps/templates/demo/config/communication.js @@ -4,6 +4,7 @@ module.exports = { enabled: true, provider: "whisper", // Communication provider. Currently, Embark only supports whisper available_providers: ["whisper"], // Array of available providers + client: "geth" }, // default environment, merges with the settings in default @@ -36,11 +37,11 @@ module.exports = { // "embark run custom_name" //custom_name: { //} - // Use this section when you need a specific symmetric or private keys in whisper - /* - ,keys: { - symmetricKey: "your_symmetric_key",// Symmetric key for message decryption - privateKey: "your_private_key" // Private Key to be used as a signing key and for message decryption - } - */ + // Use this section when you need a specific symmetric or private keys in whisper + /* + ,keys: { + symmetricKey: "your_symmetric_key",// Symmetric key for message decryption + privateKey: "your_private_key" // Private Key to be used as a signing key and for message decryption + } + */ }; diff --git a/packages/cockpit/ui/src/components/Communication.js b/packages/cockpit/ui/src/components/Communication.js index 5819b5c07..ebbe60f84 100644 --- a/packages/cockpit/ui/src/components/Communication.js +++ b/packages/cockpit/ui/src/components/Communication.js @@ -1,5 +1,5 @@ import PropTypes from "prop-types"; -import React, {Component} from 'react'; +import React, { Component } from 'react'; import { Button, Card, @@ -13,6 +13,7 @@ import { ListGroup, ListGroupItem } from 'reactstrap'; +import Error from "./Error"; class Communication extends Component { constructor(props) { @@ -61,6 +62,7 @@ class Communication extends Component { return ( + {this.props.error && this.props.error.error && } Listen to channel @@ -147,7 +149,8 @@ Communication.propTypes = { sendMessage: PropTypes.func, listenToMessages: PropTypes.func, subscriptions: PropTypes.array, - channels: PropTypes.object + channels: PropTypes.object, + error: PropTypes.object }; export default Communication; diff --git a/packages/cockpit/ui/src/containers/CommunicationContainer.js b/packages/cockpit/ui/src/containers/CommunicationContainer.js index d0d2e7b4c..5ea7706d0 100644 --- a/packages/cockpit/ui/src/containers/CommunicationContainer.js +++ b/packages/cockpit/ui/src/containers/CommunicationContainer.js @@ -5,7 +5,7 @@ import { Alert } from 'reactstrap'; import {messageSend, messageListen, versions} from "../actions"; import Communication from "../components/Communication"; import PageHead from "../components/PageHead"; -import {getMessages, getMessageChannels, isOldWeb3, isWeb3Enabled} from "../reducers/selectors"; +import { getMessages, getMessageChannels, isOldWeb3, isWeb3Enabled, getMessagesError } from "../reducers/selectors"; class CommunicationContainer extends Component { componentDidMount() { @@ -37,9 +37,11 @@ class CommunicationContainer extends Component { this.listenToChannel(channel)} - sendMessage={(channel, message) => this.sendMessage(channel, message)} - channels={this.props.messages} - subscriptions={this.props.messageChannels}/> + sendMessage={(channel, message) => this.sendMessage(channel, message)} + channels={this.props.messages} + subscriptions={this.props.messageChannels} + error={this.props.error} + /> ); } @@ -60,7 +62,8 @@ CommunicationContainer.propTypes = { isWeb3Enabled: PropTypes.bool, messages: PropTypes.object, messageChannels: PropTypes.array, - fetchVersions: PropTypes.func + fetchVersions: PropTypes.func, + error: PropTypes.object }; function mapStateToProps(state) { @@ -68,7 +71,8 @@ function mapStateToProps(state) { messages: getMessages(state), messageChannels: getMessageChannels(state), isOldWeb3: isOldWeb3(state), - isWeb3Enabled: isWeb3Enabled(state) + isWeb3Enabled: isWeb3Enabled(state), + error: getMessagesError(state) }; } diff --git a/packages/cockpit/ui/src/reducers/selectors.js b/packages/cockpit/ui/src/reducers/selectors.js index 5be9cc9c7..be256616c 100644 --- a/packages/cockpit/ui/src/reducers/selectors.js +++ b/packages/cockpit/ui/src/reducers/selectors.js @@ -150,6 +150,12 @@ export function getMessages(state) { return messages; } +export function getMessagesError(state) { + return { + error: state.errorEntities.messages + }; +} + export function getFiddleDeploy(state) { return { data: last(state.entities.fiddleDeploys), diff --git a/packages/cockpit/ui/src/sagas/index.js b/packages/cockpit/ui/src/sagas/index.js index bfda7c82d..7ef30f897 100644 --- a/packages/cockpit/ui/src/sagas/index.js +++ b/packages/cockpit/ui/src/sagas/index.js @@ -571,7 +571,10 @@ export function *listenToMessages(action) { const channel = yield call(createChannel, socket); while (true) { const message = yield take(channel); - yield put(actions.messageListen.success([{channel: action.messageChannels[0], message: message.data, time: message.time}])); + if (message.error) { + return yield put(actions.messageListen.failure(message.error)); + } + yield put(actions.messageListen.success([{ channel: action.messageChannels[0], message: message.data, time: message.time }])); } } diff --git a/packages/core/core/src/config.ts b/packages/core/core/src/config.ts index 3c648fce9..7cafd27ca 100644 --- a/packages/core/core/src/config.ts +++ b/packages/core/core/src/config.ts @@ -567,6 +567,7 @@ export class Config { enabled: true, provider: "whisper", available_providers: ["whisper"], + client: "geth", connection: { host: defaultHost, port: 8547, diff --git a/packages/plugins/whisper-geth/src/index.js b/packages/plugins/whisper-geth/src/index.js index a869f8425..3589258ac 100644 --- a/packages/plugins/whisper-geth/src/index.js +++ b/packages/plugins/whisper-geth/src/index.js @@ -18,7 +18,7 @@ class Whisper { this.webSocketsChannels = {}; this.modulesPath = dappPath(embark.config.embarkConfig.generationDir, constants.dappArtifacts.symlinkDir); - if (!this.communicationConfig.enabled || this.blockchainConfig.client !== constants.blockchain.clients.geth) { + if (!this.communicationConfig.enabled || this.communicationConfig.client !== constants.blockchain.clients.geth) { return; } diff --git a/packages/plugins/whisper-parity/src/api.js b/packages/plugins/whisper-parity/src/api.js index 7c399270c..b0469f9cd 100644 --- a/packages/plugins/whisper-parity/src/api.js +++ b/packages/plugins/whisper-parity/src/api.js @@ -1,7 +1,9 @@ import EmbarkJS from "embarkjs"; import EmbarkJSWhisper from "embarkjs-whisper"; -class API { +export const PARITY_WHISPER_ERROR = "Parity's implementation of Whisper is not compatible with Whisper v6 (and therefore web3.js). Try changing the communication config to use '{client: \"geth\"}' instead."; + +export class Api { constructor(embark) { this.embark = embark; @@ -25,13 +27,8 @@ class API { 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); - }); + (_req, res) => { + res.status(500).send({ error: PARITY_WHISPER_ERROR }); }); } @@ -39,13 +36,8 @@ class API { 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)); - }); + (ws, _req) => { + ws.send(JSON.stringify({ error: PARITY_WHISPER_ERROR })); }); } - } - -module.exports = API; diff --git a/packages/plugins/whisper-parity/src/check.js b/packages/plugins/whisper-parity/src/check.js deleted file mode 100644 index 95939036f..000000000 --- a/packages/plugins/whisper-parity/src/check.js +++ /dev/null @@ -1,65 +0,0 @@ -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 -}; diff --git a/packages/plugins/whisper-parity/src/index.js b/packages/plugins/whisper-parity/src/index.js index 3d2895ae0..82b6420ca 100644 --- a/packages/plugins/whisper-parity/src/index.js +++ b/packages/plugins/whisper-parity/src/index.js @@ -1,8 +1,7 @@ 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"; +const { Api, PARITY_WHISPER_ERROR } = require("./api.js"); class Whisper { constructor(embark, _options) { @@ -16,71 +15,33 @@ class Whisper { this.webSocketsChannels = {}; this.modulesPath = dappPath(embark.config.embarkConfig.generationDir, constants.dappArtifacts.symlinkDir); - if (!this.communicationConfig.enabled || this.blockchainConfig.client !== constants.blockchain.clients.parity) { + if (!this.communicationConfig.enabled || this.communicationConfig.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.logger.warn(PARITY_WHISPER_ERROR); + readyCb(); this.registerServiceCheck(); }); this.events.on("communication:started", () => { - this.api = new API(embark); + 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(); + cb({ name: "Whisper Parity", status: "off" }); + }, 1000 * 60 * 30, "off"); } // esline-disable-next-line complexity diff --git a/site/source/docs/messages_configuration.md b/site/source/docs/messages_configuration.md index 58da74a16..dd09485c9 100644 --- a/site/source/docs/messages_configuration.md +++ b/site/source/docs/messages_configuration.md @@ -28,4 +28,5 @@ Option | Type: `default` | Value `enabled` | boolean: `true/false` | To enable or completely disable communication support `provider` | string: `whisper` | Desired provider to automatically connect to in the dapp. `available_providers` | array: `["whisper"]` | List of communication platforms to be supported in the dapp. This will affect what's available with the EmbarkJS library in the dapp so if you don't need Whisper for example, removing it from this will considerably reduce the file size of the generated JS code. +`client` | string: `geth/parity` | Desired Whisper client for Embark to start. **NOTE:** Parity's implementation of Whisper does not currently adhere to Whisper v6 standards and thus is not supported by `web3.js`.