Skip to content

Commit

Permalink
Merge pull request #70 from goodtrailer/failed-provider-scan
Browse files Browse the repository at this point in the history
Core: Address situation where provider scan fails
  • Loading branch information
goodtrailer authored Aug 26, 2023
2 parents 2f59f48 + 12b3395 commit c04810b
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 51 deletions.
40 changes: 15 additions & 25 deletions DailyDesktop.Core/DailyDesktopCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ namespace DailyDesktop.Core
/// module scanning, though <see cref="ProviderStore"/> is fully functional as
/// a standalone class.
/// </summary>
public class DailyDesktopCore : IDisposable
public sealed class DailyDesktopCore : IDisposable
{
private Microsoft.Win32.TaskScheduler.Task? task;
private string taskName;

private readonly ProviderStore store = new ProviderStore();
private readonly ProviderStore store = new();

/// <summary>
/// Read-only interface to the path configuration.
Expand Down Expand Up @@ -62,8 +62,12 @@ public string TaskName
/// <summary>
/// The currently selected provider corresponding to <see cref="TaskConfiguration.Dll"/>.
/// </summary>
public IProvider? CurrentProvider => currentProvider;
private IProvider? currentProvider;
public IProvider? CurrentProvider => Providers.ContainsKey(taskConfig.Dll) ? IProvider.Instantiate(Providers[taskConfig.Dll]) : null;

/// <summary>
/// The collection of currently loaded <see cref="IProvider"/>s.
/// </summary>
public IReadOnlyDictionary<string, Type> Providers => store.Providers;

/// <summary>
/// The state of the desktop wallpaper update task.
Expand All @@ -79,35 +83,24 @@ public string TaskName
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public static async Task<DailyDesktopCore> CreateCoreAsync(PathConfiguration pathConfig, string taskName, bool isAutoCreatingTask, CancellationToken cancellationToken)
{
var core = new DailyDesktopCore(pathConfig, taskName);

core.IsAutoCreatingTask = isAutoCreatingTask;
var core = new DailyDesktopCore(pathConfig, taskName)
{
IsAutoCreatingTask = isAutoCreatingTask
};

core.taskConfig.OnUpdateAsync += core.onTaskConfigUpdateAsync;

if (!await core.taskConfig.TryDeserializeAsync(cancellationToken))
await core.taskConfig.UpdateAsync(cancellationToken);

var providers = await core.GetProvidersAsync(cancellationToken);
if (providers.ContainsKey(core.taskConfig.Dll))
core.currentProvider = IProvider.Instantiate(providers[core.taskConfig.Dll]);

if (core.IsAutoCreatingTask)
core.CreateTask();

return core;
}

/// <summary>
/// Get an asynchronously scanned dictionary of <see cref="IProvider"/> <see cref="Type"/> values and DLL module path keys.
/// Scans for <see cref="IProvider"/>s and populates <see cref="Providers"/>.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <returns>The dictionary of DLL path <see cref="string"/>s to <see cref="IProvider"/> <see cref="Type"/>s.</returns>
public async Task<IReadOnlyDictionary<string, Type>> GetProvidersAsync(CancellationToken cancellationToken)
{
await store.ScanAsync(pathConfig.ProvidersDir, cancellationToken);
return store.Providers;
}
public async Task ScanProvidersAsync(CancellationToken cancellationToken) => await store.ScanAsync(pathConfig.ProvidersDir, cancellationToken);

/// <summary>
/// Creates a <see cref="Microsoft.Win32.TaskScheduler.Task"/> under the name <see cref="TaskName"/>. If
Expand Down Expand Up @@ -190,11 +183,8 @@ private DailyDesktopCore(PathConfiguration pathConfig, string taskName)

private async Task onTaskConfigUpdateAsync(object? sender, EventArgs? args, CancellationToken cancellationToken)
{
var providers = await GetProvidersAsync(cancellationToken);
currentProvider = providers.ContainsKey(taskConfig.Dll) ? IProvider.Instantiate(providers[taskConfig.Dll]) : null;

if (IsAutoCreatingTask)
CreateTask();
await Task.Run(CreateTask, cancellationToken);
}

/// <summary>
Expand Down
7 changes: 5 additions & 2 deletions DailyDesktop.Core/Providers/ProviderStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private Type addImpl(string dllPath, Assembly assembly)
public void Scan(string directory)
{
if (!Directory.Exists(directory))
return;
throw new DirectoryNotFoundException($"{directory} does not exist");

foreach (var path in Directory.GetFiles(directory, PROVIDERS_SEARCH_PATTERN, SearchOption.AllDirectories))
{
Expand All @@ -113,10 +113,13 @@ public void Scan(string directory)
public async Task ScanAsync(string directory, CancellationToken cancellationToken)
{
if (!Directory.Exists(directory))
return;
throw new DirectoryNotFoundException($"{directory} does not exist");

foreach (var path in Directory.GetFiles(directory, PROVIDERS_SEARCH_PATTERN, SearchOption.AllDirectories))
{
if (cancellationToken.IsCancellationRequested)
throw new OperationCanceledException();

try
{
await AddAsync(path, cancellationToken);
Expand Down
66 changes: 42 additions & 24 deletions DailyDesktop.Desktop/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public partial class MainForm : Form
private const string null_text = "null";
private const string fetched_text = "fetched on";

private const string failed_scan_text = "Could not load all providers. (took too long?)";

private readonly DailyDesktopCore core;
private readonly WallpaperConfiguration wallpaperConfig;

Expand Down Expand Up @@ -64,7 +66,7 @@ public static async Task<MainForm> CreateFormAsync()
AssemblyDir = assemblyDir,
ProvidersDir = providersDir,
SerializationDir = serializationDir,
}, taskName, true, AsyncUtils.TimedCancel(2500)));
}, taskName, true, AsyncUtils.TimedCancel()));
}

