More thread safety to address #492

This commit is contained in:
Michael Bucari-Tovo 2023-02-17 22:57:43 -07:00
parent 25f7c29380
commit dde8024506

View File

@ -7,6 +7,7 @@ using AudibleApi;
using AudibleApi.Common; using AudibleApi.Common;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Threading;
using DataLayer; using DataLayer;
using Dinah.Core; using Dinah.Core;
using Dinah.Core.ErrorHandling; using Dinah.Core.ErrorHandling;
@ -60,12 +61,12 @@ namespace LibationAvalonia.ViewModels
#region Properties exposed to the view #region Properties exposed to the view
public ProcessBookResult Result { get => _result; set { this.RaiseAndSetIfChanged(ref _result, value); this.RaisePropertyChanged(nameof(StatusText)); } } public ProcessBookResult Result { get => _result; set { this.RaiseAndSetIfChanged(ref _result, value); this.RaisePropertyChanged(nameof(StatusText)); } }
public ProcessBookStatus Status { get => _status; set { this.RaiseAndSetIfChanged(ref _status, value); this.RaisePropertyChanged(nameof(BackgroundColor)); this.RaisePropertyChanged(nameof(IsFinished)); this.RaisePropertyChanged(nameof(IsDownloading)); this.RaisePropertyChanged(nameof(Queued)); } } public ProcessBookStatus Status { get => _status; set { this.RaiseAndSetIfChanged(ref _status, value); this.RaisePropertyChanged(nameof(BackgroundColor)); this.RaisePropertyChanged(nameof(IsFinished)); this.RaisePropertyChanged(nameof(IsDownloading)); this.RaisePropertyChanged(nameof(Queued)); } }
public string Narrator { get => _narrator; set { this.RaiseAndSetIfChanged(ref _narrator, value); } } public string Narrator { get => _narrator; set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _narrator, value)); }
public string Author { get => _author; set { this.RaiseAndSetIfChanged(ref _author, value); } } public string Author { get => _author; set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _author, value)); }
public string Title { get => _title; set { this.RaiseAndSetIfChanged(ref _title, value); } } public string Title { get => _title; set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _title, value)); }
public int Progress { get => _progress; private set { this.RaiseAndSetIfChanged(ref _progress, value); } } public int Progress { get => _progress; private set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _progress, value)); }
public string ETA { get => _eta; private set { this.RaiseAndSetIfChanged(ref _eta, value); } } public string ETA { get => _eta; private set => Dispatcher.UIThread.Post(() =>this.RaiseAndSetIfChanged(ref _eta, value)); }
public Bitmap Cover { get => _cover; private set { this.RaiseAndSetIfChanged(ref _cover, value); } } public Bitmap Cover { get => _cover; private set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _cover, value)); }
public bool IsFinished => Status is not ProcessBookStatus.Queued and not ProcessBookStatus.Working; public bool IsFinished => Status is not ProcessBookStatus.Queued and not ProcessBookStatus.Working;
public bool IsDownloading => Status is ProcessBookStatus.Working; public bool IsDownloading => Status is ProcessBookStatus.Working;
public bool Queued => Status is ProcessBookStatus.Queued; public bool Queued => Status is ProcessBookStatus.Queued;
@ -131,6 +132,7 @@ namespace LibationAvalonia.ViewModels
public async Task<ProcessBookResult> ProcessOneAsync() public async Task<ProcessBookResult> ProcessOneAsync()
{ {
string procName = CurrentProcessable.Name; string procName = CurrentProcessable.Name;
ProcessBookResult result = ProcessBookResult.None;
try try
{ {
LinkProcessable(CurrentProcessable); LinkProcessable(CurrentProcessable);
@ -138,32 +140,34 @@ namespace LibationAvalonia.ViewModels
var statusHandler = await CurrentProcessable.ProcessSingleAsync(LibraryBook, validate: true); var statusHandler = await CurrentProcessable.ProcessSingleAsync(LibraryBook, validate: true);
if (statusHandler.IsSuccess) if (statusHandler.IsSuccess)
return Result = ProcessBookResult.Success; result = ProcessBookResult.Success;
else if (statusHandler.Errors.Contains("Cancelled")) else if (statusHandler.Errors.Contains("Cancelled"))
{ {
Logger.Info($"{procName}: Process was cancelled - {LibraryBook.Book}"); Logger.Info($"{procName}: Process was cancelled - {LibraryBook.Book}");
return Result = ProcessBookResult.Cancelled; result = ProcessBookResult.Cancelled;
} }
else if (statusHandler.Errors.Contains("Validation failed")) else if (statusHandler.Errors.Contains("Validation failed"))
{ {
Logger.Info($"{procName}: Validation failed - {LibraryBook.Book}"); Logger.Info($"{procName}: Validation failed - {LibraryBook.Book}");
return Result = ProcessBookResult.ValidationFail; result = ProcessBookResult.ValidationFail;
}
else
{
foreach (var errorMessage in statusHandler.Errors)
Logger.Error($"{procName}: {errorMessage}");
} }
foreach (var errorMessage in statusHandler.Errors)
Logger.Error($"{procName}: {errorMessage}");
} }
catch (ContentLicenseDeniedException ldex) catch (ContentLicenseDeniedException ldex)
{ {
if (ldex.AYCL?.RejectionReason is null or RejectionReason.GenericError) if (ldex.AYCL?.RejectionReason is null or RejectionReason.GenericError)
{ {
Logger.Info($"{procName}: Content license was denied, but this error appears to be caused by a temporary interruption of service. - {LibraryBook.Book}"); Logger.Info($"{procName}: Content license was denied, but this error appears to be caused by a temporary interruption of service. - {LibraryBook.Book}");
return Result = ProcessBookResult.LicenseDeniedPossibleOutage; result = ProcessBookResult.LicenseDeniedPossibleOutage;
} }
else else
{ {
Logger.Info($"{procName}: Content license denied. Check your Audible account to see if you have access to this title. - {LibraryBook.Book}"); Logger.Info($"{procName}: Content license denied. Check your Audible account to see if you have access to this title. - {LibraryBook.Book}");
return Result = ProcessBookResult.LicenseDenied; result = ProcessBookResult.LicenseDenied;
} }
} }
catch (Exception ex) catch (Exception ex)
@ -172,18 +176,21 @@ namespace LibationAvalonia.ViewModels
} }
finally finally
{ {
if (Result == ProcessBookResult.None) if (result == ProcessBookResult.None)
Result = await showRetry(LibraryBook); result = await showRetry(LibraryBook);
Status = Result switch var status = result switch
{ {
ProcessBookResult.Success => ProcessBookStatus.Completed, ProcessBookResult.Success => ProcessBookStatus.Completed,
ProcessBookResult.Cancelled => ProcessBookStatus.Cancelled, ProcessBookResult.Cancelled => ProcessBookStatus.Cancelled,
_ => ProcessBookStatus.Failed, _ => ProcessBookStatus.Failed,
}; };
await Dispatcher.UIThread.InvokeAsync(() => Status = status);
} }
return Result; await Dispatcher.UIThread.InvokeAsync(() => Result = result);
return result;
} }
public async Task CancelAsync() public async Task CancelAsync()
@ -294,9 +301,9 @@ namespace LibationAvalonia.ViewModels
#region Processable event handlers #region Processable event handlers
private void Processable_Begin(object sender, LibraryBook libraryBook) private async void Processable_Begin(object sender, LibraryBook libraryBook)
{ {
Status = ProcessBookStatus.Working; await Dispatcher.UIThread.InvokeAsync(() => Status = ProcessBookStatus.Working);
Logger.Info($"{Environment.NewLine}{((Processable)sender).Name} Step, Begin: {libraryBook.Book}"); Logger.Info($"{Environment.NewLine}{((Processable)sender).Name} Step, Begin: {libraryBook.Book}");