diff --git a/src/lib/core/env.js b/src/lib/core/env.js index 9d59850eb2..6e1bb47586 100644 --- a/src/lib/core/env.js +++ b/src/lib/core/env.js @@ -1,8 +1,7 @@ /* global __dirname module process require */ const {execSync} = require('child_process'); -const {delimiter} = require('path'); -const {joinPath} = require('../utils/utils.js'); +const {delimiter, join} = require('path'); function anchoredValue(anchor, value) { if (!arguments.length) { @@ -39,11 +38,11 @@ const DEFAULT_CMD_HISTORY_SIZE = 20; anchoredValue(CMD_HISTORY_SIZE, DEFAULT_CMD_HISTORY_SIZE); const DIAGRAM_PATH = 'DIAGRAM_PATH'; -const DEFAULT_DIAGRAM_PATH = joinPath(anchoredValue(DAPP_PATH), 'diagram.svg'); +const DEFAULT_DIAGRAM_PATH = join(anchoredValue(DAPP_PATH), 'diagram.svg'); anchoredValue(DIAGRAM_PATH, DEFAULT_DIAGRAM_PATH); const EMBARK_PATH = 'EMBARK_PATH'; -const DEFAULT_EMBARK_PATH = joinPath(__dirname, '../../..'); +const DEFAULT_EMBARK_PATH = join(__dirname, '../../..'); anchoredValue(EMBARK_PATH, DEFAULT_EMBARK_PATH); const PKG_PATH = 'PKG_PATH'; @@ -52,7 +51,7 @@ anchoredValue(PKG_PATH, DEFAULT_PKG_PATH); let YARN_GLOBAL_PATH; try { - YARN_GLOBAL_PATH = joinPath( + YARN_GLOBAL_PATH = join( execSync('yarn global dir', {stdio: ['pipe', 'pipe', 'ignore']}) .toString() .trim(), @@ -65,7 +64,7 @@ try { const NODE_PATH = 'NODE_PATH'; // NOTE: setting NODE_PATH at runtime won't effect lookup behavior in the // current process, but will take effect in child processes -process.env[NODE_PATH] = joinPath(anchoredValue(EMBARK_PATH), 'node_modules') + +process.env[NODE_PATH] = join(anchoredValue(EMBARK_PATH), 'node_modules') + (YARN_GLOBAL_PATH ? delimiter : '') + (YARN_GLOBAL_PATH || '') + (process.env[NODE_PATH] ? delimiter : '') + diff --git a/src/lib/core/ipc.js b/src/lib/core/ipc.js index 8b073935ab..8a9aac451f 100644 --- a/src/lib/core/ipc.js +++ b/src/lib/core/ipc.js @@ -1,17 +1,36 @@ const fs = require('./fs.js'); const ipc = require('node-ipc'); +const {isDappMountedFromWindowsDockerHost} = require('../utils/host'); +const os = require('os'); const {parse, stringify} = require('flatted/cjs'); +const utils = require('../utils/utils.js'); class IPC { - constructor(options) { this.logger = options.logger; - this.socketPath = options.socketPath || fs.dappPath(".embark/embark.ipc"); + this.socketPath = options.socketPath || IPC.ipcPath('embark.ipc'); this.ipcRole = options.ipcRole; ipc.config.silent = true; this.connected = false; } + static ipcPath(basename, usePipePathOnWindows = false) { + if (!(basename && typeof basename === 'string')) { + throw new TypeError('first argument must be a non-empty string'); + } + let ipcDir; + if (process.platform === 'win32' && usePipePathOnWindows) { + return `\\\\.\\pipe\\${basename}`; + } else if (isDappMountedFromWindowsDockerHost) { + ipcDir = utils.joinPath( + os.tmpdir(), `embark-${utils.sha512(fs.dappPath()).slice(0, 8)}` + ); + } else { + ipcDir = fs.dappPath('.embark'); + } + return utils.joinPath(ipcDir, basename); + } + connect(done) { const self = this; function connecting(_socket) { @@ -39,7 +58,7 @@ class IPC { } serve() { - fs.mkdirpSync(fs.dappPath(".embark")); + fs.mkdirpSync(utils.dirname(this.socketPath)); ipc.serve(this.socketPath, () => {}); ipc.server.start(); diff --git a/src/lib/core/processes/processManager.js b/src/lib/core/processes/processManager.js index 4922fa7165..4f314598d3 100644 --- a/src/lib/core/processes/processManager.js +++ b/src/lib/core/processes/processManager.js @@ -1,4 +1,3 @@ - const ProcessState = { Unstarted: 'unstarted', Starting: 'starting', diff --git a/src/lib/modules/blockchain_process/gethClient.js b/src/lib/modules/blockchain_process/gethClient.js index 6e276e64bd..40fe9175f9 100644 --- a/src/lib/modules/blockchain_process/gethClient.js +++ b/src/lib/modules/blockchain_process/gethClient.js @@ -1,5 +1,6 @@ const async = require('async'); const GethMiner = require('./miner'); +const IPC = require('../../core/ipc'); const semver = require('semver'); const constants = require('../../constants'); @@ -50,7 +51,7 @@ class GethClient { needKeepAlive() { // TODO: check version also (geth version < 1.8.15) if (this.isDev) { - // Trigger regular txs due to a bug in geth (< 1.8.15) and stuck transactions in --dev mode. + // Trigger regular txs due to a bug in geth (< 1.8.15) and stuck transactions in --dev mode. return true; } return false; @@ -78,6 +79,8 @@ class GethClient { cmd.push("--verbosity=" + config.verbosity); } + cmd.push(`--ipcpath=${IPC.ipcPath('geth.ipc', true)}`); + return cmd; } diff --git a/src/lib/modules/blockchain_process/miner.js b/src/lib/modules/blockchain_process/miner.js index 79f132b83c..559a5e9e23 100644 --- a/src/lib/modules/blockchain_process/miner.js +++ b/src/lib/modules/blockchain_process/miner.js @@ -1,4 +1,5 @@ const async = require('async'); +const IPC = require('../../core/ipc'); const NetcatClient = require('netcat/client'); //Constants @@ -43,14 +44,7 @@ class GethMiner { } } - const isWin = process.platform === "win32"; - - let ipcPath; - if (isWin) { - ipcPath = '\\\\.\\pipe\\geth.ipc'; - } else { - ipcPath = this.datadir + '/geth.ipc'; - } + const ipcPath = IPC.ipcPath('geth.ipc', true); this.client = new NetcatClient(); this.client.unixSocket(ipcPath) diff --git a/src/lib/utils/host.ts b/src/lib/utils/host.ts index 3e1a1c3795..89b6e2fd1d 100644 --- a/src/lib/utils/host.ts +++ b/src/lib/utils/host.ts @@ -1,30 +1,59 @@ -const isDocker = (() => { - let isDockerProcess; +const {execSync} = require("child_process"); +const {anchoredValue, DAPP_PATH} = require("../core/env"); +const {hostname} = require("os"); + +const dappPath = anchoredValue(DAPP_PATH); - const hostname = require("os").hostname(); - const pattern = new RegExp( - "[0-9]+\:[a-z_-]+\:\/docker\/" + hostname + "[0-9a-z]+", "i", - ); +function subdir(pdir_, dir_) { + let pdir = path.resolve(path.normalize(pdir_)) + (path.sep || "/"); + const dir = path.resolve(pdir, path.normalize(dir_)); + if (pdir === "//") { pdir = "/"; } + if (pdir === dir) { return false; } + return dir.slice(0, pdir.length) === pdir; +} + +const isDocker = (() => { + // assumption: an Embark container is always a Linux Docker container, though + // the Docker host may be Linux, macOS, or Windows + if (process.platform !== "linux") { return false; } + try { + return ( + new RegExp(`[0-9]+\:[a-z_-]+\:\/docker\/${hostname()}[0-9a-z]+`, "i") + ).test( + execSync( + "cat /proc/self/cgroup", + {stdio: ["ignore", "pipe", "ignore"]}, + ).toString(), + ); + } catch (e) { + return false; + } +})(); +const isDappMountedFromWindowsDockerHost = (() => { + if (!isDocker) { return false; } try { - isDockerProcess = require("child_process") - .execSync( - "cat /proc/self/cgroup", + return execSync( + "mount", {stdio: ["ignore", "pipe", "ignore"]}, ) - .toString().match(pattern) !== null; + .toString() + .split("\n") + .filter((line) => /nounix/.test(line)) + .some((line) => { + const mount = line.match(/on (\/.*) type/)[1]; + return mount === dappPath || subdir(mount, dappPath); + }); } catch (e) { - isDockerProcess = false; + return false; } - - return isDockerProcess; })(); const defaultHost = isDocker ? "0.0.0.0" : "localhost"; -// when we"re runing in Docker, we can expect (generally, in a development +// when we're runing in Docker, we can expect (generally, in a development // scenario) that the user would like to connect to the service in the -// container via the **host"s** loopback address, so this helper can be used to +// container via the **host's** loopback address, so this helper can be used to // swap 0.0.0.0 for localhost in code/messages that pertain to client-side function canonicalHost(host: string): string { return isDocker && host === "0.0.0.0" ? "localhost" : host; @@ -41,5 +70,6 @@ export { defaultCorsHost, defaultHost, dockerHostSwap, + isDappMountedFromWindowsDockerHost, isDocker, }; diff --git a/src/lib/utils/utils.js b/src/lib/utils/utils.js index c747377b2a..dbc680be37 100644 --- a/src/lib/utils/utils.js +++ b/src/lib/utils/utils.js @@ -390,6 +390,12 @@ function sha3(arg) { return Web3.utils.sha3(arg); } +function sha512(arg) { + const crypto = require('crypto'); + const hash = crypto.createHash('sha512'); + return hash.update(arg, 'utf8').digest('hex'); +} + function soliditySha3(arg) { const Web3 = require('web3'); return Web3.utils.soliditySha3(arg); @@ -640,6 +646,7 @@ module.exports = { getExternalContractUrl, toChecksumAddress, sha3, + sha512, soliditySha3, normalizeInput, buildUrl,