diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 0b5f181..8003227 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -108,7 +108,7 @@ public class DiscordClient if (botResponse.StatusCode != HttpStatusCode.Unauthorized) return TokenKind.Bot; - throw DiscordChatExporterException.Unauthorized(); + throw new DiscordChatExporterException("Authentication token is invalid.", true); } private async ValueTask GetResponseAsync( @@ -129,10 +129,26 @@ public class DiscordClient { throw response.StatusCode switch { - HttpStatusCode.Unauthorized => DiscordChatExporterException.Unauthorized(), - HttpStatusCode.Forbidden => DiscordChatExporterException.Forbidden(), - HttpStatusCode.NotFound => DiscordChatExporterException.NotFound(url), - _ => DiscordChatExporterException.FailedHttpRequest(response) + HttpStatusCode.Unauthorized => throw new DiscordChatExporterException( + "Authentication token is invalid.", + true + ), + + HttpStatusCode.Forbidden => throw new DiscordChatExporterException( + $"Request to '{url}' failed: forbidden." + ), + + HttpStatusCode.NotFound => throw new DiscordChatExporterException( + $"Request to '{url}' failed: not found." + ), + + _ => throw new DiscordChatExporterException( + $""" + Request to '{url}' failed: {response.StatusCode.ToString().ToSpaceSeparatedWords().ToLowerInvariant()}. + Response content: {await response.Content.ReadAsStringAsync(cancellationToken)} + """, + true + ) }; } diff --git a/DiscordChatExporter.Core/Exceptions/DiscordChatExporterException.cs b/DiscordChatExporter.Core/Exceptions/DiscordChatExporterException.cs index b0ce135..53a08a6 100644 --- a/DiscordChatExporter.Core/Exceptions/DiscordChatExporterException.cs +++ b/DiscordChatExporter.Core/Exceptions/DiscordChatExporterException.cs @@ -1,9 +1,8 @@ using System; -using System.Net.Http; namespace DiscordChatExporter.Core.Exceptions; -public partial class DiscordChatExporterException : Exception +public class DiscordChatExporterException : Exception { public bool IsFatal { get; } @@ -12,33 +11,4 @@ public partial class DiscordChatExporterException : Exception { IsFatal = isFatal; } -} - -public partial class DiscordChatExporterException -{ - internal static DiscordChatExporterException FailedHttpRequest(HttpResponseMessage response) - { - var message = $@" -Failed to perform an HTTP request. - -[Request] -{response.RequestMessage} - -[Response] -{response}"; - - return new DiscordChatExporterException(message.Trim(), true); - } - - internal static DiscordChatExporterException Unauthorized() => - new("Authentication token is invalid.", true); - - internal static DiscordChatExporterException Forbidden() => - new("Access is forbidden."); - - internal static DiscordChatExporterException NotFound(string resourceId) => - new($"Requested resource ({resourceId}) does not exist."); - - internal static DiscordChatExporterException ChannelIsEmpty() => - new("Channel is empty or contains no messages for the specified period."); } \ No newline at end of file diff --git a/DiscordChatExporter.Core/Exporting/ChannelExporter.cs b/DiscordChatExporter.Core/Exporting/ChannelExporter.cs index b1a8bff..dc74487 100644 --- a/DiscordChatExporter.Core/Exporting/ChannelExporter.cs +++ b/DiscordChatExporter.Core/Exporting/ChannelExporter.cs @@ -20,11 +20,19 @@ public class ChannelExporter { // Check if the channel is empty if (request.Channel.LastMessageId is null) - throw DiscordChatExporterException.ChannelIsEmpty(); + { + throw new DiscordChatExporterException( + "Channel does not contain any messages." + ); + } // Check if the 'after' boundary is valid if (request.After is not null && request.Channel.LastMessageId < request.After) - throw DiscordChatExporterException.ChannelIsEmpty(); + { + throw new DiscordChatExporterException( + "Channel does not contain any messages within the specified period." + ); + } // Build context var context = new ExportContext(_discord, request); @@ -50,6 +58,10 @@ public class ChannelExporter // Throw if no messages were exported if (messageExporter.MessagesExported <= 0) - throw DiscordChatExporterException.ChannelIsEmpty(); + { + throw new DiscordChatExporterException( + "Channel does not contain any matching messages within the specified period." + ); + } } } \ No newline at end of file diff --git a/DiscordChatExporter.Core/Utils/Extensions/StringExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/StringExtensions.cs index 711b5e1..c364249 100644 --- a/DiscordChatExporter.Core/Utils/Extensions/StringExtensions.cs +++ b/DiscordChatExporter.Core/Utils/Extensions/StringExtensions.cs @@ -16,6 +16,21 @@ public static class StringExtensions ? str[..charCount] : str; + public static string ToSpaceSeparatedWords(this string str) + { + var builder = new StringBuilder(str.Length * 2); + + foreach (var c in str) + { + if (char.IsUpper(c) && builder.Length > 0) + builder.Append(' '); + + builder.Append(c); + } + + return builder.ToString(); + } + public static IEnumerable GetRunes(this string str) { var lastIndex = 0;