[Peek]UserSettings load logging fix and refactor (#36111)

* UserSettings refactor to fix logging bug, properly initialise defaults etc.

* Apply lock only to code which changes shared data.
This commit is contained in:
Dave Rayment 2024-11-28 17:36:32 +00:00 коммит произвёл GitHub
Родитель 28304838af
Коммит 438ee39252
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 51 добавлений и 47 удалений

Просмотреть файл

@ -3,10 +3,8 @@
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.IO.Abstractions;
using System.Threading;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
@ -16,71 +14,77 @@ namespace Peek.UI
public class UserSettings : IUserSettings
{
private const string PeekModuleName = "Peek";
private const int MaxNumberOfRetry = 5;
private const int MaxAttempts = 4;
private readonly SettingsUtils _settingsUtils;
private readonly IFileSystemWatcher _watcher;
private readonly Lock _loadingSettingsLock = new();
private readonly Lock _settingsLock = new();
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Defined in helper called in constructor.")]
private readonly IFileSystemWatcher _watcher;
/// <summary>
/// Gets a value indicating whether Peek closes automatically when the window loses focus.
/// </summary>
public bool CloseAfterLosingFocus { get; private set; }
public UserSettings()
{
_settingsUtils = new SettingsUtils();
CloseAfterLosingFocus = false;
LoadSettingsFromJson();
_watcher = Helper.GetFileWatcher(PeekModuleName, "settings.json", () => LoadSettingsFromJson());
_watcher = Helper.GetFileWatcher(PeekModuleName, SettingsUtils.DefaultFileName, LoadSettingsFromJson);
}
private void ApplySettings(PeekSettings settings)
{
lock (_settingsLock)
{
CloseAfterLosingFocus = settings.Properties.CloseAfterLosingFocus.Value;
}
}
private void ApplyDefaultSettings()
{
ApplySettings(new PeekSettings());
}
private void LoadSettingsFromJson()
{
lock (_loadingSettingsLock)
for (int attempt = 1; attempt <= MaxAttempts; attempt++)
{
var retry = true;
var retryCount = 0;
while (retry)
try
{
try
ApplySettings(_settingsUtils.GetSettingsOrDefault<PeekSettings>(PeekModuleName));
return;
}
catch (System.IO.IOException ex)
{
Logger.LogError($"Peek settings load attempt {attempt} failed: {ex.Message}", ex);
if (attempt == MaxAttempts)
{
retryCount++;
if (!_settingsUtils.SettingsExists(PeekModuleName))
{
Logger.LogInfo("Peek settings.json was missing, creating a new one");
var defaultSettings = new PeekSettings();
defaultSettings.Save(_settingsUtils);
}
var settings = _settingsUtils.GetSettingsOrDefault<PeekSettings>(PeekModuleName);
if (settings != null)
{
CloseAfterLosingFocus = settings.Properties.CloseAfterLosingFocus.Value;
}
retry = false;
}
catch (IOException e)
{
if (retryCount > MaxNumberOfRetry)
{
retry = false;
Logger.LogError($"Failed to Deserialize PowerToys settings, Retrying {e.Message}", e);
}
else
{
Thread.Sleep(500);
}
}
catch (Exception ex)
{
retry = false;
Logger.LogError("Failed to read changed settings", ex);
Logger.LogError($"Failed to load Peek settings after {MaxAttempts} attempts. Continuing with default settings.");
ApplyDefaultSettings();
return;
}
// Exponential back-off then retry.
Thread.Sleep(CalculateRetryDelay(attempt));
}
catch (Exception ex)
{
// Anything other than an IO exception is an immediate failure.
Logger.LogError($"Peek settings load failed, continuing with defaults: {ex.Message}", ex);
ApplyDefaultSettings();
return;
}
}
}
private static int CalculateRetryDelay(int attempt)
{
return (int)Math.Pow(2, attempt) * 100;
}
}
}

Просмотреть файл

@ -14,7 +14,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
{
public class SettingsUtils : ISettingsUtils
{
private const string DefaultFileName = "settings.json";
public const string DefaultFileName = "settings.json";
private const string DefaultModuleName = "";
private readonly IFile _file;
private readonly ISettingsPath _settingsPath;