diff --git a/main.js b/main.js index 4d34178..ed541d5 100644 --- a/main.js +++ b/main.js @@ -1,68 +1,76 @@ // Modules to control application life and create native browser window const {app, ipcMain, BrowserWindow} = require('electron'); +const singleInstance = require('single-instance'); const path = require('path'); const fs = require('fs'); -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the JavaScript object is garbage collected. -let mainWindow +var locker = new singleInstance('Ether1DesktopWallet'); -function createWindow () { - // Create the browser window. - mainWindow = new BrowserWindow({ - width: 1200, - height: 800, - minWidth: 1100, - minHeight: 700, - backgroundColor: "#000000" - }); +locker.lock().then(function() { + // Keep a global reference of the window object, if you don't, the window will + // be closed automatically when the JavaScript object is garbage collected. + let mainWindow - // and load the index.html of the app. - mainWindow.loadFile('index.html'); - EthoGeth.startGeth(); + function createWindow () { + // Create the browser window. + mainWindow = new BrowserWindow({ + width: 1200, + height: 800, + minWidth: 1100, + minHeight: 700, + backgroundColor: "#000000" + }); - // Open the DevTools. - // mainWindow.webContents.openDevTools() + // and load the index.html of the app. + mainWindow.loadFile('index.html'); + EthoGeth.startGeth(); - // Emitted when the window is closed. - mainWindow.on('closed', function () { - // Dereference the window object, usually you would store windows - // in an array if your app supports multi windows, this is the time - // when you should delete the corresponding element. - mainWindow = null + // Open the DevTools. + // mainWindow.webContents.openDevTools() + + // Emitted when the window is closed. + mainWindow.on('closed', function () { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow = null + }) + } + + // This method will be called when Electron has finished + // initialization and is ready to create browser windows. + // Some APIs can only be used after this event occurs. + app.on('ready', createWindow) + + // Quit when all windows are closed. + app.on('window-all-closed', function () { + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + EthoGeth.stopGeth(); + app.quit(); + } }) -} -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.on('ready', createWindow) + app.on('activate', function () { + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow() + } + }) -// Quit when all windows are closed. -app.on('window-all-closed', function () { - // On OS X it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - EthoGeth.stopGeth(); - app.quit() - } + // In this file you can include the rest of your app's specific main process + // code. You can also put them in separate files and require them here. + // listen for request to get template + ipcMain.on('getTemplateContent', (event, arg) => { + event.returnValue = fs.readFileSync(path.join(app.getAppPath(), "assets/templates/") + arg, 'utf8'); + }); }) - -app.on('activate', function () { - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow() - } +.catch(function(err) { + app.quit(); }) -// In this file you can include the rest of your app's specific main process -// code. You can also put them in separate files and require them here. -// listen for request to get template -ipcMain.on('getTemplateContent', (event, arg) => { - event.returnValue = fs.readFileSync(path.join(app.getAppPath(), "assets/templates/") + arg, 'utf8'); -}); - require('./modules/geth.js'); require('./modules/accounts.js'); require('./modules/database.js'); \ No newline at end of file diff --git a/modules/database.js b/modules/database.js index 1650dac..715e41c 100644 --- a/modules/database.js +++ b/modules/database.js @@ -14,7 +14,7 @@ db.ensureIndex({ fieldName: 'block' }, function (err) { }); ipcMain.on('storeTransaction', (event, arg) => { - db.update({ block: arg.block, fromaddr: arg.fromaddr, toaddr: arg.toaddr }, arg, { upsert: true }, function (err, numReplaced, upsert) { + db.update({ txhash: arg.txhash }, arg, { upsert: true }, function (err, numReplaced, upsert) { // do nothing for now }); }); @@ -29,8 +29,7 @@ ipcMain.on('getTransactions', (event, arg) => { docs[i].timestamp, docs[i].fromaddr, docs[i].toaddr, - docs[i].value, - docs[i].confirmed || 1 + docs[i].value ]); } diff --git a/modules/geth.js b/modules/geth.js index e7ec1ca..372642d 100644 --- a/modules/geth.js +++ b/modules/geth.js @@ -53,8 +53,8 @@ class Geth { this.gethProcess.stdout.on('data', function(data) { EthoGeth._writeLog(data.toString() + '\n'); }); - } catch (e) { - dialog.showErrorBox("Error starting application", e); + } catch (err) { + dialog.showErrorBox("Error starting application", err.message); app.quit(); } } diff --git a/package.json b/package.json index 9b73c28..f02b844 100644 --- a/package.json +++ b/package.json @@ -21,18 +21,18 @@ "win": { "icon": "build/icon.png", "target": "7z", - "artifactName": "Windows-${productName}-${version}.${ext}", + "artifactName": "Windows-${productName}-${version}.${ext}", "extraResources": [ "bin/win/*" ] }, "linux": { "target": "tar.gz", - "artifactName": "Linux-${productName}-${version}.${ext}", + "artifactName": "Linux-${productName}-${version}.${ext}", "extraResources": [ "bin/linux/*" ] - } + } }, "repository": "https://github.com/taeguscromis/Ether1DesktopWallet", "keywords": [ @@ -47,7 +47,8 @@ "app-root-path": "^2.1.0", "electron-storage": "^1.0.7", "handlebars": "^4.0.12", - "nedb": "^1.8.0" + "nedb": "^1.8.0", + "single-instance": "0.0.1" }, "devDependencies": { "electron": "^3.0.12", diff --git a/renderer/send.js b/renderer/send.js index 5c74b4f..cfe7374 100644 --- a/renderer/send.js +++ b/renderer/send.js @@ -145,16 +145,14 @@ $(document).on("render_send", function() { EthoMainGUI.showGeneralError(error); }, function(transaction) { - /* ipcRenderer.send('storeTransaction', { - block: element.block, - fromaddr: element.fromaddr, + block: element.block.toString(), + txhash: element.hash.toLowerCase(), + fromaddr: element.fromaddr.toLowerCase(), timestamp: element.timestamp, - toaddr: element.toaddr, - value: element.value, - confirmed: "1", + toaddr: element.toaddr.toLowerCase(), + value: element.value }); - */ } ); } diff --git a/renderer/syncing.js b/renderer/syncing.js index 6052665..ee83e67 100644 --- a/renderer/syncing.js +++ b/renderer/syncing.js @@ -28,7 +28,7 @@ SyncProgress = new ProgressBar.Line('#syncProgress', }); // set initial value for the progress text -SyncProgress.setText("initializing, please wait..."); +SyncProgress.setText("Waiting for blockchain, please wait..."); var peerCountInterval = setInterval(function() { @@ -39,61 +39,67 @@ var peerCountInterval = setInterval(function() function StartSyncProcess() { var alreadyCatchedUp = false; + var nodeSyncInterval = null; - function keepTheNodeInSync(interval) { - var nodeSyncInterval = setInterval(function() - { - web3Local.eth.isSyncing(function(error, sync) - { - if(!error) { - if(sync == true) { - console.log("start the sync"); - } else if(sync) { - SyncProgress.animate(sync.currentBlock / sync.highestBlock); - SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.currentBlock, sync.highestBlock, Math.round(sync.currentBlock / sync.highestBlock * 100)])); - } else { - web3Local.eth.getBlock("latest", function(error, localBlock) { - if (localBlock.number > 0) { - web3Remote.eth.getBlock("latest", function(error, remoteBlock) { - if (!EthoTransactions.getIsSyncing()) { - SyncProgress.animate(localBlock.number / remoteBlock.number); - SyncProgress.setText(vsprintf('%d/%d (%d%%)', [localBlock.number, remoteBlock.number, Math.round(localBlock.number / remoteBlock.number * 100)])); - } - - if (remoteBlock.number == localBlock.number) { - if (alreadyCatchedUp == false) - { - // clear the repeat interval and render wallets - $(document).trigger("onNewAccountTransaction"); - clearInterval(nodeSyncInterval); - alreadyCatchedUp = true; - - // sync all the transactions to the current block - EthoTransactions.syncTransactionsForAllAddresses(localBlock.number); - $(document).trigger("onSyncInterval"); - - // restart with less intensity - keepTheNodeInSync(10000); - } - } - }); - } - }); - } + var subscription = web3Local.eth.subscribe('syncing', function(error, sync){ + if (!error) { + if (!sync) { + if (nodeSyncInterval) { + clearInterval(nodeSyncInterval); } - }); - }, interval); - } - // initial fast syncing - keepTheNodeInSync(2000); + nodeSyncInterval = setInterval(function() + { + web3Local.eth.getBlock("latest", function(error, localBlock) { + if (localBlock.number > 0) { + if (!EthoTransactions.getIsSyncing()) { + SyncProgress.animate(1); + SyncProgress.setText(vsprintf('%d/%d (100%%)', [localBlock.number, localBlock.number])); + } + + if (alreadyCatchedUp == false) + { + // clear the repeat interval and render wallets + $(document).trigger("onNewAccountTransaction"); + alreadyCatchedUp = true; + + // sync all the transactions to the current block + EthoTransactions.syncTransactionsForAllAddresses(localBlock.number); + $(document).trigger("onSyncInterval"); + } + } + }); + }, 10000); + } + } + }).on("data", function(sync){ + if ((sync) && (sync.HighestBlock > 0)) { + SyncProgress.animate(sync.CurrentBlock / sync.HighestBlock); + SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.CurrentBlock, sync.HighestBlock, Math.round(sync.CurrentBlock / sync.HighestBlock * 100)])); + } + }).on("changed", function(isSyncing){ + if(isSyncing) { + nodeSyncInterval = setInterval(function() + { + web3Local.eth.isSyncing(function(error, sync){ + if ((!error) && (sync)) { + SyncProgress.animate(sync.currentBlock / sync.highestBlock); + SyncProgress.setText(vsprintf('%d/%d (%d%%)', [sync.currentBlock, sync.highestBlock, Math.round(sync.currentBlock / sync.highestBlock * 100)])); + } + }); + }, 2000); + } else { + if (nodeSyncInterval) { + clearInterval(nodeSyncInterval); + } + } + }); } var InitWeb3 = setInterval(function() { try { web3Local = new Web3(new Web3.providers.WebsocketProvider('ws://localhost:8546')); - web3Remote = new Web3(new Web3.providers.HttpProvider("https://rpc.ether1.org")); web3Local.eth.net.isListening(function(error, success) { if (!error) { diff --git a/renderer/transactions.js b/renderer/transactions.js index 342a2d8..4cb36ec 100644 --- a/renderer/transactions.js +++ b/renderer/transactions.js @@ -36,13 +36,12 @@ class Transactions { $.getJSON("https://richlist.ether1.org/transactions_list.php" + params, function( result ) { result.data.forEach(element => { ipcRenderer.send('storeTransaction', { - block: element.block, - txhash: element.hash, - fromaddr: element.fromaddr, + block: element.block.toString(), + txhash: element.txhash.toLowerCase(), + fromaddr: element.fromaddr.toLowerCase(), timestamp: element.timestamp, - toaddr: element.toaddr, - value: element.value, - confirmed: "1" + toaddr: element.toaddr.toLowerCase(), + value: element.value }); }); @@ -149,11 +148,12 @@ class Transactions { }, { "targets": 6, + "defaultContent": "", "render": function ( data, type, row ) { - if (data == 0) { - return ''; - } else if (data == 1) { + if (row[1]) { return ''; + } else if (data == 1) { + return ''; } } } @@ -196,11 +196,11 @@ $(document).on("onSyncInterval", function() { if ((EthoWallets.getAddressExists(element.from)) || (EthoWallets.getAddressExists(element.to))) { var Transaction = { block: element.blockNumber.toString(), + txhash: element.hash.toLowerCase(), fromaddr: element.from.toLowerCase(), timestamp: moment().format('YYYY-MM-DD HH:mm:ss'), toaddr: element.to.toLowerCase(), - value: Number(element.value).toExponential(5).toString().replace('+',''), - confirmed: "0", + value: Number(element.value).toExponential(5).toString().replace('+','') } // store transaction and notify about new transactions