Implement graceful shutdown
MODIFY
HiddenWallet/HiddenWallet.API/Controllers/WalletController.cs
HiddenWallet/HiddenWallet.API/Controllers/WalletController.cs
@@ -118,10 +118,18 @@ namespace HiddenWallet.API.Controllers
{
try
{
- Global.WalletWrapper.ShutdownAsync().Wait();
+ try
+ {
+ Global.WalletWrapper.EndAsync().Wait();
return new ObjectResult(new SuccessResponse());
}
+ finally
+ {
+ // wait until the call returns
+ Task.Delay(1000).ContinueWith(_ => Environment.Exit(0));
+ }
+ }
catch (Exception ex)
{
return new ObjectResult(new FailureResponse { Message = ex.Message, Details = ex.ToString() });

MODIFY
HiddenWallet/HiddenWallet.API/Program.cs
HiddenWallet/HiddenWallet.API/Program.cs
@@ -7,14 +7,13 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System.Net.Http;
using HiddenWallet.API.Wrappers;
+using System.Runtime.Loader;
namespace HiddenWallet.API
{
public class Program
{
public static void Main(string[] args)
- {
- try
{
Global.WalletWrapper = new WalletWrapper();
@@ -26,10 +25,5 @@ namespace HiddenWallet.API
host.Run();
}
- finally
- {
- Global.WalletWrapper.ShutdownAsync().Wait(); // won't happen if process is killed
- }
- }
}
}

MODIFY
HiddenWallet/HiddenWallet.API/Startup.cs
HiddenWallet/HiddenWallet.API/Startup.cs
@@ -33,6 +33,14 @@ namespace HiddenWallet.API
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
+
+ var applicationLifetime = app.ApplicationServices.GetRequiredService<IApplicationLifetime>();
+ applicationLifetime.ApplicationStopping.Register(OnShutdown);
+ }
+
+ private void OnShutdown()
+ {
+ Global.WalletWrapper.EndAsync().Wait();
}
}
}

MODIFY
HiddenWallet/HiddenWallet.API/Wrappers/WalletWrapper.cs
HiddenWallet/HiddenWallet.API/Wrappers/WalletWrapper.cs
@@ -66,11 +66,11 @@ namespace HiddenWallet.API.Wrappers
DateTimeOffset.ParseExact(creationTime, "yyyy-MM-dd", CultureInfo.InvariantCulture));
}
- public async Task ShutdownAsync()
+ public async Task EndAsync()
{
_cts.Cancel();
await Task.WhenAll(_walletJobTask).ConfigureAwait(false);
- Console.WriteLine("Gracefully shut down...");
+ Console.WriteLine("Graceful shut down...");
}
public StatusResponse GetStatusResponse()

MODIFY
HiddenWallet/HiddenWallet.GUI/HiddenWallet.GUI.njsproj
HiddenWallet/HiddenWallet.GUI/HiddenWallet.GUI.njsproj
<ItemGroup>
<Compile Include="app\js\cleanup.js" />
<Compile Include="app\js\decryption-phase.js" />
+ <Compile Include="app\js\default.js">
+ <SubType>Code</SubType>
+ </Compile>
<Compile Include="app\js\status.js" />
<Compile Include="app\js\wallet-phase.js" />
<Compile Include="main.js" />
+ <Content Include="app\css\default.css">
+ <SubType>Code</SubType>
+ </Content>
<Content Include="app\css\justified-nav.css" />
<Content Include="app\html\decryption-phase-content.html" />
<Content Include="app\html\decryption-phase-menu.html" />
+ <Content Include="app\html\shutdown.html" />
<Content Include="app\html\wallet-phase-tabs.html" />
<Content Include="index.html" />
<Content Include="package.json" />

ADD
HiddenWallet/HiddenWallet.GUI/app/html/shutdown.html
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <link rel="stylesheet" href="../css/default.css" />
+</head>
+<body>
+ <div id="title-bar">
+ <div id="title">Shutting down...</div>
+ </div>
+</body>
+</html>
\ No newline at end of file

