Add better error messages for license denial #352

This commit is contained in:
Michael Bucari-Tovo 2022-12-15 16:22:25 -07:00
parent a0dd2ccad6
commit 94469cae3d
6 changed files with 98 additions and 71 deletions

View File

@ -1,4 +1,5 @@
using System; using Avalonia.Threading;
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace LibationAvalonia namespace LibationAvalonia
@ -40,19 +41,15 @@ namespace LibationAvalonia
private static async void LogMe_LogError(object sender, (Exception, string) tuple) private static async void LogMe_LogError(object sender, (Exception, string) tuple)
{ {
await Task.Run(() => LogForm?.WriteLine(tuple.Item2 ?? "Automated backup: error")); await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine(tuple.Item2 ?? "Automated backup: error"));
await Task.Run(() => LogForm?.WriteLine("ERROR: " + tuple.Item1.Message)); await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine("ERROR: " + tuple.Item1.Message));
} }
private static async void LogMe_LogErrorString(object sender, string text) private static async void LogMe_LogErrorString(object sender, string text)
{ => await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine(text));
await Task.Run(() => LogForm?.WriteLine(text));
}
private static async void LogMe_LogInfo(object sender, string text) private static async void LogMe_LogInfo(object sender, string text)
{ => await Dispatcher.UIThread.InvokeAsync(() => LogForm?.WriteLine(text));
await Task.Run(() => LogForm?.WriteLine(text));
}
public void Info(string text) => LogInfo?.Invoke(this, text); public void Info(string text) => LogInfo?.Invoke(this, text);
public void Error(string text) => LogErrorString?.Invoke(this, text); public void Error(string text) => LogErrorString?.Invoke(this, text);

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using ApplicationServices; using ApplicationServices;
using AudibleApi;
using AudibleApi.Common;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using DataLayer; using DataLayer;
@ -22,7 +24,9 @@ namespace LibationAvalonia.ViewModels
ValidationFail, ValidationFail,
FailedRetry, FailedRetry,
FailedSkip, FailedSkip,
FailedAbort FailedAbort,
LicenseDenied,
LicenseDeniedPossibleOutage
} }
public enum ProcessBookStatus public enum ProcessBookStatus
@ -80,6 +84,8 @@ namespace LibationAvalonia.ViewModels
ProcessBookResult.FailedRetry => "Error, will retry later", ProcessBookResult.FailedRetry => "Error, will retry later",
ProcessBookResult.FailedSkip => "Error, Skippping", ProcessBookResult.FailedSkip => "Error, Skippping",
ProcessBookResult.FailedAbort => "Error, Abort", ProcessBookResult.FailedAbort => "Error, Abort",
ProcessBookResult.LicenseDenied => "License Denied",
ProcessBookResult.LicenseDeniedPossibleOutage => "Possible Service Interruption",
_ => Status.ToString(), _ => Status.ToString(),
}; };
@ -134,18 +140,31 @@ namespace LibationAvalonia.ViewModels
return Result = ProcessBookResult.Success; return 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; return 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; return Result = ProcessBookResult.ValidationFail;
} }
foreach (var errorMessage in statusHandler.Errors) foreach (var errorMessage in statusHandler.Errors)
Logger.Error($"{procName}: {errorMessage}"); Logger.Error($"{procName}: {errorMessage}");
} }
catch (ContentLicenseDeniedException ldex)
{
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}");
return Result = ProcessBookResult.LicenseDeniedPossibleOutage;
}
else
{
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;
}
}
catch (Exception ex) catch (Exception ex)
{ {
Logger.Error(ex, procName); Logger.Error(ex, procName);

View File

@ -163,6 +163,8 @@ namespace LibationAvalonia.ViewModels
using var counterTimer = new System.Threading.Timer(CounterTimer_Tick, null, 0, 500); using var counterTimer = new System.Threading.Timer(CounterTimer_Tick, null, 0, 500);
bool shownServiceOutageMessage = false;
while (Queue.MoveNext()) while (Queue.MoveNext())
{ {
var nextBook = Queue.Current; var nextBook = Queue.Current;
@ -178,7 +180,19 @@ namespace LibationAvalonia.ViewModels
else if (result == ProcessBookResult.FailedAbort) else if (result == ProcessBookResult.FailedAbort)
Queue.ClearQueue(); Queue.ClearQueue();
else if (result == ProcessBookResult.FailedSkip) else if (result == ProcessBookResult.FailedSkip)
nextBook.LibraryBook.Book.UpdateBookStatus(DataLayer.LiberatedStatus.Error); nextBook.LibraryBook.Book.UpdateBookStatus(LiberatedStatus.Error);
else if (result == ProcessBookResult.LicenseDeniedPossibleOutage && !shownServiceOutageMessage)
{
await MessageBox.Show(@$"
You were denied a content license for {nextBook.LibraryBook.Book.Title}
This error appears to be caused by a temporary interruption of service that sometimes affects Libation's users. This type of error usually resolves itself in 1 to 2 days, and in the meantime you should still be able to access your books through Audible's website or app.
",
"Possible Interruption of Service",
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
shownServiceOutageMessage = true;
}
} }
Serilog.Log.Logger.Information("Completed processing queue"); Serilog.Log.Logger.Information("Completed processing queue");

View File

@ -7,6 +7,8 @@ using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using ApplicationServices; using ApplicationServices;
using AudibleApi.Common;
using AudibleApi;
using DataLayer; using DataLayer;
using Dinah.Core; using Dinah.Core;
using Dinah.Core.ErrorHandling; using Dinah.Core.ErrorHandling;
@ -24,7 +26,9 @@ namespace LibationWinForms.ProcessQueue
ValidationFail, ValidationFail,
FailedRetry, FailedRetry,
FailedSkip, FailedSkip,
FailedAbort FailedAbort,
LicenseDenied,
LicenseDeniedPossibleOutage
} }
public enum ProcessBookStatus public enum ProcessBookStatus
@ -108,18 +112,31 @@ namespace LibationWinForms.ProcessQueue
return Result = ProcessBookResult.Success; return 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; return 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; return Result = ProcessBookResult.ValidationFail;
} }
foreach (var errorMessage in statusHandler.Errors) foreach (var errorMessage in statusHandler.Errors)
Logger.Error($"{procName}: {errorMessage}"); Logger.Error($"{procName}: {errorMessage}");
} }
catch (ContentLicenseDeniedException ldex)
{
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}");
return Result = ProcessBookResult.LicenseDeniedPossibleOutage;
}
else
{
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;
}
}
catch (Exception ex) catch (Exception ex)
{ {
Logger.Error(ex, procName); Logger.Error(ex, procName);

View File

@ -60,68 +60,34 @@ namespace LibationWinForms.ProcessQueue
public void SetResult(ProcessBookResult result) public void SetResult(ProcessBookResult result)
{ {
string statusText = default; (string statusText, ProcessBookStatus status) = result switch
switch (result)
{ {
case ProcessBookResult.Success: ProcessBookResult.Success => ("Finished", ProcessBookStatus.Completed),
statusText = "Finished"; ProcessBookResult.Cancelled => ("Cancelled", ProcessBookStatus.Cancelled),
Status = ProcessBookStatus.Completed; ProcessBookResult.FailedRetry => ("Error, will retry later", ProcessBookStatus.Failed),
break; ProcessBookResult.FailedSkip => ("Error, Skippping", ProcessBookStatus.Failed),
case ProcessBookResult.Cancelled: ProcessBookResult.FailedAbort => ("Error, Abort", ProcessBookStatus.Failed),
statusText = "Cancelled"; ProcessBookResult.ValidationFail => ("Validion fail", ProcessBookStatus.Failed),
Status = ProcessBookStatus.Cancelled; ProcessBookResult.LicenseDenied => ("License Denied", ProcessBookStatus.Failed),
break; ProcessBookResult.LicenseDeniedPossibleOutage => ("Possible Service Interruption", ProcessBookStatus.Failed),
case ProcessBookResult.FailedRetry: _ => ("UNKNOWN", ProcessBookStatus.Failed),
statusText = "Error, will retry later"; };
Status = ProcessBookStatus.Failed;
break;
case ProcessBookResult.FailedSkip:
statusText = "Error, Skippping";
Status = ProcessBookStatus.Failed;
break;
case ProcessBookResult.FailedAbort:
statusText = "Error, Abort";
Status = ProcessBookStatus.Failed;
break;
case ProcessBookResult.ValidationFail:
statusText = "Validion fail";
Status = ProcessBookStatus.Failed;
break;
case ProcessBookResult.None:
statusText = "UNKNOWN";
Status = ProcessBookStatus.Failed;
break;
}
SetStatus(Status, statusText); SetStatus(status, statusText);
} }
public void SetStatus(ProcessBookStatus status, string statusText = null) public void SetStatus(ProcessBookStatus status, string statusText = null)
{ {
Color backColor = default; Status = status;
switch (status)
Color backColor = Status switch
{ {
case ProcessBookStatus.Completed: ProcessBookStatus.Completed => SuccessColor,
backColor = SuccessColor; ProcessBookStatus.Cancelled => CancelledColor,
Status = ProcessBookStatus.Completed; ProcessBookStatus.Queued => QueuedColor,
break; ProcessBookStatus.Working => QueuedColor,
case ProcessBookStatus.Cancelled: _ => FailedColor
backColor = CancelledColor; };
Status = ProcessBookStatus.Cancelled;
break;
case ProcessBookStatus.Queued:
backColor = QueuedColor;
Status = ProcessBookStatus.Queued;
break;
case ProcessBookStatus.Working:
backColor = QueuedColor;
Status = ProcessBookStatus.Working;
break;
case ProcessBookStatus.Failed:
backColor = FailedColor;
Status = ProcessBookStatus.Failed;
break;
}
SuspendLayout(); SuspendLayout();

View File

@ -161,6 +161,8 @@ namespace LibationWinForms.ProcessQueue
StartingTime = DateTime.Now; StartingTime = DateTime.Now;
counterTimer.Start(); counterTimer.Start();
bool shownServiceOutageMessage = false;
while (Queue.MoveNext()) while (Queue.MoveNext())
{ {
var nextBook = Queue.Current; var nextBook = Queue.Current;
@ -177,6 +179,18 @@ namespace LibationWinForms.ProcessQueue
Queue.ClearQueue(); Queue.ClearQueue();
else if (result == ProcessBookResult.FailedSkip) else if (result == ProcessBookResult.FailedSkip)
nextBook.LibraryBook.Book.UpdateBookStatus(DataLayer.LiberatedStatus.Error); nextBook.LibraryBook.Book.UpdateBookStatus(DataLayer.LiberatedStatus.Error);
else if (result == ProcessBookResult.LicenseDeniedPossibleOutage && !shownServiceOutageMessage)
{
MessageBox.Show(@$"
You were denied a content license for {nextBook.LibraryBook.Book.Title}
This error appears to be caused by a temporary interruption of service that sometimes affects Libation's users. This type of error usually resolves itself in 1 to 2 days, and in the meantime you should still be able to access your books through Audible's website or app.
",
"Possible Interruption of Service",
MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
shownServiceOutageMessage = true;
}
} }
Serilog.Log.Logger.Information("Completed processing queue"); Serilog.Log.Logger.Information("Completed processing queue");