Refactor TorMonitor.
MODIFY
WalletWasabi.Gui/Global.cs
WalletWasabi.Gui/Global.cs
@@ -66,7 +66,6 @@ namespace WalletWasabi.Gui
public Node RegTestMempoolServingNode { get; private set; }
public EndPoint? TorSocks5EndPoint { get; private set; }
private TorProcessManager? TorManager { get; set; }
- private TorMonitor? TorMonitor { get; set; }
public CoreNode BitcoinCoreNode { get; private set; }
public HostedServices HostedServices { get; }
@@ -167,8 +166,7 @@ namespace WalletWasabi.Gui
var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
- TorMonitor = new TorMonitor(TorManager);
- TorMonitor.StartMonitor(fallbackRequestTestUri, Config.TorSocks5EndPoint);
+ HostedServices.Register(new TorMonitor(period: TimeSpan.FromSeconds(3), fallbackRequestTestUri, Config.TorSocks5EndPoint, TorManager), nameof(TorMonitor));
}
else
{
@@ -737,15 +735,7 @@ namespace WalletWasabi.Gui
}
}
- Logger.LogDebug($"Step #13: {nameof(TorMonitor)}.", nameof(Global));
-
- if (TorMonitor is { } torMonitor)
- {
- await torMonitor.StopAsync().ConfigureAwait(false);
- Logger.LogInfo($"{nameof(TorMonitor)} is stopped.");
- }
-
- Logger.LogDebug($"Step #14: {nameof(TorManager)}.", nameof(Global));
+ Logger.LogDebug($"Step #12: {nameof(TorManager)}.", nameof(Global));
if (TorManager is { } torManager)
{
@@ -753,14 +743,14 @@ namespace WalletWasabi.Gui
Logger.LogInfo($"{nameof(TorManager)} is stopped.");
}
- Logger.LogDebug($"Step #15: {nameof(Cache)}.", nameof(Global));
+ Logger.LogDebug($"Step #13: {nameof(Cache)}.", nameof(Global));
if (Cache is { } cache)
{
cache.Dispose();
}
- Logger.LogDebug($"Step #16: {nameof(SingleInstanceChecker)}.", nameof(Global));
+ Logger.LogDebug($"Step #14: {nameof(SingleInstanceChecker)}.", nameof(Global));
try
{
@@ -771,7 +761,7 @@ namespace WalletWasabi.Gui
Logger.LogError($"Error during the disposal of {nameof(SingleInstanceChecker)}: {ex}");
}
- Logger.LogDebug($"Step #17: {nameof(AsyncMutex)}.", nameof(Global));
+ Logger.LogDebug($"Step #15: {nameof(AsyncMutex)}.", nameof(Global));
if (AsyncMutex.IsAny)
{

MODIFY
WalletWasabi/Tor/Http/TorHttpClient.cs
WalletWasabi/Tor/Http/TorHttpClient.cs
@@ -46,7 +46,7 @@ namespace WalletWasabi.Tor.Http
public static DateTimeOffset? TorDoesntWorkSince
{
get => TorDoesntWorkSinceBacking;
- private set
+ set
{
if (value != TorDoesntWorkSinceBacking)
{

MODIFY
WalletWasabi/Tor/TorMonitor.cs
WalletWasabi/Tor/TorMonitor.cs
@@ -3,6 +3,7 @@ using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.Bases;
using WalletWasabi.Logging;
using WalletWasabi.Tor.Exceptions;
using WalletWasabi.Tor.Http;
@@ -13,60 +14,29 @@ namespace WalletWasabi.Tor
/// <summary>
/// Monitors Tor process.
/// </summary>
- public class TorMonitor
+ public class TorMonitor : PeriodicRunner
{
- public static readonly TimeSpan TorMisbehaviorCheckPeriod = TimeSpan.FromSeconds(3);
public static readonly TimeSpan CheckIfRunningAfterTorMisbehavedFor = TimeSpan.FromSeconds(7);
- private const long StateNotStarted = 0;
-
- private const long StateRunning = 1;
-
- private const long StateStopping = 2;
-
- private const long StateStopped = 3;
-
- /// <summary>
- /// Value can be any of: <see cref="StateNotStarted"/>, <see cref="StateRunning"/>, <see cref="StateStopping"/> and <see cref="StateStopped"/>.
- /// </summary>
- private long _monitorState;
-
/// <summary>
/// Creates a new instance of the object.
/// </summary>
- public TorMonitor(TorProcessManager torProcessManager)
+ public TorMonitor(TimeSpan period, Uri fallBackTestRequestUri, EndPoint torSocks5EndPoint, TorProcessManager torProcessManager) : base(period)
{
- _monitorState = StateNotStarted;
- MonitorCts = new CancellationTokenSource();
+ FallBackTestRequestUri = fallBackTestRequestUri;
+ TorSocks5EndPoint = torSocks5EndPoint;
TorProcessManager = torProcessManager;
}
public static bool RequestFallbackAddressUsage { get; private set; } = false;
-
- private CancellationTokenSource MonitorCts { get; set; }
-
+ private Uri FallBackTestRequestUri { get; }
+ private EndPoint TorSocks5EndPoint { get; }
private TorProcessManager TorProcessManager { get; }
- public bool IsRunning => Interlocked.Read(ref _monitorState) == StateRunning;
-
- public void StartMonitor(Uri fallBackTestRequestUri, EndPoint torSocks5EndPoint)
- {
- Logger.LogInfo("Starting Tor monitor...");
- if (Interlocked.CompareExchange(ref _monitorState, StateRunning, StateNotStarted) != StateNotStarted)
- {
- return;
- }
-
- Task.Run(async () =>
+ protected override async Task ActionAsync(CancellationToken token)
{
try
{
- while (IsRunning)
- {
- try
- {
- await Task.Delay(TorMisbehaviorCheckPeriod, MonitorCts.Token).ConfigureAwait(false);
-
if (TorHttpClient.TorDoesntWorkSince is { }) // If Tor misbehaves.
{
TimeSpan torMisbehavedFor = DateTimeOffset.UtcNow - TorHttpClient.TorDoesntWorkSince ?? TimeSpan.Zero;
@@ -77,11 +47,11 @@ namespace WalletWasabi.Tor
{
if (torEx.RepField == RepField.HostUnreachable)
{
- Uri baseUri = new Uri($"{fallBackTestRequestUri.Scheme}://{fallBackTestRequestUri.DnsSafeHost}");
- using (var client = new TorHttpClient(baseUri, torSocks5EndPoint))
+ Uri baseUri = new Uri($"{FallBackTestRequestUri.Scheme}://{FallBackTestRequestUri.DnsSafeHost}");
+ using (var client = new TorHttpClient(baseUri, TorSocks5EndPoint))
{
- var message = new HttpRequestMessage(HttpMethod.Get, fallBackTestRequestUri);
- await client.SendAsync(message, MonitorCts.Token).ConfigureAwait(false);
+ var message = new HttpRequestMessage(HttpMethod.Get, FallBackTestRequestUri);
+ await client.SendAsync(message, token).ConfigureAwait(false);
}
// Check if it changed in the meantime...
@@ -95,12 +65,17 @@ namespace WalletWasabi.Tor
else
{
Logger.LogInfo($"Tor did not work properly for {(int)torMisbehavedFor.TotalSeconds} seconds. Maybe it crashed. Attempting to start it...");
- await TorProcessManager.StartAsync(ensureRunning: true).ConfigureAwait(false); // Try starting Tor, if it does not work it'll be another issue.
+ bool started = await TorProcessManager.StartAsync(ensureRunning: true).ConfigureAwait(false); // Try starting Tor, if it does not work it'll be another issue.
+
+ if (started)
+ {
+ TorHttpClient.TorDoesntWorkSince = null;
}
}
}
}
- catch (Exception ex) when (ex is OperationCanceledException || ex is TaskCanceledException || ex is TimeoutException)
+ }
+ catch (Exception ex) when (ex is OperationCanceledException || ex is TimeoutException)
{
Logger.LogTrace(ex);
}
@@ -110,23 +85,4 @@ namespace WalletWasabi.Tor
}
}
}
- finally
- {
- Interlocked.CompareExchange(ref _monitorState, StateStopped, StateStopping); // If IsStopping, make it stopped.
- }
- });
- }
-
- public async Task StopAsync()
- {
- Interlocked.CompareExchange(ref _monitorState, StateStopping, StateRunning); // If running, make it stopping.
-
- MonitorCts?.Cancel();
- while (Interlocked.CompareExchange(ref _monitorState, StateStopped, StateNotStarted) == StateStopping)
- {
- await Task.Delay(50).ConfigureAwait(false);
- }
- MonitorCts?.Dispose();
- }
- }
}

Refactor TorMonitor.