MODIFY
HiddenWallet/HiddenWallet.GUI/app/js/decryption-phase.js
HiddenWallet/HiddenWallet.GUI/app/js/decryption-phase.js
var walletExists;
function decryptionPhaseShow(menuItem = "") {
+ document.getElementById("hide-btn").hidden = true;
if (menuItem === "") {
walletExists = httpGetWallet("wallet-exists").Value;
if (walletExists === true) {
+ var alreadyRunning = httpGetWallet("status").WalletState.toUpperCase() !== "NotStarted".toUpperCase();
+ if (alreadyRunning) {
+ walletPhaseShow("alice");
+ }
+ else {
decryptionPhaseShow("decrypt");
}
+ }
else {
decryptionPhaseShow("generate");
}

MODIFY
HiddenWallet/HiddenWallet.GUI/app/js/status.js
HiddenWallet/HiddenWallet.GUI/app/js/status.js
@@ -55,19 +55,19 @@ function periodicStatusUpdate() {
var text = "";
var progressType = "";
if (walletState.toUpperCase() === "NotStarted".toUpperCase()) {
- progressType = "warning";
+ progressType = "info";
text = "NotConnected";
}
if (walletState.toUpperCase() === "SyncingHeaders".toUpperCase()) {
- progressType = "info";
+ progressType = "info progress-bar-striped active";
text = walletState + ", " + connectionText + ", Headers: " + headerHeight;
}
if (walletState.toUpperCase() === "SyncingBlocks".toUpperCase()) {
- progressType = "striped";
+ progressType = "striped active";
text = walletState + ", " + connectionText + ", Headers: " + headerHeight + ", Blocks left: " + blocksLeft;
}
if (walletState.toUpperCase() === "SyncingMemPool".toUpperCase()) {
- progressType = "success"; // this is the default
+ progressType = "success progress-bar-striped active"; // this is the default
text = connectionText + ", Headers: " + headerHeight + ", Blocks left: " + blocksLeft + ", MemPool txs: " + memPoolTransactionCount;
}
if (walletState.toUpperCase() === "Synced".toUpperCase()) {
@@ -75,6 +75,7 @@ function periodicStatusUpdate() {
text = walletState + ", " + connectionText + ", Headers: " + headerHeight + ", Blocks left: " + blocksLeft + ", MemPool txs: " + memPoolTransactionCount;
}
if (connectedNodeCount === 0 && walletState.toUpperCase() !== "NotStarted".toUpperCase()) {
+ progressType = "info progress-bar-striped";
text = "Connecting. . .";
}

MODIFY
HiddenWallet/HiddenWallet.GUI/app/js/wallet-phase.js
HiddenWallet/HiddenWallet.GUI/app/js/wallet-phase.js
function walletPhaseShow(tabItem) {
+ document.getElementById("hide-btn").hidden = false;
+
if (tabItem === "alice") {
document.getElementById("tabs").innerHTML = document.getElementById("wallet-phase-tabs-frame").contentWindow.document.getElementById("alice-active").innerHTML;
}

MODIFY
HiddenWallet/HiddenWallet.GUI/index.html
HiddenWallet/HiddenWallet.GUI/index.html
<html>
<head>
<meta charset="UTF-8">
- <title>HiddenWallet - nopara73</title>
- <!-- Bootstrap core CSS -->
<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
-
<link rel="stylesheet" href="app/css/justified-nav.css">
+ <link rel="stylesheet" href="app/css/default.css" />
</head>
<body onload="decryptionPhaseShow(); periodicStatusUpdate();">
<iframe id="decryption-phase-menu-frame" src="app/html/decryption-phase-menu.html" style="display:none"></iframe>
<iframe id="decryption-phase-content-frame" src="app/html/decryption-phase-content.html" style="display:none"></iframe>
<iframe id="wallet-phase-tabs-frame" src="app/html/wallet-phase-tabs.html" style="display:none"></iframe>
- <div class="container">
+ <div id="title-bar">
+ <div id="title"> </div>
+ <div id="title-bar-btns">
+ <button id="hide-btn" type="button">
+ <span class="glyphicon glyphicon-eye-close"></span>
+ </button>
+ <button id="close-btn" type="button">
+ <span class="glyphicon glyphicon-off"></span>
+ </button>
+ </div>
+ </div>
+ <br />
+ <div id="below-title-bar" class="container">
<div id="tabs"> </div>
<div id="menu"> </div>
<hr />
</div>
<div id="status" style="position:absolute; bottom:1px; width: 100%;"></div>
+ <script src="app/js/default.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script type="text/javascript" src="app/js/decryption-phase.js"></script>
<script type="text/javascript" src="app/js/wallet-phase.js"></script>

MODIFY
HiddenWallet/HiddenWallet.GUI/main.js
HiddenWallet/HiddenWallet.GUI/main.js
@@ -6,7 +6,6 @@ const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
-const packageJson = require('./package.json');
// 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.
@@ -14,8 +13,7 @@ let mainWindow;
function createWindow() {
// Create the browser window.
- var constructedTitle = "HiddenWallet " + packageJson.version + " - " + packageJson.author.name + " (EXPERIMENTAL)";
- mainWindow = new BrowserWindow({ width: 800, height: 600, resizable: false, title: constructedTitle });
+ mainWindow = new BrowserWindow({ width: 800, height: 600, resizable: false, frame: false });
// and load the index.html of the app.
mainWindow.loadURL(url.format({
@@ -58,13 +56,13 @@ app.on('activate', function () {
// code. You can also put them in separate files and require them here.
const os = require('os');
-var apiProcess = null;
+var apiProcess;
function startApi() {
- var proc = require('child_process').spawn;
+ var spawn = require('child_process').spawn;
// run server
var apipath = path.join(__dirname, '..\\HiddenWallet.API\\bin\\dist\\win\\HiddenWallet.API.exe');
- apiProcess = proc(apipath, {
+ apiProcess = spawn(apipath, {
detached: true
});
@@ -77,15 +75,11 @@ function startApi() {
}
// loads module and registers app specific cleanup callback...
-var cleanup = require('./app/js/cleanup').Cleanup(myCleanup);
+const cleanup = require('./app/js/cleanup').Cleanup(myCleanup);
// defines app specific callback...
-
-var request = require('request');
function myCleanup() {
writeLog('exit');
};
-// Prevents the program from closing instantly
-process.stdin.resume();
function writeLog(msg) {
console.log(msg);

MODIFY
HiddenWallet/HiddenWallet.GUI/package.json
HiddenWallet/HiddenWallet.GUI/package.json
"electron-builder": "^17.0.1"
},
"dependencies": {
- "request": "^2.81.0",
"bootstrap": "^3.3.7",
- "electron": "^1.6.7",
- "electron-builder": "^17.0.2"
+ "electron": "^1.6.8",
+ "electron-builder": "^17.1.2"
},
"scripts": {
"start": "electron .",

Implement graceful shutdown