private MainForm(DailyDesktopCore core)
Expand Down Expand Up @@ -129,40 +131,56 @@ private void MainForm_FormClosing(object? sender, EventArgs e)

private async void providerComboBox_SelectedIndexChanged(object? sender, EventArgs e)
{
if (providerComboBox.SelectedItem is ProviderWrapper provider)
await taskConfig.SetDllAsync(provider.Dll, AsyncUtils.TimedCancel());
if (providerComboBox.SelectedItem is not ProviderWrapper p)
return;

await taskConfig.SetDllAsync(p.Dll, AsyncUtils.TimedCancel());

providerDescriptionLabel.Text = core.CurrentProvider?.Description ?? null_description;
providerSourceLinkLabel.Text = core.CurrentProvider?.SourceUri ?? null_text;
providerSourceLinkLabel.Links[0].Enabled = Uri.TryCreate(providerSourceLinkLabel.Text, UriKind.Absolute, out _);
providerSourceLinkLabel.TabStop = wallpaperAuthorLinkLabel.Links[0].Enabled;
Invoke(() =>
{
var provider = core.CurrentProvider;
providerDescriptionLabel.Text = provider?.Description ?? null_description;
providerSourceLinkLabel.Text = provider?.SourceUri ?? null_text;
providerSourceLinkLabel.Links[0].Enabled = Uri.TryCreate(providerSourceLinkLabel.Text, UriKind.Absolute, out _);
providerSourceLinkLabel.TabStop = wallpaperAuthorLinkLabel.Links[0].Enabled;
});
}

private async Task repopulateProviderComboBox()
{
var providers = await core.GetProvidersAsync(AsyncUtils.TimedCancel());
bool isFullyLoaded = true;

providerComboBox.Items.Clear();
providerComboBox.Items.Add(ProviderWrapper.Null);
try
{
await core.ScanProvidersAsync(AsyncUtils.TimedCancel(3000));
}
catch (OperationCanceledException)
{
isFullyLoaded = false;
}

foreach (var keyVal in providers)
Invoke(() =>
{
try
{
var provider = IProvider.Instantiate(keyVal.Value);
var item = new ProviderWrapper(keyVal.Key, provider);
providerComboBox.Items.Add(item);
}
catch (ProviderException pe)
providerComboBox.Items.Clear();
providerComboBox.Items.Add(isFullyLoaded ? ProviderWrapper.Null : failed_scan_text);

foreach (var keyVal in core.Providers)
{
Console.WriteLine(pe.StackTrace);
try
{
var provider = IProvider.Instantiate(keyVal.Value);
var item = new ProviderWrapper(keyVal.Key, provider);
providerComboBox.Items.Add(item);
}
catch (ProviderException pe)
{
Console.WriteLine(pe.StackTrace);
}
}
}

int index = providerComboBox.FindString(core.CurrentProvider?.DisplayName ?? "");

if (index >= 0)
providerComboBox.SelectedIndex = index;
if (core.CurrentProvider != null)
providerComboBox.SelectedIndex = providerComboBox.FindString(core.CurrentProvider.DisplayName);
});
}

private async void providerComboBox_DropDown(object? sender, EventArgs e) => await repopulateProviderComboBox();
Expand Down

0 comments on commit c04810b

Please sign in to comment.