From 4b231d0bc1b8b5702b7864373b7fe4b07fcd8bca Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 25 Oct 2017 18:48:08 +0200 Subject: [PATCH 1/5] add more functionnalities: - start/stop geth/mist to the right ipc endpoint - start a frontend - automine if pending txs --- package.json | 7 ++- src/main.js | 55 +++++++++++++++++++--- src/services/autoMine.js | 37 +++++++++++++++ src/services/startFrontend.js | 13 +++++ src/services/startMistGeth.js | 89 +++++++++++++++++++++++++++++++++++ 5 files changed, 193 insertions(+), 8 deletions(-) create mode 100644 src/services/autoMine.js create mode 100644 src/services/startFrontend.js create mode 100644 src/services/startMistGeth.js diff --git a/package.json b/package.json index 339339cf91..8909888204 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "./src/main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node ./src/main.js" + "start": "node ./src/main.js --dev-path /home/yann/Ethereum/testchains/test2 --mist --geth --frontend /home/yann/Ethereum/DevCon3/frontend --frontend-port 8084 --auto-mine" }, "repository": { "type": "git", @@ -32,5 +32,10 @@ }, "bin": { "remixd": "./src/main.js" + }, + "devDependencies": { + "serve": "^6.3.1", + "stdout": "0.0.3", + "web3": "^1.0.0-beta.24" } } diff --git a/src/main.js b/src/main.js index ff6aba337d..a96fb0b867 100644 --- a/src/main.js +++ b/src/main.js @@ -1,19 +1,60 @@ #!/usr/bin/env node var Router = require('./router') var program = require('commander') +var startmistGeth = require('./services/startMistGeth') +var startFrontend = require('./services/startFrontend') +var fs = require('fs-extra') + program .usage('-S ') .description('Provide a two ways connection between the local computer and Remix IDE') -.option('-S, --shared-folder ', 'Folder to share with Remix IDE') +.option('-s, --shared-folder ', 'Folder to share with Remix IDE') +.option('-m, --mist', 'start mist') +.option('-g, --geth', 'start geth') +.option('-p, --dev-path ', 'Folder used by mist/geth to start the development instance') +.option('-f, --frontend ', 'Folder that should be served by remixd') +.option('-p, --frontend-port ', 'Http port used by the frontend (default 8082)') +.option('-a, --auto-mine', 'mine pending transactions') .parse(process.argv) +console.log('example: --dev-path /home/devchains/chain1 --mist --geth --frontend /home/frontend --frontend-port 8084 --auto-mine') +program.outputHelp() + +var killCallBack = [] + +if (program.devPath) { + if (fs.existsSync(program.devPath)) { + killCallBack.push(startmistGeth(program.devPath, program.mist, program.geth, program.autoMine)) + } else { + console.log('\x1b[31m%s\x1b[0m', '[ERR] can\'t start mist/geth. ' + program.devPath + ' does not exist') + } +} -if (!program.sharedFolder) { - program.outputHelp() - process.exit(1) -} else { +if (program.frontend) { + if (!program.frontendPort) program.frontendPort = 8082 + if (fs.existsSync(program.frontend)) { + killCallBack.push(startFrontend(program.frontend, program.frontendPort)) + } else { + console.log('\x1b[31m%s\x1b[0m', '[ERR] can\'t start frontend. ' + program.frontend + ' does not exist') + } +} + +if (program.sharedFolder) { console.log('\x1b[33m%s\x1b[0m', '[WARN] Any application that runs on your computer can potentially read from and write to all files in the directory.') console.log('\x1b[33m%s\x1b[0m', '[WARN] Symbolinc links are not forwarded to Remix IDE\n') + var router = new Router() + router.start(program.sharedFolder) } -var router = new Router() -router.start(program.sharedFolder) +// kill +function kill () { + for (var k in killCallBack) { + try { + killCallBack[k]() + } catch (e) { + console.log(e) + } + } +} +process.on('SIGINT', kill) // catch ctrl-c +process.on('SIGTERM', kill) // catch kill +process.on('exit', kill) diff --git a/src/services/autoMine.js b/src/services/autoMine.js new file mode 100644 index 0000000000..5ef9375123 --- /dev/null +++ b/src/services/autoMine.js @@ -0,0 +1,37 @@ +module.exports = function (web3) { + console.log('auto mine transactions') + + var methods = [] + methods.push({ + name: 'start', + call: 'miner_start', + inputFormatter: [null], + params: 1 + }) + methods.push({ + name: 'stop', + call: 'miner_stop', + inputFormatter: [], + params: 0 + }) + web3.extend({ + property: 'miner', + methods: methods, + properties: [] + }) + + var timeOutId + web3.eth.subscribe('pendingTransactions', (error, result) => { + if (error) { + console.log(error) + } else { + console.log('start or continue mining') + web3.miner.start() + if (timeOutId) clearTimeout(timeOutId) + timeOutId = setTimeout(() => { + console.log('stop mining') + web3.miner.stop() + }, 30000) + } + }) +} diff --git a/src/services/startFrontend.js b/src/services/startFrontend.js new file mode 100644 index 0000000000..0905faa118 --- /dev/null +++ b/src/services/startFrontend.js @@ -0,0 +1,13 @@ +const serve = require('serve') + +module.exports = function (path, port) { + var server = serve(path, { + port: port + }) + + function kill () { + console.log('stopping frontend') + server.stop() + } + return kill +} diff --git a/src/services/startMistGeth.js b/src/services/startMistGeth.js new file mode 100644 index 0000000000..495d816baa --- /dev/null +++ b/src/services/startMistGeth.js @@ -0,0 +1,89 @@ +var spawn = require('child_process').spawn +var stdout = require('stdout') +var autoMine = require('./autoMine') +var Web3 = require('web3') +var net = require('net') + +var connectTimeout +module.exports = function (dataDir, mist, geth, mine) { + console.log(mist) + console.log(geth) + console.log('opening dev env at ' + dataDir) + // geth --vmdebug --dev --ipcpath /home/yann/Ethereum/testchains/test2/geth.ipc --datadir /home/yann/Ethereum/testchains/test2 + var gethprocess + if (geth) { + var ipcPath = dataDir + '/geth.ipc' + var gethArgs = [ + '--vmdebug', + '--dev', + '--ipcpath', ipcPath, + '--datadir', dataDir + ] + console.log('starting geth ... ' + ipcPath) + gethprocess = run('geth', gethArgs) + + connectTimeout = setInterval(() => { + connectWeb3(ipcPath, (web3) => { + clearInterval(connectTimeout) + if (mine) { + autoMine(web3) + } + }) + }, 1000) + } + + // mist --rpc /home/yann/Ethereum/testchains/test2/geth.ipc + var mistprocess + if (mist) { + const mistArgs = [ + '--rpc', ipcPath + ] + console.log('starting mist ...') + mistprocess = run('mist', mistArgs) + } + + function kill () { + if (connectTimeout) { + clearInterval(connectTimeout) + } + if (mistprocess) { + console.log('stopping mist') + mistprocess.kill() + } + if (gethprocess) { + console.log('stopping geth') + gethprocess.kill() + } + } + + return kill +} + +function connectWeb3 (ipcpath, cb) { + try { + console.log('connect to ' + ipcpath) + var web3 = new Web3(new Web3.providers.IpcProvider(ipcpath, net)) + web3.eth.getBlockNumber(function (error) { + if (error) { + console.log('still trying to connect to node... ' + error) + + } else { + cb(web3) + } + }) + } catch (e) {} +} + +function run (app, args) { + var proc + try { + proc = spawn(app, args) + proc.on('error', (err) => { + console.log('\x1b[31m%s\x1b[0m', '[ERR] can\'t start ' + app + '. seems not installed') + console.log(err) + }) + proc.stdout.pipe(stdout()) + } catch (e) { + } + return proc +} From 1f4ca7b168ac12ab5abe44edac48d9ae3b799ccf Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 25 Oct 2017 18:48:24 +0200 Subject: [PATCH 2/5] standard --- src/services/startMistGeth.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/startMistGeth.js b/src/services/startMistGeth.js index 495d816baa..fbef23e5b2 100644 --- a/src/services/startMistGeth.js +++ b/src/services/startMistGeth.js @@ -66,7 +66,6 @@ function connectWeb3 (ipcpath, cb) { web3.eth.getBlockNumber(function (error) { if (error) { console.log('still trying to connect to node... ' + error) - } else { cb(web3) } From 40ebee6d90e80e753e9a7601d8fa8f4be5f35ebc Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 25 Oct 2017 18:50:58 +0200 Subject: [PATCH 3/5] remove local path --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8909888204..51dccb9e7e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "./src/main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node ./src/main.js --dev-path /home/yann/Ethereum/testchains/test2 --mist --geth --frontend /home/yann/Ethereum/DevCon3/frontend --frontend-port 8084 --auto-mine" + "start": "node ./src/main.js" }, "repository": { "type": "git", From 8c8f8e367023ae2d4bd5c50624141c4088aa4967 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 3 Nov 2017 23:05:58 +0100 Subject: [PATCH 4/5] close listening to 65520 --- src/main.js | 2 +- src/router.js | 8 +++++++- src/websocket.js | 17 ++++++++++++++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main.js b/src/main.js index a96fb0b867..af616146df 100644 --- a/src/main.js +++ b/src/main.js @@ -42,7 +42,7 @@ if (program.sharedFolder) { console.log('\x1b[33m%s\x1b[0m', '[WARN] Any application that runs on your computer can potentially read from and write to all files in the directory.') console.log('\x1b[33m%s\x1b[0m', '[WARN] Symbolinc links are not forwarded to Remix IDE\n') var router = new Router() - router.start(program.sharedFolder) + killCallBack.push(router.start(program.sharedFolder)) } // kill diff --git a/src/router.js b/src/router.js index d8751b79b3..9c9e53731d 100644 --- a/src/router.js +++ b/src/router.js @@ -3,13 +3,19 @@ var Websocket = require('./websocket') class Router { start (sharedFolder) { - this.websocket = new Websocket() + var websocket = new Websocket() + this.websocket = websocket this.websocket.start((message) => { this.call(message.id, message.service, message.fn, message.args) }) servicesList['sharedfolder'].setupNotifications(this.websocket, sharedFolder) servicesList['sharedfolder'].sharedFolder(sharedFolder) console.log('Shared folder : ' + sharedFolder) + return function () { + if (websocket) { + websocket.close() + } + } } call (callid, name, fn, args) { diff --git a/src/websocket.js b/src/websocket.js index aa0aa178d9..a367b243f7 100644 --- a/src/websocket.js +++ b/src/websocket.js @@ -8,18 +8,18 @@ class WebSocket { } start (callback) { - var server = http.createServer(function (request, response) { + this.server = http.createServer(function (request, response) { console.log((new Date()) + ' Received request for ' + request.url) response.writeHead(404) response.end() }) var loopback = '127.0.0.1' - server.listen(65520, loopback, function () { + this.server.listen(65520, loopback, function () { console.log((new Date()) + ' Remixd is listening on ' + loopback + ':65520') }) this.wsServer = new WebSocketServer({ - httpServer: server, + httpServer: this.server, autoAcceptConnections: false }) @@ -53,6 +53,17 @@ class WebSocket { send (data) { this.connection.sendUTF(data) } + + close () { + if (this.connection) { + this.connection.close() + this.connection = null + } + if (this.server) { + this.server.close() + this.server = null + } + } } function originIsAllowed (origin) { From 2bb8af15fe55b3332a94e73bc28b77421c006ecb Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 3 Nov 2017 23:21:10 +0100 Subject: [PATCH 5/5] options to open rpc server --- src/main.js | 4 +++- src/services/startMistGeth.js | 19 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main.js b/src/main.js index af616146df..2f6e248105 100644 --- a/src/main.js +++ b/src/main.js @@ -15,6 +15,8 @@ program .option('-f, --frontend ', 'Folder that should be served by remixd') .option('-p, --frontend-port ', 'Http port used by the frontend (default 8082)') .option('-a, --auto-mine', 'mine pending transactions') +.option('-r, --rpc ', 'start rpc server. Values are CORS domain') +.option('-rp, --rpc-port', 'rpc server port (default 8545)') .parse(process.argv) console.log('example: --dev-path /home/devchains/chain1 --mist --geth --frontend /home/frontend --frontend-port 8084 --auto-mine') program.outputHelp() @@ -23,7 +25,7 @@ var killCallBack = [] if (program.devPath) { if (fs.existsSync(program.devPath)) { - killCallBack.push(startmistGeth(program.devPath, program.mist, program.geth, program.autoMine)) + killCallBack.push(startmistGeth(program.devPath, program.mist, program.geth, program.autoMine, program.rpc, program.rpcPort)) } else { console.log('\x1b[31m%s\x1b[0m', '[ERR] can\'t start mist/geth. ' + program.devPath + ' does not exist') } diff --git a/src/services/startMistGeth.js b/src/services/startMistGeth.js index fbef23e5b2..cfc6d7c6d5 100644 --- a/src/services/startMistGeth.js +++ b/src/services/startMistGeth.js @@ -5,9 +5,7 @@ var Web3 = require('web3') var net = require('net') var connectTimeout -module.exports = function (dataDir, mist, geth, mine) { - console.log(mist) - console.log(geth) +module.exports = function (dataDir, mist, geth, mine, rpc, rpcPort) { console.log('opening dev env at ' + dataDir) // geth --vmdebug --dev --ipcpath /home/yann/Ethereum/testchains/test2/geth.ipc --datadir /home/yann/Ethereum/testchains/test2 var gethprocess @@ -19,7 +17,20 @@ module.exports = function (dataDir, mist, geth, mine) { '--ipcpath', ipcPath, '--datadir', dataDir ] - console.log('starting geth ... ' + ipcPath) + if (rpc) { + gethArgs.push('--rpc') + gethArgs.push('--rpccorsdomain') + gethArgs.push(rpc) + gethArgs.push('--rpcapi') + gethArgs.push('web3,eth,debug,net') + if (!rpcPort) { + rpcPort = 8545 + } + gethArgs.push('--rpcport') + gethArgs.push(rpcPort) + } + console.log(gethArgs) + console.log('starting geth ... ') gethprocess = run('geth', gethArgs) connectTimeout = setInterval(() => {