diff --git a/gui/agama-icon-small.png b/gui/agama-icon-small.png new file mode 100644 index 0000000..739e2e0 Binary files /dev/null and b/gui/agama-icon-small.png differ diff --git a/gui/agama-icon.svg b/gui/agama-icon.svg new file mode 100644 index 0000000..4b9055c --- /dev/null +++ b/gui/agama-icon.svg @@ -0,0 +1,43 @@ + + + + background + + + + Layer 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/index.html b/gui/index.html index 5c6c9af..14a6977 100644 --- a/gui/index.html +++ b/gui/index.html @@ -13,14 +13,22 @@ - +
-
-
Starting Wallet. Please wait...
-
-
+ +
+ +
Choose Agama mode
+ +
-
diff --git a/gui/init.js b/gui/init.js index 265e389..b7f1414 100644 --- a/gui/init.js +++ b/gui/init.js @@ -1,48 +1,52 @@ $(document).ready(function() { const remote = require('electron').remote; var window = remote.getCurrentWindow(); + var appConf = remote.getCurrentWindow().appConfig; $('#pulse').jRoll({ radius: 100, animation: 'pulse' }); - $('#loading_status_text').text('Starting Iguana daemon...'); + inititalWalletLoading(); - GetAppConf(inititalWalletLoading); + $('#loading_status_text').text('Starting Wallet. Please wait...'); - function inititalWalletLoading(appConf) { - if (appConf && !appConf.manualIguanaStart) { - StartIguana(); - } + function inititalWalletLoading() { + // run iguana-less mode with no daemons startup + if (appConf && appConf.iguanaLessMode) { + // do something + } else { // run normal mode with 2 iguana instances started prior loading GUI + if (appConf && !appConf.manualIguanaStart) { + StartIguana(); + } + + var portcheck; - var portcheck; + function startcheck() { + portcheck = setInterval(function(){ + Iguana_activehandle(appConf).then(function(result){ + console.log(result); - function startcheck() { - portcheck = setInterval(function(){ - Iguana_activehandle(appConf).then(function(result){ - console.log(result); + if (result !== 'error') { + stopcheck(); - if (result !== 'error') { - stopcheck(); + if (appConf && appConf.useBasiliskInstance) { + StartIguana_Cache(); + } - if (appConf && appConf.useBasiliskInstance) { - StartIguana_Cache(); + $('#loading_status_text').text('Connecting to Basilisk Network...'); + EDEX_DEXgetinfoAll(appConf.skipBasiliskNetworkCheck, appConf.minNotaries, appConf); } + }) + }, 2000); + } - $('#loading_status_text').text('Connecting to Basilisk Network...'); - EDEX_DEXgetinfoAll(appConf.skipBasiliskNetworkCheck, appConf.minNotaries, appConf); - } - }) - //var check = Iguana_activehandle(); - //console.log(check[0]) - }, 2000); - } + function stopcheck() { + clearInterval(portcheck); + } - function stopcheck() { - clearInterval(portcheck); + startcheck(); } - - startcheck(); } }); \ No newline at end of file diff --git a/gui/loading.css b/gui/loading.css index 74b3067..f25764a 100644 --- a/gui/loading.css +++ b/gui/loading.css @@ -25,4 +25,84 @@ body { left: -100px; margin: 80px 50px; width: 400px !important; +} + +body.agamaMode { + background-color: rgba(33, 33, 33, 0.85); + padding-top: 40px; + color: #fff; +} + +.agama-logo { + padding-bottom: 20px; +} + +#agamaModeStatus { + padding-bottom: 25px; + font-weight: bold; + font-size: 16px; +} + +.btn-primary.focus, +.btn-primary:focus, +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active { + background-color: #ffa726 !important; + border-color: #ffa726 !important; +} + +.btn.active.focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn:active:focus, +.btn:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn { + padding: 6px 15px; + font-size: 14px; + line-height: 1.57142857; + border-radius: 3px; + -webkit-box-shadow: 0 1px 4px 0 rgba(0,0,0,.1); + box-shadow: 0 1px 4px 0 rgba(0,0,0,.1); + -webkit-transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear; + -o-transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear; + transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear; + -webkit-font-smoothing: subpixel-antialiased; + font-weight: bold; + display: inline-block; + padding: 6px 15px; + margin-bottom: 0; + line-height: 1.57142857; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 3px; +} + +.btn-primary { + color: #fff; + background-color: #FF6600; + border-color: #FF6600; +} + +.btn:first-child { + margin-right: 20px; +} + +.btn:last-child { + margin-left: 20px; } \ No newline at end of file diff --git a/gui/loading.js b/gui/loading.js index 8a178bc..445e078 100644 --- a/gui/loading.js +++ b/gui/loading.js @@ -1,3 +1,53 @@ + function closeMainWindow() { + const remote = require('electron').remote; + const window = remote.getCurrentWindow(); + + window.createWindow('open'); + window.hide(); + } + + function normalStart() { + const remote = require('electron').remote; + let appConf = remote.getCurrentWindow().appConfig; + appConf.iguanaLessMode = false; + + // run iguana-less mode with no daemons startup + if (appConf && appConf.iguanaLessMode) { + // do something + } else { // run normal mode with 2 iguana instances started prior loading GUI + if (appConf && !appConf.manualIguanaStart) { + StartIguana(); + } + + var portcheck; + + function startcheck() { + portcheck = setInterval(function() { + Iguana_activehandle(appConf).then(function(result){ + console.log(result); + + if (result !== 'error') { + stopcheck(); + + if (appConf && appConf.useBasiliskInstance) { + StartIguana_Cache(); + } + + $('#loading_status_text').text('Connecting to Basilisk Network...'); + EDEX_DEXgetinfoAll(appConf.skipBasiliskNetworkCheck, appConf.minNotaries, appConf); + } + }) + }, 2000); + } + + function stopcheck() { + clearInterval(portcheck); + } + + startcheck(); + } + } + function IguanaAJAX(url, ajax_data, timeout) { return $.ajax({ data: JSON.stringify(ajax_data), @@ -44,6 +94,8 @@ function StartIguana() { var ajax_data = { 'herd': 'iguana'}; console.log(ajax_data); + $('#agamaModeStatus').text('Starting main iguana instance...'); + $.ajax({ type: 'POST', data: JSON.stringify(ajax_data), @@ -66,6 +118,8 @@ function StartIguana() { } function StartIguana_Cache() { + $('#agamaModeStatus').text('Starting basilisk iguana instance...'); + var ajax_data = { 'mode': 'basilisk', 'coin': 'all' @@ -83,34 +137,6 @@ function StartIguana_Cache() { }); } -function GetAppConf(cb) { // get iguana app conf - var ajax_data = { 'herd': 'iguana' }, - data = false; - - console.log(ajax_data); - $.ajax({ - type: 'GET', - url: 'http://127.0.0.1:17777/shepherd/appconf' - }) - .done(function(_data) { - console.log('== App Conf Data OutPut =='); - console.log(_data); - data = _data; - cb.call(this, data); - }) - .fail(function(xhr, textStatus, error) { - // handle request failures - console.log(xhr.statusText); - if ( xhr.readyState == 0 ) { - } - console.log(textStatus); - console.log(error); - cb.call(this, data); - }); - - return data; -} - function EDEX_DEXgetinfoAll(skip, minNotaries, appConf) { const remote = require('electron').remote; var window = remote.getCurrentWindow(); diff --git a/main.js b/main.js index 22dbbe0..4f45364 100644 --- a/main.js +++ b/main.js @@ -203,6 +203,7 @@ function createLoadingWindow() { }); loadingWindow.createWindow = createWindow; // expose createWindow to front-end scripts + loadingWindow.appConfig = appConfig; // load our index.html (i.e. easyDEX GUI) loadingWindow.loadURL(`http://${appConfig.host}:${appConfig.agamaPort}/gui/`); @@ -233,7 +234,7 @@ function createLoadingWindow() { app.on('ready', createLoadingWindow); function createWindow (status) { - if ( status === 'open') { + if (status === 'open') { require(path.join(__dirname, 'private/mainmenu')); // initialise window @@ -307,10 +308,6 @@ function createWindow (status) { shepherd.dumpCacheBeforeExit(); shepherd.quitKomodod(); - // if komodod is under heavy load it may not respond to cli stop the first time - setInterval(function() { - shepherd.quitKomodod(); - }, 100); pm2.connect(true, function(err) { console.log('connecting to pm2...'); diff --git a/package.json b/package.json index 5d525cb..2dfd09d 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "adm-zip": "^0.4.7", "bluebird": "^3.4.7", "body-parser": "^1.15.2", - "corsproxy": "^1.5.0", "electron": "^1.6.5", "express": "^4.14.0", "fix-path": "^2.1.0", diff --git a/routes/shepherd.js b/routes/shepherd.js index 0dcd488..dd72c6d 100644 --- a/routes/shepherd.js +++ b/routes/shepherd.js @@ -26,6 +26,7 @@ var ps = require('ps-node'), assetChainPorts = require('./ports.js'), shepherd = express.Router(), iguanaInstanceRegistry = {}, + coindInstanceRegistry = {}, syncOnlyIguanaInstanceInfo = {}, syncOnlyInstanceInterval = -1, guiLog = {}, @@ -98,7 +99,8 @@ shepherd.appConfig = { "cli": { "passthru": false, "default": false - } + }, + "iguanaLessMode": false }; shepherd.writeLog = function(data) { @@ -426,17 +428,31 @@ shepherd.post('/coinslist', function(req, res, next) { }); // TODO: check if komodod is running -shepherd.quitKomodod = function(chain) { +shepherd.quitKomodod = function() { + // if komodod is under heavy load it may not respond to cli stop the first time // exit komodod gracefully - console.log('exec ' + komodocliBin + (chain ? ' -ac_name=' + chain : '') + ' stop'); - exec(komodocliBin + (chain ? ' -ac_name=' + chain : '') + ' stop', function(error, stdout, stderr) { - console.log(`stdout: ${stdout}`); - console.log(`stderr: ${stderr}`); + let coindExitInterval = {}; - if (error !== null) { - console.log(`exec error: ${error}`); - } - }); + for (let key in coindInstanceRegistry) { + const chain = key !== 'komodod' ? key : null; + + coindExitInterval[key] = setInterval(function() { + console.log('exec ' + komodocliBin + (chain ? ' -ac_name=' + chain : '') + ' stop'); + exec(komodocliBin + (chain ? ' -ac_name=' + chain : '') + ' stop', function(error, stdout, stderr) { + console.log(`stdout: ${stdout}`); + console.log(`stderr: ${stderr}`); + + if (stdout.indexOf('stopping') > -1 || + stdout.indexOf('EOF reached') > -1) { + clearInterval(coindExitInterval[key]); + } + + if (error !== null) { + console.log(`exec error: ${error}`); + } + }); + }, 100); + } } shepherd.getConf = function(chain) { @@ -642,7 +658,7 @@ shepherd.saveLocalAppConf = function(appSettings) { shepherd.loadLocalConfig = function() { if (fs.existsSync(`${iguanaDir}/config.json`)) { let localAppConfig = fs.readFileSync(`${iguanaDir}/config.json`, 'utf8'); - + console.log('app config set from local file'); shepherd.writeLog('app config set from local file'); @@ -662,7 +678,7 @@ shepherd.loadLocalConfig = function() { if (localAppConfig) { const compareConfigs = compareJSON(shepherd.appConfig, JSON.parse(localAppConfig)); - + if (Object.keys(compareConfigs).length) { const newConfig = Object.assign(JSON.parse(localAppConfig), compareConfigs); @@ -947,15 +963,98 @@ shepherd.post('/forks', function(req, res, next) { pm2.disconnect(); // Disconnect from PM2 if (err) { - throw err; shepherd.writeLog(`iguana fork error: ${err}`); console.log(`iguana fork error: ${err}`); + throw err; } }); }); }); }); +/* + * type: GET + * + */ +shepherd.get('/InstantDEX/allcoins', function(req, res, next) { + // TODO: if only native return obj + // else query main iguana instance and return combined response + // http://localhost:7778/api/InstantDEX/allcoins?userpass=tmpIgRPCUser@1234 + let successObj; + let nativeCoindList = []; + + for (let key in coindInstanceRegistry) { + nativeCoindList.push(key === 'komodod' ? 'KMD' : key); + } + + if (Object.keys(iguanaInstanceRegistry).length) { + // call to iguana + request({ + url: `http://localhost:${shepherd.appConfig.iguanaCorePort}/api/InstantDEX/allcoins?userpass=${req.query.userpass}`, + method: 'GET' + }, function (error, response, body) { + if (response && + response.statusCode && + response.statusCode === 200) { + const _body = JSON.parse(body); + _body.native = nativeCoindList; + console.log(_body); + } else { + console.log('main iguana instance is not ready yet'); + } + + res.send(body); + }); + } else { + successObj = { + 'native': nativeCoindList, + 'basilisk': [], + 'full': [] + }; + + res.end(JSON.stringify(successObj)); + } +}); + +/* + * type: GET + * + */ +shepherd.get('/SuperNET/activehandle', function(req, res, next) { + // TODO: if only native return obj + // else query main iguana instance and return combined response + // http://localhost:7778/api/SuperNET/activehandle?userpass=tmpIgRPCUser@1234 + let successObj; + + if (Object.keys(iguanaInstanceRegistry).length) { + // call to iguana + request({ + url: `http://localhost:${shepherd.appConfig.iguanaCorePort}/api/SuperNET/activehandle?userpass=${req.query.userpass}`, + method: 'GET' + }, function (error, response, body) { + if (response && + response.statusCode && + response.statusCode === 200) { + console.log(body); + } else { + console.log('main iguana instance is not ready yet'); + } + + res.send(body); + }); + } else { + successObj = { + 'pubkey': 'nativeonly', + 'result': 'success', + 'handle': '', + 'status': Object.keys(coindInstanceRegistry).length ? 'unlocked' : 'locked', + 'duration': 2507830 + }; + + res.end(JSON.stringify(successObj)); + } +}); + /* * type: GET * params: pubkey @@ -1332,7 +1431,7 @@ shepherd.readDebugLog = function(fileLocation, lastNLines) { const lines = data.trim().split('\n'); const lastLine = lines.slice(lines.length - lastNLines, lines.length).join('\n'); - + resolve(lastLine); }); } @@ -1415,17 +1514,18 @@ function herder(flock, data) { pm2.disconnect(); // Disconnect from PM2 if (err) { - throw err; shepherd.writeLog(`iguana core port ${shepherd.appConfig.iguanaCorePort}`); console.log(`iguana fork error: ${err}`); + throw err; } }); }); } + // TODO: notify gui that reindex/rescan param is used to reflect on the screen if (flock === 'komodod') { let kmdDebugLogLocation = (data.ac_name !== 'komodod' ? komodoDir + '/' + data.ac_name : komodoDir) + '/debug.log'; - + console.log('komodod flock selected...'); console.log(`selected data: ${data}`); shepherd.writeLog('komodod flock selected...'); @@ -1457,59 +1557,50 @@ function herder(flock, data) { // Status is 'open' if currently in use or 'closed' if available if (status === 'closed') { // start komodod via exec - if (data.ac_name === 'komodod') { - const _customParamDict = { - 'silent': '&', - 'reindex': '-reindex', - 'change': '-pubkey=' - }; - let _customParam = ''; - - if (data.ac_custom_param === 'silent' || - data.ac_custom_param === 'reindex') { - _customParam = ` ${_customParamDict[data.ac_custom_param]}`; - } else if (data.ac_custom_param === 'change' && data.ac_custom_param_value) { - _customParam = ` ${_customParamDict[data.ac_custom_param]}${data.ac_custom_param_value}`; - } - - console.log(`exec ${komododBin} ${data.ac_options.join(' ')}${_customParam}`); - shepherd.writeLog(`exec ${komododBin} ${data.ac_options.join(' ')}${_customParam}`); - - exec(`${komododBin} ${data.ac_options.join(' ')}${_customParam}`, { - maxBuffer: 1024 * 10000 // 10 mb - }, function(error, stdout, stderr) { - // console.log('stdout: ' + stdout); - // console.log('stderr: ' + stderr); - shepherd.writeLog(`stdout: ${stdout}`); - shepherd.writeLog(`stderr: ${stderr}`); + const _customParamDict = { + 'silent': '&', + 'reindex': '-reindex', + 'change': '-pubkey=', + 'datadir': '-datadir=', + 'rescan': '-rescan' + }; + let _customParam = ''; + + if (data.ac_custom_param === 'silent' || + data.ac_custom_param === 'reindex' || + data.ac_custom_param === 'rescan') { + _customParam = ` ${_customParamDict[data.ac_custom_param]}`; + } else if (data.ac_custom_param === 'change' && data.ac_custom_param_value) { + _customParam = ` ${_customParamDict[data.ac_custom_param]}${data.ac_custom_param_value}`; + } - if (error !== null) { - console.log(`exec error: ${error}`) - shepherd.writeLog(`exec error: ${error}`); - } - }); - } else { - pm2.connect(true, function(err) { // start up pm2 god - if (err) { - console.error(err); - process.exit(2); + console.log(`exec ${komododBin} ${data.ac_options.join(' ')}${_customParam}`); + shepherd.writeLog(`exec ${komododBin} ${data.ac_options.join(' ')}${_customParam}`); + + const isChain = data.ac_name.match(/^[A-Z]*$/); + const coindACParam = isChain ? ` -ac_name=${data.ac_name} ` : ''; + console.log('daemon param ' + data.ac_custom_param); + + coindInstanceRegistry[data.ac_name] = true; + exec(`${komododBin} ${coindACParam}${data.ac_options.join(' ')}${_customParam}`, { + maxBuffer: 1024 * 10000 // 10 mb + }, function(error, stdout, stderr) { + shepherd.writeLog(`stdout: ${stdout}`); + shepherd.writeLog(`stderr: ${stderr}`); + + if (error !== null) { + console.log(`exec error: ${error}`); + shepherd.writeLog(`exec error: ${error}`); + + if (error.toString().indexOf('using -reindex') > -1) { + cache.io.emit('service', { + 'komodod': { + 'error': 'run -reindex' + } + }); } - - pm2.start({ - script: komododBin, // path to binary - name: data.ac_name, // REVS, USD, EUR etc. - exec_mode : 'fork', - cwd: komodoDir, - args: data.ac_options - }, function(err, apps) { - shepherd.writeLog(`komodod fork started ${data.ac_name} ${JSON.stringify(data.ac_options)}`); - - pm2.disconnect(); // Disconnect from PM2 - if (err) - throw err; - }); - }); - } + } + }); } else { console.log(`port ${_port} (${data.ac_name}) is already in use`); shepherd.writeLog(`port ${_port} (${data.ac_name}) is already in use`); @@ -1538,7 +1629,7 @@ function herder(flock, data) { pm2.start({ script: zcashdBin, // path to binary name: data.ac_name, // REVS, USD, EUR etc. - exec_mode : 'fork', + exec_mode: 'fork', cwd: zcashDir, args: data.ac_options }, function(err, apps) { @@ -1550,30 +1641,6 @@ function herder(flock, data) { }); }); } - - // deprecated, to be removed - if (flock === 'corsproxy') { - console.log('corsproxy flock selected...'); - console.log(`selected data: ${data}`); - - pm2.connect(true,function(err) { //start up pm2 god - if (err) { - console.error(err); - process.exit(2); - } - - pm2.start({ - script: CorsProxyBin, // path to binary - name: 'CORSPROXY', - exec_mode : 'fork', - cwd: iguanaDir - }, function(err, apps) { - pm2.disconnect(); // Disconnect from PM2 - if (err) - throw err; - }); - }); - } } function slayer(flock) { @@ -1646,14 +1713,14 @@ function setConf(flock) { switch (flock) { case 'komodod': DaemonConfPath = `${komodoDir}/komodo.conf`; - + if (os.platform() === 'win32') { DaemonConfPath = path.normalize(DaemonConfPath); } break; case 'zcashd': DaemonConfPath = `${ZcashDir}/zcash.conf`; - + if (os.platform() === 'win32') { DaemonConfPath = path.normalize(DaemonConfPath); } @@ -1703,11 +1770,11 @@ function setConf(flock) { const RemoveLines = function() { return new Promise(function(resolve, reject) { - const result = 'RemoveLines is done' + const result = 'RemoveLines is done'; fs.readFile(DaemonConfPath, 'utf8', function(err, data) { if (err) { - shepherd.writeLog(`setconf error '${err}`); + shepherd.writeLog(`setconf error ${err}`); return console.log(err); } @@ -1930,7 +1997,7 @@ function formatBytes(bytes, decimals) { return '0 Bytes'; const k = 1000, - dm = decimals + 1 || 3, + dm = (decimals + 1) || 3, sizes = [ 'Bytes', 'KB',