Create SingleInstanceChecker
MODIFY
WalletWasabi.Gui/Global.cs
WalletWasabi.Gui/Global.cs
@@ -77,8 +77,6 @@ namespace WalletWasabi.Gui
public static JsonRpcServer RpcServer { get; private set; }
- private IDisposable SingleApplicationLockHolder { get; set; }
-
public Global()
{
using (BenchmarkLogger.Measure())
@@ -112,6 +110,8 @@ namespace WalletWasabi.Gui
private CancellationTokenSource StoppingCts { get; }
+ private SingleInstanceChecker SingleInstanceChecker { get; } = new SingleInstanceChecker();
+
public async Task InitializeNoWalletAsync()
{
InitializationStarted = true;
@@ -121,7 +121,7 @@ namespace WalletWasabi.Gui
try
{
- await EnsureSingleInstanceAsync().ConfigureAwait(false);
+ await SingleInstanceChecker.EnsureSingleInstanceAsync().ConfigureAwait(false);
Cache = new MemoryCache(new MemoryCacheOptions
{
@@ -621,22 +621,6 @@ namespace WalletWasabi.Gui
Logger.LogInfo($"Transaction Notification ({notificationType}): {title} - {message} - {e.Transaction.GetHash()}");
}
- private async Task EnsureSingleInstanceAsync()
- {
- using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
-
- // The disposal of this mutex handled by AsyncMutex.WaitForAllMutexToCloseAsync().
- var mutex = new AsyncMutex("WalletWasabiSingleInstance");
- try
- {
- SingleApplicationLockHolder = await mutex.LockAsync(cts.Token).ConfigureAwait(false);
- }
- catch (IOException)
- {
- throw new InvalidOperationException("Wasabi is already running!");
- }
- }
-
/// <summary>
/// 0: nobody called
/// 1: somebody called
@@ -794,11 +778,11 @@ namespace WalletWasabi.Gui
try
{
- SingleApplicationLockHolder?.Dispose();
+ SingleInstanceChecker.Dispose();
}
catch (Exception ex)
{
- Logger.LogError($"Error during the disposal of {nameof(SingleApplicationLockHolder)}: {ex}");
+ Logger.LogError($"Error during the disposal of {nameof(SingleInstanceChecker)}: {ex}");
}
if (AsyncMutex.IsAny)

MODIFY
WalletWasabi.Tests/UnitTests/Clients/WasabiClientTests.cs
WalletWasabi.Tests/UnitTests/Clients/WasabiClientTests.cs
@@ -7,6 +7,7 @@ using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.Models;
+using WalletWasabi.Services;
using WalletWasabi.WebClients.Wasabi;
using Xunit;
@@ -116,21 +117,15 @@ namespace WalletWasabi.Tests.UnitTests.Clients
[Fact]
public async Task SingleInstanceTestsAsync()
{
- Gui.Global global = new Gui.Global();
- await global.InitializeNoWalletAsync();
- await global.DisposeAsync();
-
- try
+ using (SingleInstanceChecker sic = new SingleInstanceChecker())
{
- global = new Gui.Global();
-
- await global.InitializeNoWalletAsync();
-
- await Assert.ThrowsAsync<FormatException>(() => global.InitializeNoWalletAsync());
+ await sic.EnsureSingleInstanceAsync().ConfigureAwait(false);
}
- finally
+
+ using (SingleInstanceChecker sic = new SingleInstanceChecker())
{
- await global?.DisposeAsync();
+ await sic.EnsureSingleInstanceAsync().ConfigureAwait(false);
+ await Assert.ThrowsAsync<InvalidOperationException>(async () => await sic.EnsureSingleInstanceAsync().ConfigureAwait(false));
}
}
}

ADD
WalletWasabi/Services/SingleInstanceChecker.cs
+using Nito.AsyncEx;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace WalletWasabi.Services
+{
+ public class SingleInstanceChecker : IDisposable
+ {
+ private const string MutexString = "WalletWasabiSingleInstance";
+ private bool _disposedValue;
+
+ private IDisposable SingleApplicationLockHolder { get; set; }
+
+ public async Task EnsureSingleInstanceAsync()
+ {
+ using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.Zero);
+
+ // The disposal of this mutex handled by AsyncMutex.WaitForAllMutexToCloseAsync().
+ var mutex = new AsyncMutex(MutexString);
+ try
+ {
+ SingleApplicationLockHolder = await mutex.LockAsync(cts.Token).ConfigureAwait(false);
+ }
+ catch (IOException)
+ {
+ throw new InvalidOperationException("Wasabi is already running!");
+ }
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ SingleApplicationLockHolder?.Dispose();
+ }
+ _disposedValue = true;
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+ }
+}

Create SingleInstanceChecker