-
Notifications
You must be signed in to change notification settings - Fork 495
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature(@embark/core): IPC adapts when run in Docker Linux on Win #1202
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -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)}` | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is almost exactly what I was thinking! I was thinking:
So, as an example:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting idea to put the original path itself into the directory name. I worry that things might get weird if spaces were in the dirname, though maybe not a problem in practice. |
||||||||||||||
); | ||||||||||||||
} 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(); | ||||||||||||||
|
||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
|
||
const ProcessState = { | ||
Unstarted: 'unstarted', | ||
Starting: 'starting', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"]}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @michaelsbradleyjr just out of curiosity: why are we doing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, that makes sense! |
||
).toString(), | ||
); | ||
} catch (e) { | ||
return false; | ||
} | ||
})(); | ||
|
||
const isDappMountedFromWindowsDockerHost = (() => { | ||
if (!isDocker) { return false; } | ||
jrainville marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just some cosmetics that can be ignored: we can get rid of the parenthesis here in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't have them originally but tslint said it was an error to not use parens around There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When removed, I get something like this:
Maybe it's something we can relax in the linter, and/or we could have another team discussion about adopting use of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wow I'm surprised tslint is complaining about that. Definitely something we should relax in the future. |
||
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, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, just as a precaution, you want to make sure that return hash.update(arg.toString(), 'utf8').digest('hex'); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://nodejs.org/dist/latest-v10.x/docs/api/crypto.html#crypto_hash_update_data_inputencoding Maybe we should just throw if it's not a string?
|
||
} | ||
|
||
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, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big fan of extracting these off of path.
delimiter
andjoin
are concepts used in a lot more ways than just path, so it'll get a bit confusing down below.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the usage context (args and neighboring variables/literals always have something do to w/ paths), I thought it wasn't too confusing, but willing to reconsider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can just do
const {delimiter as pathDelimiter, join as pathJoin} = require('path');
if we want them to be more clear