diff --git a/routes/appConfig.js b/routes/appConfig.js index a6420fe..e9cb64d 100644 --- a/routes/appConfig.js +++ b/routes/appConfig.js @@ -15,6 +15,9 @@ const appConfig = { walletUnlockTimeout: 3600, }, cliStopTimeout: 1000, + disableKomododDownModal: false, + failedRPCAttemptsThreshold: 10, + stopNativeDaemonsOnQuit: true, }, schema: { host: { @@ -95,6 +98,19 @@ const appConfig = { cliStopTimeout: { display: true, displayName: 'CLI stop timeout', + info: 'Timeout between consequent CLI stop commands', + type: 'number', + }, + stopNativeDaemonsOnQuit: { + display: true, + displayName: 'Stop native daemons on app quit', + info: 'If set to false agama will run in detached coin daemon mode', + type: 'boolean', + }, + failedRPCAttemptsThreshold: { + display: true, + displayName: 'Failed RPC connect attempts threshold', + info: 'Number of allowed consequent RPC connect failures before the app marks native coin daemon as not running properly', type: 'number', }, }, diff --git a/routes/shepherd/daemonControl.js b/routes/shepherd/daemonControl.js index 29cf545..6565845 100644 --- a/routes/shepherd/daemonControl.js +++ b/routes/shepherd/daemonControl.js @@ -1,3 +1,5 @@ +const spawn = require('child_process').spawn; + module.exports = (shepherd) => { const getConf = (flock, coind) => { let DaemonConfPath = ''; @@ -135,7 +137,8 @@ module.exports = (shepherd) => { // check if komodod instance is already running shepherd.portscanner.checkPortStatus(_port, '127.0.0.1', (error, status) => { // Status is 'open' if currently in use or 'closed' if available - if (status === 'closed') { + if (status === 'closed' || + !shepherd.appConfig.stopNativeDaemonsOnQuit) { // start komodod via exec const _customParamDict = { silent: '&', @@ -169,25 +172,33 @@ module.exports = (shepherd) => { if (!shepherd.kmdMainPassiveMode) { let _arg = `${coindACParam}${data.ac_options.join(' ')}${_customParam}`; _arg = _arg.trim().split(' '); - shepherd.execFile(`${shepherd.komododBin}`, _arg, { - maxBuffer: 1024 * 1000000 // 1000 mb - }, (error, stdout, stderr) => { - shepherd.writeLog(`stdout: ${stdout}`); - shepherd.writeLog(`stderr: ${stderr}`); - if (error !== null) { - shepherd.log(`exec error: ${error}`); - shepherd.writeLog(`exec error: ${error}`); - - if (error.toString().indexOf('using -reindex') > -1) { - shepherd.io.emit('service', { - komodod: { - error: 'run -reindex', - }, - }); + if (!shepherd.appConfig.stopNativeDaemonsOnQuit) { + spawn(shepherd.komododBin, _arg, { + stdio: 'ignore', // piping all stdio to /dev/null + detached: true, + }).unref(); + } else { + shepherd.execFile(`${shepherd.komododBin}`, _arg, { + maxBuffer: 1024 * 1000000 // 1000 mb + }, (error, stdout, stderr) => { + shepherd.writeLog(`stdout: ${stdout}`); + shepherd.writeLog(`stderr: ${stderr}`); + + if (error !== null) { + shepherd.log(`exec error: ${error}`); + shepherd.writeLog(`exec error: ${error}`); + + if (error.toString().indexOf('using -reindex') > -1) { + shepherd.io.emit('service', { + komodod: { + error: 'run -reindex', + }, + }); + } } - } - }); + }); + } } } else { if (shepherd.kmdMainPassiveMode) { @@ -731,7 +742,8 @@ module.exports = (shepherd) => { shepherd.portscanner.checkPortStatus(_port, '127.0.0.1', (error, status) => { // Status is 'open' if currently in use or 'closed' if available - if (status === 'open') { + if (status === 'open' && + shepherd.appConfig.stopNativeDaemonsOnQuit) { if (!skipError) { shepherd.log(`komodod service start error at port ${_port}, reason: port is closed`); shepherd.writeLog(`komodod service start error at port ${_port}, reason: port is closed`); diff --git a/routes/shepherd/dashboardUpdate.js b/routes/shepherd/dashboardUpdate.js index c40d6e4..e89553a 100644 --- a/routes/shepherd/dashboardUpdate.js +++ b/routes/shepherd/dashboardUpdate.js @@ -269,6 +269,7 @@ module.exports = (shepherd) => { 0 ]; } + return new shepherd.Promise((resolve, reject) => { _bitcoinRPC( _coin, diff --git a/routes/shepherd/quitDaemon.js b/routes/shepherd/quitDaemon.js index c0ca981..dd0feb5 100644 --- a/routes/shepherd/quitDaemon.js +++ b/routes/shepherd/quitDaemon.js @@ -6,70 +6,74 @@ module.exports = (shepherd) => { shepherd.lockDownAddCoin = true; for (let key in shepherd.coindInstanceRegistry) { - const chain = key !== 'komodod' ? key : null; - let _coindQuitCmd = shepherd.komodocliBin; + if (shepherd.appConfig.stopNativeDaemonsOnQuit) { + const chain = key !== 'komodod' ? key : null; + let _coindQuitCmd = shepherd.komodocliBin; - // any coind - if (shepherd.nativeCoindList[key.toLowerCase()]) { - _coindQuitCmd = `${shepherd.coindRootDir}/${key.toLowerCase()}/${shepherd.nativeCoindList[key.toLowerCase()].bin.toLowerCase()}-cli`; - } - if (key === 'CHIPS') { - _coindQuitCmd = shepherd.chipscliBin; - } + // any coind + if (shepherd.nativeCoindList[key.toLowerCase()]) { + _coindQuitCmd = `${shepherd.coindRootDir}/${key.toLowerCase()}/${shepherd.nativeCoindList[key.toLowerCase()].bin.toLowerCase()}-cli`; + } + if (key === 'CHIPS') { + _coindQuitCmd = shepherd.chipscliBin; + } - const execCliStop = () => { - let _arg = []; - if (chain && - !shepherd.nativeCoindList[key.toLowerCase()] && key !== 'CHIPS') { - _arg.push(`-ac_name=${chain}`); + const execCliStop = () => { + let _arg = []; + if (chain && + !shepherd.nativeCoindList[key.toLowerCase()] && key !== 'CHIPS') { + _arg.push(`-ac_name=${chain}`); - if (shepherd.appConfig.dataDir.length) { - _arg.push(`-datadir=${shepherd.appConfig.dataDir + (key !== 'komodod' ? '/' + key : '')}`); + if (shepherd.appConfig.dataDir.length) { + _arg.push(`-datadir=${shepherd.appConfig.dataDir + (key !== 'komodod' ? '/' + key : '')}`); + } + } else if (key === 'komodod' && shepherd.appConfig.dataDir.length) { + _arg.push(`-datadir=${shepherd.appConfig.dataDir}`); } - } else if (key === 'komodod' && shepherd.appConfig.dataDir.length) { - _arg.push(`-datadir=${shepherd.appConfig.dataDir}`); - } - _arg.push('stop'); - shepherd.execFile(`${_coindQuitCmd}`, _arg, (error, stdout, stderr) => { - shepherd.log(`stdout: ${stdout}`); - shepherd.log(`stderr: ${stderr}`); + _arg.push('stop'); + shepherd.execFile(`${_coindQuitCmd}`, _arg, (error, stdout, stderr) => { + shepherd.log(`stdout: ${stdout}`); + shepherd.log(`stderr: ${stderr}`); - if (stdout.indexOf('EOF reached') > -1 || - stderr.indexOf('EOF reached') > -1 || - (error && error.toString().indexOf('Command failed') > -1 && !stderr) || // win "special snowflake" case - stdout.indexOf('connect to server: unknown (code -1)') > -1 || - stderr.indexOf('connect to server: unknown (code -1)') > -1) { - delete shepherd.coindInstanceRegistry[key]; - clearInterval(coindExitInterval[key]); - } + if (stdout.indexOf('EOF reached') > -1 || + stderr.indexOf('EOF reached') > -1 || + (error && error.toString().indexOf('Command failed') > -1 && !stderr) || // win "special snowflake" case + stdout.indexOf('connect to server: unknown (code -1)') > -1 || + stderr.indexOf('connect to server: unknown (code -1)') > -1) { + delete shepherd.coindInstanceRegistry[key]; + clearInterval(coindExitInterval[key]); + } - // workaround for AGT-65 - const _port = shepherd.assetChainPorts[key]; - setTimeout(() => { - shepherd.portscanner.checkPortStatus(_port, '127.0.0.1', (error, status) => { - // Status is 'open' if currently in use or 'closed' if available - if (status === 'closed') { - delete shepherd.coindInstanceRegistry[key]; - clearInterval(coindExitInterval[key]); - } - }); - }, 100); + // workaround for AGT-65 + const _port = shepherd.assetChainPorts[key]; + setTimeout(() => { + shepherd.portscanner.checkPortStatus(_port, '127.0.0.1', (error, status) => { + // Status is 'open' if currently in use or 'closed' if available + if (status === 'closed') { + delete shepherd.coindInstanceRegistry[key]; + clearInterval(coindExitInterval[key]); + } + }); + }, 100); - if (error !== null) { - shepherd.log(`exec error: ${error}`); - } + if (error !== null) { + shepherd.log(`exec error: ${error}`); + } - setTimeout(() => { - shepherd.killRogueProcess(key === 'CHIPS' ? 'chips-cli' : 'komodo-cli'); - }, 100); - }); - } + setTimeout(() => { + shepherd.killRogueProcess(key === 'CHIPS' ? 'chips-cli' : 'komodo-cli'); + }, 100); + }); + } - execCliStop(); - coindExitInterval[key] = setInterval(() => { execCliStop(); - }, timeout); + coindExitInterval[key] = setInterval(() => { + execCliStop(); + }, timeout); + } else { + delete shepherd.coindInstanceRegistry[key]; + } } }