Browse Source

Init

pull/2305/head
Armano den Boef 3 years ago
parent
commit
ec0492af0f
27 changed files with 173 additions and 201 deletions
  1. +4
    -1
      samples/InteractionFramework/InteractionHandler.cs
  2. +2
    -2
      samples/InteractionFramework/Modules/ExampleModule.cs
  3. +4
    -1
      samples/InteractionFramework/Program.cs
  4. +14
    -15
      samples/TextCommandFramework/Program.cs
  5. +1
    -1
      samples/TextCommandFramework/Services/CommandHandlingService.cs
  6. +10
    -14
      samples/WebhookClient/Program.cs
  7. +1
    -1
      src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs
  8. +2
    -10
      src/Discord.Net.Commands/CommandService.cs
  9. +5
    -5
      src/Discord.Net.Core/CDN.cs
  10. +5
    -5
      src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs
  11. +2
    -2
      src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
  12. +2
    -2
      src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
  13. +6
    -6
      src/Discord.Net.Core/Format.cs
  14. +0
    -4
      src/Discord.Net.Rest/BaseDiscordClient.cs
  15. +87
    -92
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  16. +1
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs
  17. +1
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ThreadUpdateAuditLogData.cs
  18. +1
    -3
      src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs
  19. +2
    -4
      src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs
  20. +1
    -2
      src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs
  21. +2
    -2
      src/Discord.Net.Rest/Net/Queue/RequestQueue.cs
  22. +2
    -2
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  23. +1
    -9
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
  24. +4
    -4
      src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
  25. +6
    -6
      test/Discord.Net.Tests.Integration/ChannelsTests.cs
  26. +6
    -6
      test/Discord.Net.Tests.Integration/GuildTests.cs
  27. +1
    -0
      test/Discord.Net.Tests.Unit/ColorTests.cs

+ 4
- 1
samples/InteractionFramework/InteractionHandler.cs View File

@@ -37,7 +37,10 @@ namespace InteractionFramework
}

private async Task LogAsync(LogMessage log)
=> Console.WriteLine(log);
{
Console.WriteLine(log);
await Task.CompletedTask;
}

private async Task ReadyAsync()
{


+ 2
- 2
samples/InteractionFramework/Modules/ExampleModule.cs View File

@@ -12,7 +12,7 @@ namespace InteractionFramework.Modules
// Dependencies can be accessed through Property injection, public properties with public setters will be set by the service provider
public InteractionService Commands { get; set; }

private InteractionHandler _handler;
private readonly InteractionHandler _handler;

// Constructor injection is also a valid way to access the dependencies
public ExampleModule(InteractionHandler handler)
@@ -63,7 +63,7 @@ namespace InteractionFramework.Modules
[ComponentInteraction("roleSelect")]
public async Task RoleSelect(string[] selections)
{
throw new NotImplementedException();
await DeferAsync();
}

// With the Attribute DoUserCheck you can make sure that only the user this button targets can click it. This is defined by the first wildcard: *.


+ 4
- 1
samples/InteractionFramework/Program.cs View File

@@ -60,7 +60,10 @@ namespace InteractionFramework
}

private async Task LogAsync(LogMessage message)
=> Console.WriteLine(message.ToString());
{
Console.WriteLine(message.ToString());
await Task.CompletedTask;
}

public static bool IsDebug()
{


+ 14
- 15
samples/TextCommandFramework/Program.cs View File

@@ -22,7 +22,7 @@ namespace TextCommandFramework
{
// There is no need to implement IDisposable like before as we are
// using dependency injection, which handles calling Dispose for us.
static void Main(string[] args)
static void Main(string[] _)
=> new Program().MainAsync().GetAwaiter().GetResult();

public async Task MainAsync()
@@ -31,23 +31,22 @@ namespace TextCommandFramework
// when you are finished using it, at the end of your app's lifetime.
// If you use another dependency injection framework, you should inspect
// its documentation for the best way to do this.
using (var services = ConfigureServices())
{
var client = services.GetRequiredService<DiscordSocketClient>();
using var services = ConfigureServices();

client.Log += LogAsync;
services.GetRequiredService<CommandService>().Log += LogAsync;
var client = services.GetRequiredService<DiscordSocketClient>();

// Tokens should be considered secret data and never hard-coded.
// We can read from the environment variable to avoid hard coding.
await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("token"));
await client.StartAsync();
client.Log += LogAsync;
services.GetRequiredService<CommandService>().Log += LogAsync;

// Here we initialize the logic required to register our commands.
await services.GetRequiredService<CommandHandlingService>().InitializeAsync();
// Tokens should be considered secret data and never hard-coded.
// We can read from the environment variable to avoid hard coding.
await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("token"));
await client.StartAsync();

await Task.Delay(Timeout.Infinite);
}
// Here we initialize the logic required to register our commands.
await services.GetRequiredService<CommandHandlingService>().InitializeAsync();

await Task.Delay(Timeout.Infinite);
}

private Task LogAsync(LogMessage log)
@@ -57,7 +56,7 @@ namespace TextCommandFramework
return Task.CompletedTask;
}

private ServiceProvider ConfigureServices()
private static ServiceProvider ConfigureServices()
{
return new ServiceCollection()
.AddSingleton<DiscordSocketClient>()


+ 1
- 1
samples/TextCommandFramework/Services/CommandHandlingService.cs View File

@@ -58,7 +58,7 @@ namespace TextCommandFramework.Services
// we will handle the result in CommandExecutedAsync,
}

public async Task CommandExecutedAsync(Optional<CommandInfo> command, ICommandContext context, IResult result)
public static async Task CommandExecutedAsync(Optional<CommandInfo> command, ICommandContext context, IResult result)
{
// command is unspecified when there was a search failure (command not found); we don't care about these errors
if (!command.IsSpecified)


+ 10
- 14
samples/WebhookClient/Program.cs View File

@@ -9,26 +9,22 @@ namespace WebHookClient
// To a channel specific URL to send a message to that channel.
class Program
{
static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult();

public async Task MainAsync()
async static Task Main(string[] _)
{
// The webhook url follows the format https://discord.com/api/webhooks/{id}/{token}
// Because anyone with the webhook URL can use your webhook
// you should NOT hard code the URL or ID + token into your application.
using (var client = new DiscordWebhookClient("https://discord.com/api/webhooks/123/abc123"))
using var client = new DiscordWebhookClient("https://discord.com/api/webhooks/123/abc123");

var embed = new EmbedBuilder
{
var embed = new EmbedBuilder
{
Title = "Test Embed",
Description = "Test Description"
};
Title = "Test Embed",
Description = "Test Description"
};

// Webhooks are able to send multiple embeds per message
// As such, your embeds must be passed as a collection.
await client.SendMessageAsync(text: "Send a message to this webhook!", embeds: new[] { embed.Build() });
}
// Webhooks are able to send multiple embeds per message
// As such, your embeds must be passed as a collection.
await client.SendMessageAsync(text: "Send a message to this webhook!", embeds: new[] { embed.Build() });
}
}
}

+ 1
- 1
src/Discord.Net.Analyzers/GuildAccessAnalyzer.cs View File

@@ -18,7 +18,7 @@ namespace Discord.Analyzers
private const string Description = "Accessing 'Context.Guild' in a command without limiting the command to run only in guilds.";
private const string Category = "API Usage";

private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
private static DiagnosticDescriptor Rule = new(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);



+ 2
- 10
src/Discord.Net.Commands/CommandService.cs View File

@@ -503,18 +503,10 @@ namespace Discord.Commands
/// <param name="argPos">The position of which the command starts at.</param>
/// <returns>The result containing the matching commands.</returns>
public SearchResult Search(ICommandContext context, int argPos)
=> Search(context.Message.Content.Substring(argPos));
/// <summary>
/// Searches for the command.
/// </summary>
/// <param name="context">The context of the command.</param>
/// <param name="input">The command string.</param>
/// <returns>The result containing the matching commands.</returns>
public SearchResult Search(ICommandContext context, string input)
=> Search(input);
=> Search(context.Message.Content[argPos..]);
public SearchResult Search(string input)
{
string searchInput = _caseSensitive ? input : input.ToLowerInvariant();
var searchInput = _caseSensitive ? input : input.ToLowerInvariant();
var matches = _map.GetCommands(searchInput).OrderByDescending(x => x.Command.Priority).ToImmutableArray();

if (matches.Length > 0)


+ 5
- 5
src/Discord.Net.Core/CDN.cs View File

@@ -43,7 +43,7 @@ namespace Discord
{
if (avatarId == null)
return null;
string extension = FormatToExtension(format, avatarId);
var extension = FormatToExtension(format, avatarId);
return $"{DiscordConfig.CDNUrl}avatars/{userId}/{avatarId}.{extension}?size={size}";
}

@@ -51,7 +51,7 @@ namespace Discord
{
if (avatarId == null)
return null;
string extension = FormatToExtension(format, avatarId);
var extension = FormatToExtension(format, avatarId);
return $"{DiscordConfig.CDNUrl}guilds/{guildId}/users/{userId}/avatars/{avatarId}.{extension}?size={size}";
}

@@ -69,7 +69,7 @@ namespace Discord
{
if (bannerId == null)
return null;
string extension = FormatToExtension(format, bannerId);
var extension = FormatToExtension(format, bannerId);
return $"{DiscordConfig.CDNUrl}banners/{userId}/{bannerId}.{extension}?size={size}";
}
/// <summary>
@@ -148,7 +148,7 @@ namespace Discord
{
if (string.IsNullOrEmpty(bannerId))
return null;
string extension = FormatToExtension(format, bannerId);
var extension = FormatToExtension(format, bannerId);
return $"{DiscordConfig.CDNUrl}banners/{guildId}/{bannerId}.{extension}" + (size.HasValue ? $"?size={size}" : string.Empty);
}
/// <summary>
@@ -174,7 +174,7 @@ namespace Discord
/// </returns>
public static string GetRichAssetUrl(ulong appId, string assetId, ushort size, ImageFormat format)
{
string extension = FormatToExtension(format, "");
var extension = FormatToExtension(format, "");
return $"{DiscordConfig.CDNUrl}app-assets/{appId}/{assetId}.{extension}?size={size}";
}



+ 5
- 5
src/Discord.Net.Core/Entities/Messages/EmbedBuilder.cs View File

@@ -145,11 +145,11 @@ namespace Discord
{
get
{
int titleLength = Title?.Length ?? 0;
int authorLength = Author?.Name?.Length ?? 0;
int descriptionLength = Description?.Length ?? 0;
int footerLength = Footer?.Text?.Length ?? 0;
int fieldSum = Fields.Sum(f => f.Name.Length + f.Value.ToString().Length);
var titleLength = Title?.Length ?? 0;
var authorLength = Author?.Name?.Length ?? 0;
var descriptionLength = Description?.Length ?? 0;
var footerLength = Footer?.Text?.Length ?? 0;
var fieldSum = Fields.Sum(f => f.Name.Length + f.Value.ToString().Length);

return titleLength + authorLength + descriptionLength + footerLength + fieldSum;
}


+ 2
- 2
src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs View File

@@ -141,7 +141,7 @@ namespace Discord
bool? sendMessagesInThreads = null,
bool? startEmbeddedActivities = null)
{
ulong value = initialValue;
var value = initialValue;

Permissions.SetValue(ref value, createInstantInvite, ChannelPermission.CreateInstantInvite);
Permissions.SetValue(ref value, manageChannel, ChannelPermission.ManageChannels);
@@ -287,7 +287,7 @@ namespace Discord
var perms = new List<ChannelPermission>();
for (byte i = 0; i < Permissions.MaxBits; i++)
{
ulong flag = ((ulong)1 << i);
var flag = ((ulong)1 << i);
if ((RawValue & flag) != 0)
perms.Add((ChannelPermission)flag);
}


+ 2
- 2
src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs View File

@@ -153,7 +153,7 @@ namespace Discord
bool? startEmbeddedActivities = null,
bool? moderateMembers = null)
{
ulong value = initialValue;
var value = initialValue;

Permissions.SetValue(ref value, createInstantInvite, GuildPermission.CreateInstantInvite);
Permissions.SetValue(ref value, banMembers, GuildPermission.BanMembers);
@@ -358,7 +358,7 @@ namespace Discord
// each of the GuildPermissions increments by 2^i from 0 to MaxBits
for (byte i = 0; i < Permissions.MaxBits; i++)
{
ulong flag = ((ulong)1 << i);
var flag = ((ulong)1 << i);
if ((RawValue & flag) != 0)
perms.Add((GuildPermission)flag);
}


+ 6
- 6
src/Discord.Net.Core/Format.cs View File

@@ -28,7 +28,7 @@ namespace Discord
/// <summary> Returns a markdown-formatted string with codeblock formatting. </summary>
public static string Code(string text, string language = null)
{
if (language != null || text.Contains("\n"))
if (language != null || text.Contains('\n'))
return $"```{language ?? ""}\n{text}\n```";
else
return $"`{text}`";
@@ -38,7 +38,7 @@ namespace Discord
public static string Sanitize(string text)
{
if (text != null)
foreach (string unsafeChar in SensitiveCharacters)
foreach (var unsafeChar in SensitiveCharacters)
text = text.Replace(unsafeChar, $"\\{unsafeChar}");
return text;
}
@@ -55,9 +55,9 @@ namespace Discord
if (string.IsNullOrWhiteSpace(text))
return text;

StringBuilder result = new StringBuilder();
StringBuilder result = new();

int startIndex = 0;
var startIndex = 0;
int newLineIndex;
do
{
@@ -65,13 +65,13 @@ namespace Discord
if (newLineIndex == -1)
{
// read the rest of the string
var str = text.Substring(startIndex);
var str = text[startIndex..];
result.Append($"> {str}");
}
else
{
// read until the next newline
var str = text.Substring(startIndex, newLineIndex - startIndex);
var str = text[startIndex..newLineIndex];
result.Append($"> {str}\n");
}
startIndex = newLineIndex + 1;


+ 0
- 4
src/Discord.Net.Rest/BaseDiscordClient.cs View File

@@ -144,9 +144,7 @@ namespace Discord.Rest
{
if (!_isDisposed)
{
#pragma warning disable IDISP007
ApiClient.Dispose();
#pragma warning restore IDISP007
_stateLock?.Dispose();
_isDisposed = true;
}
@@ -156,9 +154,7 @@ namespace Discord.Rest
{
if (!_isDisposed)
{
#pragma warning disable IDISP007
await ApiClient.DisposeAsync().ConfigureAwait(false);
#pragma warning restore IDISP007
_stateLock?.Dispose();
_isDisposed = true;
}


+ 87
- 92
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -24,10 +24,10 @@ namespace Discord.API
internal class DiscordRestApiClient : IDisposable, IAsyncDisposable
{
#region DiscordRestApiClient
private static readonly ConcurrentDictionary<string, Func<BucketIds, BucketId>> _bucketIdGenerators = new ConcurrentDictionary<string, Func<BucketIds, BucketId>>();
private static readonly ConcurrentDictionary<string, Func<BucketIds, BucketId>> _bucketIdGenerators = new();

public event Func<string, string, double, Task> SentRequest { add { _sentRequestEvent.Add(value); } remove { _sentRequestEvent.Remove(value); } }
private readonly AsyncEvent<Func<string, string, double, Task>> _sentRequestEvent = new AsyncEvent<Func<string, string, double, Task>>();
private readonly AsyncEvent<Func<string, string, double, Task>> _sentRequestEvent = new();

protected readonly JsonSerializer _serializer;
protected readonly SemaphoreSlim _stateLock;
@@ -110,7 +110,7 @@ namespace Discord.API
_loginCancelToken?.Dispose();
RestClient?.Dispose();

if (!(RequestQueue is null))
if (RequestQueue is not null)
await RequestQueue.DisposeAsync().ConfigureAwait(false);

_stateLock?.Dispose();
@@ -123,16 +123,16 @@ namespace Discord.API

public ValueTask DisposeAsync() => DisposeAsync(true);

public async Task LoginAsync(TokenType tokenType, string token, RequestOptions options = null)
public async Task LoginAsync(TokenType tokenType, string token)
{
await _stateLock.WaitAsync().ConfigureAwait(false);
try
{
await LoginInternalAsync(tokenType, token, options).ConfigureAwait(false);
await LoginInternalAsync(tokenType, token).ConfigureAwait(false);
}
finally { _stateLock.Release(); }
}
private async Task LoginInternalAsync(TokenType tokenType, string token, RequestOptions options = null)
private async Task LoginInternalAsync(TokenType tokenType, string token)
{
if (LoginState != LoginState.LoggedOut)
await LogoutInternalAsync().ConfigureAwait(false);
@@ -196,11 +196,10 @@ namespace Discord.API
#endregion

#region Core
internal Task SendAsync(string method, Expression<Func<string>> endpointExpr, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendAsync(method, GetEndpoint(endpointExpr), GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options);
internal Task SendAsync(string method, Expression<Func<string>> endpointExpr, BucketIds ids, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendAsync(method, GetEndpoint(endpointExpr), GetBucketId(method, ids, endpointExpr, funcName), options);
public async Task SendAsync(string method, string endpoint,
BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
BucketId bucketId = null, RequestOptions options = null)
{
options ??= new RequestOptions();
options.HeaderOnly = true;
@@ -210,26 +209,24 @@ namespace Discord.API
await SendInternalAsync(method, endpoint, request).ConfigureAwait(false);
}

internal Task SendJsonAsync(string method, Expression<Func<string>> endpointExpr, object payload, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendJsonAsync(method, GetEndpoint(endpointExpr), payload, GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options);
internal Task SendJsonAsync(string method, Expression<Func<string>> endpointExpr, object payload, BucketIds ids, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendJsonAsync(method, GetEndpoint(endpointExpr), payload, GetBucketId(method, ids, endpointExpr, funcName), options);
public async Task SendJsonAsync(string method, string endpoint, object payload,
BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
BucketId bucketId = null, RequestOptions options = null)
{
options ??= new RequestOptions();
options.HeaderOnly = true;
options.BucketId = bucketId;

string json = payload != null ? SerializeJson(payload) : null;
var json = payload != null ? SerializeJson(payload) : null;
var request = new JsonRestRequest(RestClient, method, endpoint, json, options);
await SendInternalAsync(method, endpoint, request).ConfigureAwait(false);
}

internal Task SendMultipartAsync(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options);
internal Task SendMultipartAsync(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(method, ids, endpointExpr, funcName), options);
public async Task SendMultipartAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
BucketId bucketId = null, RequestOptions options = null)
{
options ??= new RequestOptions();
options.HeaderOnly = true;
@@ -239,11 +236,10 @@ namespace Discord.API
await SendInternalAsync(method, endpoint, request).ConfigureAwait(false);
}

internal Task<TResponse> SendAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendAsync<TResponse>(method, GetEndpoint(endpointExpr), GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options);
internal Task<TResponse> SendAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, BucketIds ids, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendAsync<TResponse>(method, GetEndpoint(endpointExpr), GetBucketId(method, ids, endpointExpr, funcName), options);
public async Task<TResponse> SendAsync<TResponse>(string method, string endpoint,
BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class
BucketId bucketId = null, RequestOptions options = null) where TResponse : class
{
options ??= new RequestOptions();
options.BucketId = bucketId;
@@ -252,26 +248,25 @@ namespace Discord.API
return DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false));
}

internal Task<TResponse> SendJsonAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, object payload, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendJsonAsync<TResponse>(method, GetEndpoint(endpointExpr), payload, GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options);
internal Task<TResponse> SendJsonAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, object payload, BucketIds ids, RequestOptions options = null, [CallerMemberName] string funcName = null) where TResponse : class
=> SendJsonAsync<TResponse>(method, GetEndpoint(endpointExpr), payload, GetBucketId(method, ids, endpointExpr, funcName), options);
public async Task<TResponse> SendJsonAsync<TResponse>(string method, string endpoint, object payload,
BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) where TResponse : class
BucketId bucketId = null, RequestOptions options = null) where TResponse : class
{
options ??= new RequestOptions();
options.BucketId = bucketId;

string json = payload != null ? SerializeJson(payload) : null;
var json = payload != null ? SerializeJson(payload) : null;

var request = new JsonRestRequest(RestClient, method, endpoint, json, options);
return DeserializeJson<TResponse>(await SendInternalAsync(method, endpoint, request).ConfigureAwait(false));
}

internal Task<TResponse> SendMultipartAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(method, ids, endpointExpr, funcName), clientBucket, options);
RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(method, ids, endpointExpr, funcName), options);
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
BucketId bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
BucketId bucketId = null, RequestOptions options = null)
{
options ??= new RequestOptions();
options.BucketId = bucketId;
@@ -293,7 +288,7 @@ namespace Discord.API
var responseStream = await RequestQueue.SendAsync(request).ConfigureAwait(false);
stopwatch.Stop();

double milliseconds = ToMilliseconds(stopwatch);
var milliseconds = ToMilliseconds(stopwatch);
await _sentRequestEvent.InvokeAsync(method, endpoint, milliseconds).ConfigureAwait(false);

return responseStream;
@@ -585,15 +580,15 @@ namespace Discord.API

var bucket = new BucketIds(channelId: channelId);

string query = "";
var query = "";

if (limit.HasValue)
{
query = $"?before={before.GetValueOrDefault(DateTimeOffset.UtcNow).ToString("O")}&limit={limit.Value}";
query = $"?before={before.GetValueOrDefault(DateTimeOffset.UtcNow):O}&limit={limit.Value}";
}
else if (before.HasValue)
{
query = $"?before={before.Value.ToString("O")}";
query = $"?before={before.Value:O}";
}

return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/threads/archived/public{query}", bucket, options: options);
@@ -608,15 +603,15 @@ namespace Discord.API

var bucket = new BucketIds(channelId: channelId);

string query = "";
var query = "";

if (limit.HasValue)
{
query = $"?before={before.GetValueOrDefault(DateTimeOffset.UtcNow).ToString("O")}&limit={limit.Value}";
query = $"?before={before.GetValueOrDefault(DateTimeOffset.UtcNow):O}&limit={limit.Value}";
}
else if (before.HasValue)
{
query = $"?before={before.Value.ToString("O")}";
query = $"?before={before.Value:O}";
}

return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/threads/archived/private{query}", bucket, options: options);
@@ -631,7 +626,7 @@ namespace Discord.API

var bucket = new BucketIds(channelId: channelId);

string query = "";
var query = "";

if (limit.HasValue)
{
@@ -639,7 +634,7 @@ namespace Discord.API
}
else if (before.HasValue)
{
query = $"?before={before.Value.ToString("O")}";
query = $"?before={before.Value:O}";
}

return await SendAsync<ChannelThreads>("GET", () => $"channels/{channelId}/users/@me/threads/archived/private{query}", bucket, options: options);
@@ -769,8 +764,8 @@ namespace Discord.API
Preconditions.AtMost(args.Limit, DiscordConfig.MaxMessagesPerBatch, nameof(args.Limit));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxMessagesPerBatch);
ulong? relativeId = args.RelativeMessageId.IsSpecified ? args.RelativeMessageId.Value : (ulong?)null;
var limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxMessagesPerBatch);
var relativeId = args.RelativeMessageId.IsSpecified ? args.RelativeMessageId.Value : (ulong?)null;
var relativeDir = args.RelativeDirection.GetValueOrDefault(Direction.Before) switch
{
Direction.After => "after",
@@ -794,11 +789,11 @@ namespace Discord.API
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));

if (args.Content?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(channelId: channelId);
return await SendJsonAsync<Message>("POST", () => $"channels/{channelId}/messages", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendJsonAsync<Message>("POST", () => $"channels/{channelId}/messages", args, ids, options: options).ConfigureAwait(false);
}


@@ -815,12 +810,12 @@ namespace Discord.API
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));

if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args));

options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(webhookId: webhookId);
return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args, ids, options: options).ConfigureAwait(false);
}

/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
@@ -837,11 +832,11 @@ namespace Discord.API
if (args.Embeds.IsSpecified)
Preconditions.AtMost(args.Embeds.Value.Length, 10, nameof(args.Embeds), "A max of 10 Embeds are allowed.");
if (args.Content.IsSpecified && args.Content.Value.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args));
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(webhookId: webhookId);
await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}${WebhookQuery(false, threadId)}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
await SendJsonAsync<Message>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}/messages/{messageId}${WebhookQuery(false, threadId)}", args, ids, options: options).ConfigureAwait(false);
}

/// <exception cref="InvalidOperationException">This operation may only be called with a <see cref="TokenType.Webhook"/> token.</exception>
@@ -872,7 +867,7 @@ namespace Discord.API
throw new ArgumentOutOfRangeException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));

var ids = new BucketIds(channelId: channelId);
return await SendMultipartAsync<Message>("POST", () => $"channels/{channelId}/messages", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendMultipartAsync<Message>("POST", () => $"channels/{channelId}/messages", args.ToDictionary(), ids, options: options).ConfigureAwait(false);
}

/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception>
@@ -897,7 +892,7 @@ namespace Discord.API
}

var ids = new BucketIds(webhookId: webhookId);
return await SendMultipartAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendMultipartAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?{WebhookQuery(true, threadId)}", args.ToDictionary(), ids, options: options).ConfigureAwait(false);
}
public async Task DeleteMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{
@@ -941,7 +936,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(channelId: channelId);
return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendJsonAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args, ids, options: options).ConfigureAwait(false);
}

public async Task<Message> ModifyMessageAsync(ulong channelId, ulong messageId, Rest.UploadFileParams args, RequestOptions options = null)
@@ -954,7 +949,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(channelId: channelId);
return await SendMultipartAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendMultipartAsync<Message>("PATCH", () => $"channels/{channelId}/messages/{messageId}", args.ToDictionary(), ids, options: options).ConfigureAwait(false);
}
#endregion

@@ -1082,8 +1077,8 @@ namespace Discord.API
Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUserReactionsPerBatch);
ulong afterUserId = args.AfterUserId.GetValueOrDefault(0);
var limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUserReactionsPerBatch);
var afterUserId = args.AfterUserId.GetValueOrDefault(0);

var ids = new BucketIds(channelId: channelId);
Expression<Func<string>> endpoint = () => $"channels/{channelId}/messages/{messageId}/reactions/{emoji}?limit={limit}&after={afterUserId}";
@@ -1345,12 +1340,12 @@ namespace Discord.API
Preconditions.NotNullOrEmpty(response.Content, nameof(response.Content));

if (response.Content.IsSpecified && response.Content.Value.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(response.Content));
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(response));

options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds();
await SendMultipartAsync("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
await SendMultipartAsync("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response.ToDictionary(), ids, options: options).ConfigureAwait(false);
}
public async Task<Message> GetInteractionResponseAsync(string interactionToken, RequestOptions options = null)
{
@@ -1385,7 +1380,7 @@ namespace Discord.API
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));

if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args));

options = RequestOptions.CreateOrClone(options);

@@ -1401,12 +1396,12 @@ namespace Discord.API
Preconditions.NotNullOrEmpty(args.Content, nameof(args.Content));

if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args));

options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds();
return await SendMultipartAsync<Message>("POST", () => $"webhooks/{CurrentApplicationId}/{token}?wait=true", args.ToDictionary(), ids, clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
return await SendMultipartAsync<Message>("POST", () => $"webhooks/{CurrentApplicationId}/{token}?wait=true", args.ToDictionary(), ids, options: options).ConfigureAwait(false);
}

public async Task<Message> ModifyInteractionFollowupMessageAsync(ModifyInteractionResponseParams args, ulong id, string token, RequestOptions options = null)
@@ -1415,7 +1410,7 @@ namespace Discord.API
Preconditions.NotEqual(id, 0, nameof(id));

if (args.Content.IsSpecified && args.Content.Value?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args.Content));
throw new ArgumentException(message: $"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", paramName: nameof(args));

options = RequestOptions.CreateOrClone(options);

@@ -1540,7 +1535,7 @@ namespace Discord.API
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(args, nameof(args));
Preconditions.AtLeast(args.Days, 1, nameof(args.Days));
string endpointRoleIds = args.IncludeRoleIds?.Length > 0 ? $"&include_roles={string.Join(",", args.IncludeRoleIds)}" : "";
var endpointRoleIds = args.IncludeRoleIds?.Length > 0 ? $"&include_roles={string.Join(",", args.IncludeRoleIds)}" : "";
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
@@ -1557,8 +1552,8 @@ namespace Discord.API
Preconditions.AtMost(args.Limit, DiscordConfig.MaxBansPerBatch, nameof(args.Limit));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxBansPerBatch);
ulong? relativeId = args.RelativeUserId.IsSpecified ? args.RelativeUserId.Value : (ulong?)null;
var limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxBansPerBatch);
var relativeId = args.RelativeUserId.IsSpecified ? args.RelativeUserId.Value : (ulong?)null;
var relativeDir = args.RelativeDirection.GetValueOrDefault(Direction.Before) switch
{
Direction.After => "after",
@@ -1602,7 +1597,7 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds(guildId: guildId);
string reason = string.IsNullOrWhiteSpace(args.Reason) ? "" : $"&reason={Uri.EscapeDataString(args.Reason)}";
var reason = string.IsNullOrWhiteSpace(args.Reason) ? "" : $"&reason={Uri.EscapeDataString(args.Reason)}";
await SendAsync("PUT", () => $"guilds/{guildId}/bans/{userId}?delete_message_days={args.DeleteMessageDays}{reason}", ids, options: options).ConfigureAwait(false);
}
/// <exception cref="ArgumentException"><paramref name="guildId"/> and <paramref name="userId"/> must not be equal to zero.</exception>
@@ -1674,12 +1669,12 @@ namespace Discord.API
options = RequestOptions.CreateOrClone(options);

//Remove trailing slash
if (inviteId[inviteId.Length - 1] == '/')
inviteId = inviteId.Substring(0, inviteId.Length - 1);
//Remove leading URL
int index = inviteId.LastIndexOf('/');
if (inviteId[^1] == '/')
inviteId = inviteId[0..^1];
//Remove leading URL
var index = inviteId.LastIndexOf('/');
if (index >= 0)
inviteId = inviteId.Substring(index + 1);
inviteId = inviteId[(index + 1)..];

try
{
@@ -1794,8 +1789,8 @@ namespace Discord.API
Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(int.MaxValue);
ulong afterUserId = args.AfterUserId.GetValueOrDefault(0);
var limit = args.Limit.GetValueOrDefault(int.MaxValue);
var afterUserId = args.AfterUserId.GetValueOrDefault(0);

var ids = new BucketIds(guildId: guildId);
Expression<Func<string>> endpoint = () => $"guilds/{guildId}/members?limit={limit}&after={afterUserId}";
@@ -1818,7 +1813,7 @@ namespace Discord.API
Preconditions.NotNull(args, nameof(args));
options = RequestOptions.CreateOrClone(options);

bool isCurrentUser = userId == CurrentUserId;
var isCurrentUser = userId == CurrentUserId;

if (args.RoleIds.IsSpecified)
Preconditions.NotEveryoneRole(args.RoleIds.Value, guildId, nameof(args.RoleIds));
@@ -1843,8 +1838,8 @@ namespace Discord.API
Preconditions.NotNullOrEmpty(args.Query, nameof(args.Query));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUsersPerBatch);
string query = args.Query;
var limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUsersPerBatch);
var query = args.Query;

var ids = new BucketIds(guildId: guildId);
Expression<Func<string>> endpoint = () => $"guilds/{guildId}/members/search?limit={limit}&query={query}";
@@ -2034,8 +2029,8 @@ namespace Discord.API
Preconditions.AtMost(args.Limit, DiscordConfig.MaxMessagesPerBatch, nameof(args.Limit));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxGuildEventUsersPerBatch);
ulong? relativeId = args.RelativeUserId.IsSpecified ? args.RelativeUserId.Value : (ulong?)null;
var limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxGuildEventUsersPerBatch);
var relativeId = args.RelativeUserId.IsSpecified ? args.RelativeUserId.Value : (ulong?)null;
var relativeDir = args.RelativeDirection.GetValueOrDefault(Direction.Before) switch
{
Direction.After => "after",
@@ -2092,8 +2087,8 @@ namespace Discord.API
Preconditions.GreaterThan(args.AfterGuildId, 0, nameof(args.AfterGuildId));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(int.MaxValue);
ulong afterGuildId = args.AfterGuildId.GetValueOrDefault(0);
var limit = args.Limit.GetValueOrDefault(int.MaxValue);
var afterGuildId = args.AfterGuildId.GetValueOrDefault(0);

return await SendAsync<IReadOnlyCollection<UserGuild>>("GET", () => $"users/@me/guilds?limit={limit}&after={afterGuildId}", new BucketIds(), options: options).ConfigureAwait(false);
}
@@ -2152,7 +2147,7 @@ namespace Discord.API
Preconditions.NotNull(args, nameof(args));
options = RequestOptions.CreateOrClone(options);

int limit = args.Limit.GetValueOrDefault(int.MaxValue);
var limit = args.Limit.GetValueOrDefault(int.MaxValue);

var ids = new BucketIds(guildId: guildId);
Expression<Func<string>> endpoint;
@@ -2175,7 +2170,7 @@ namespace Discord.API
}

// Still use string interp for the query w/o params, as this is necessary for CreateBucketId
endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}{queryArgs.ToString()}";
endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}{queryArgs}";
return await SendAsync<AuditLog>("GET", endpoint, ids, options: options).ConfigureAwait(false);
}
#endregion
@@ -2263,9 +2258,9 @@ namespace Discord.API
}
protected T DeserializeJson<T>(Stream jsonStream)
{
using (TextReader text = new StreamReader(jsonStream))
using (JsonReader reader = new JsonTextReader(text))
return _serializer.Deserialize<T>(reader);
using TextReader text = new StreamReader(jsonStream);
using JsonReader reader = new JsonTextReader(text);
return _serializer.Deserialize<T>(reader);
}

protected async Task<T> NullifyNotFound<T>(Task<T> sendTask) where T : class
@@ -2357,7 +2352,7 @@ namespace Discord.API
var builder = new StringBuilder();
var methodCall = endpoint.Body as MethodCallExpression;
var methodArgs = methodCall.Arguments.ToArray();
string format = (methodArgs[0] as ConstantExpression).Value as string;
var format = (methodArgs[0] as ConstantExpression).Value as string;

//Unpack the array, if one exists (happens with 4+ parameters)
if (methodArgs.Length > 1 && methodArgs[1].NodeType == ExpressionType.NewArrayInit)
@@ -2368,24 +2363,24 @@ namespace Discord.API
Array.Copy(elements, 0, methodArgs, 1, elements.Length);
}

int endIndex = format.IndexOf('?'); //Don't include params
var endIndex = format.IndexOf('?'); //Don't include params
if (endIndex == -1)
endIndex = format.Length;

int lastIndex = 0;
var lastIndex = 0;
while (true)
{
int leftIndex = format.IndexOf("{", lastIndex);
var leftIndex = format.IndexOf("{", lastIndex);
if (leftIndex == -1 || leftIndex > endIndex)
{
builder.Append(format, lastIndex, endIndex - lastIndex);
break;
}
builder.Append(format, lastIndex, leftIndex - lastIndex);
int rightIndex = format.IndexOf("}", leftIndex);
var rightIndex = format.IndexOf("}", leftIndex);

int argId = int.Parse(format.Substring(leftIndex + 1, rightIndex - leftIndex - 1), NumberStyles.None, CultureInfo.InvariantCulture);
string fieldName = GetFieldName(methodArgs[argId + 1]);
var argId = int.Parse(format.AsSpan(leftIndex + 1, rightIndex - leftIndex - 1).ToString(), NumberStyles.None, CultureInfo.InvariantCulture);
var fieldName = GetFieldName(methodArgs[argId + 1]);

var mappedId = BucketIds.GetIndex(fieldName);

@@ -2397,7 +2392,7 @@ namespace Discord.API

lastIndex = rightIndex + 1;
}
if (builder[builder.Length - 1] == '/')
if (builder[^1] == '/')
builder.Remove(builder.Length - 1, 1);

format = builder.ToString();
@@ -2423,7 +2418,7 @@ namespace Discord.API

private static string WebhookQuery(bool wait = false, ulong? threadId = null)
{
List<string> querys = new List<string>() { };
List<string> querys = new() { };
if (wait)
querys.Add("wait=true");
if (threadId.HasValue)


+ 1
- 1
src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs View File

@@ -9,7 +9,7 @@ namespace Discord.Rest
internal static class AuditLogHelper
{
private static readonly Dictionary<ActionType, Func<BaseDiscordClient, Model, EntryModel, IAuditLogData>> CreateMapping
= new Dictionary<ActionType, Func<BaseDiscordClient, Model, EntryModel, IAuditLogData>>()
= new()
{
[ActionType.GuildUpdated] = GuildUpdateAuditLogData.Create,



+ 1
- 1
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ThreadUpdateAuditLogData.cs View File

@@ -15,7 +15,7 @@ namespace Discord.Rest
Thread = thread;
ThreadType = type;
Before = before;
After = After;
After = after;
}

internal static ThreadUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)


+ 1
- 3
src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs View File

@@ -17,11 +17,11 @@ namespace Discord.Rest
public class RestGroupChannel : RestChannel, IGroupChannel, IRestPrivateChannel, IRestMessageChannel, IRestAudioChannel
{
#region RestGroupChannel
private string _iconId;
private ImmutableDictionary<ulong, RestGroupUser> _users;

/// <inheritdoc />
public string Name { get; private set; }

/// <inheritdoc/>
public string RTCRegion { get; private set; }

@@ -43,8 +43,6 @@ namespace Discord.Rest
{
if (model.Name.IsSpecified)
Name = model.Name.Value;
if (model.Icon.IsSpecified)
_iconId = model.Icon.Value;

if (model.Recipients.IsSpecified)
UpdateUsers(model.Recipients.Value);


+ 2
- 4
src/Discord.Net.Rest/Entities/Interactions/MessageComponents/RestMessageComponent.cs View File

@@ -142,9 +142,8 @@ namespace Discord.Rest
/// Updates the message which this component resides in with the type <see cref="InteractionResponseType.UpdateMessage"/>
/// </summary>
/// <param name="func">A delegate containing the properties to modify the message with.</param>
/// <param name="options">The request options for this <see langword="async"/> request.</param>
/// <returns>A string that contains json to write back to the incoming http request.</returns>
public string Update(Action<MessageProperties> func, RequestOptions options = null)
public string Update(Action<MessageProperties> func)
{
var args = new MessageProperties();
func(args);
@@ -384,11 +383,10 @@ namespace Discord.Rest
/// Defers an interaction and responds with type 5 (<see cref="InteractionResponseType.DeferredChannelMessageWithSource"/>)
/// </summary>
/// <param name="ephemeral"><see langword="true"/> to send this message ephemerally, otherwise <see langword="false"/>.</param>
/// <param name="options">The request options for this <see langword="async"/> request.</param>
/// <returns>
/// A string that contains json to write back to the incoming http request.
/// </returns>
public string DeferLoading(bool ephemeral = false, RequestOptions options = null)
public string DeferLoading(bool ephemeral = false)
{
if (!InteractionHelper.CanSendResponse(this))
throw new TimeoutException($"Cannot defer an interaction after {InteractionHelper.ResponseTimeLimit} seconds of no response/acknowledgement");


+ 1
- 2
src/Discord.Net.Rest/Entities/Interactions/SlashCommands/RestAutocompleteInteraction.cs View File

@@ -49,11 +49,10 @@ namespace Discord.Rest
/// there is no choices for their autocompleted input.
/// </remarks>
/// </param>
/// <param name="options">The request options for this response.</param>
/// <returns>
/// A string that contains json to write back to the incoming http request.
/// </returns>
public string Respond(IEnumerable<AutocompleteResult> result, RequestOptions options = null)
public string Respond(IEnumerable<AutocompleteResult> result)
{
if (!InteractionHelper.CanSendResponse(this))
throw new TimeoutException($"Cannot respond to an interaction after {InteractionHelper.ResponseTimeLimit} seconds!");


+ 2
- 2
src/Discord.Net.Rest/Net/Queue/RequestQueue.cs View File

@@ -24,7 +24,7 @@ namespace Discord.Net.Queue
private CancellationToken _requestCancelToken; //Parent token + Clear token
private DateTimeOffset _waitUntil;

private Task _cleanupTask;
private readonly Task _cleanupTask;

public RequestQueue()
{
@@ -42,7 +42,7 @@ namespace Discord.Net.Queue

public async Task SetCancelTokenAsync(CancellationToken cancelToken)
{
await _tokenLock.WaitAsync().ConfigureAwait(false);
await _tokenLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
try
{
_parentToken = cancelToken;


+ 2
- 2
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -2242,7 +2242,7 @@ namespace Discord.WebSocket
//Only strip out the port if the endpoint contains it
var portBegin = endpoint.LastIndexOf(':');
if (portBegin > 0)
endpoint = endpoint.Substring(0, portBegin);
endpoint = endpoint[..portBegin];

var _ = guild.FinishConnectAudio(endpoint, data.Token).ConfigureAwait(false);
}
@@ -2978,7 +2978,7 @@ namespace Discord.WebSocket
{
return SocketDMChannel.Create(this, state, channelId, model);
}
internal SocketDMChannel CreateDMChannel(ulong channelId, SocketUser user, ClientState state)
internal SocketDMChannel CreateDMChannel(ulong channelId, SocketUser user, ClientState _)
{
return new SocketDMChannel(this, channelId, user);
}


+ 1
- 9
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -33,7 +33,6 @@ namespace Discord.WebSocket
public class SocketGuild : SocketEntity<ulong>, IGuild, IDisposable
{
#region SocketGuild
#pragma warning disable IDISP002, IDISP006
private readonly SemaphoreSlim _audioLock;
private TaskCompletionSource<bool> _syncPromise, _downloaderPromise;
private TaskCompletionSource<AudioClient> _audioConnectPromise;
@@ -47,7 +46,6 @@ namespace Discord.WebSocket

private AudioClient _audioClient;
private VoiceStateUpdateParams _voiceStateUpdateParams;
#pragma warning restore IDISP002, IDISP006

/// <inheritdoc />
public string Name { get; private set; }
@@ -585,7 +583,7 @@ namespace Discord.WebSocket
// _ = _downloaderPromise.TrySetResultAsync(true);
}*/

internal void Update(ClientState state, EmojiUpdateModel model)
internal void Update(ClientState _, EmojiUpdateModel model)
{
var emotes = ImmutableArray.CreateBuilder<GuildEmote>(model.Emojis.Length);
for (int i = 0; i < model.Emojis.Length; i++)
@@ -1607,11 +1605,9 @@ namespace Discord.WebSocket

if (external)
{
#pragma warning disable IDISP001
var _ = promise.TrySetResultAsync(null);
await Discord.ApiClient.SendVoiceStateUpdateAsync(_voiceStateUpdateParams).ConfigureAwait(false);
return null;
#pragma warning restore IDISP001
}

if (_audioClient == null)
@@ -1634,14 +1630,10 @@ namespace Discord.WebSocket
};
audioClient.Connected += () =>
{
#pragma warning disable IDISP001
var _ = promise.TrySetResultAsync(_audioClient);
#pragma warning restore IDISP001
return Task.Delay(0);
};
#pragma warning disable IDISP003
_audioClient = audioClient;
#pragma warning restore IDISP003
}

await Discord.ApiClient.SendVoiceStateUpdateAsync(_voiceStateUpdateParams).ConfigureAwait(false);


+ 4
- 4
src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs View File

@@ -143,7 +143,7 @@ namespace Discord.WebSocket
{
var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model));
entity.Update(state, model);
entity.UpdateRoles(new ulong[0]);
entity.UpdateRoles(Array.Empty<ulong>());
return entity;
}
internal static SocketGuildUser Create(SocketGuild guild, ClientState state, MemberModel model)
@@ -151,7 +151,7 @@ namespace Discord.WebSocket
var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User));
entity.Update(state, model);
if (!model.Roles.IsSpecified)
entity.UpdateRoles(new ulong[0]);
entity.UpdateRoles(Array.Empty<ulong>());
return entity;
}
internal static SocketGuildUser Create(SocketGuild guild, ClientState state, PresenceModel model)
@@ -159,7 +159,7 @@ namespace Discord.WebSocket
var entity = new SocketGuildUser(guild, guild.Discord.GetOrCreateUser(state, model.User));
entity.Update(state, model, false);
if (!model.Roles.IsSpecified)
entity.UpdateRoles(new ulong[0]);
entity.UpdateRoles(Array.Empty<ulong>());
return entity;
}
internal void Update(ClientState state, MemberModel model)
@@ -180,7 +180,7 @@ namespace Discord.WebSocket
if (model.Pending.IsSpecified)
IsPending = model.Pending.Value;
}
internal void Update(ClientState state, PresenceModel model, bool updatePresence)
internal void Update(ClientState _, PresenceModel model, bool updatePresence)
{
if (updatePresence)
{


+ 6
- 6
test/Discord.Net.Tests.Integration/ChannelsTests.cs View File

@@ -13,20 +13,20 @@ namespace Discord
[CollectionDefinition("ChannelsTests", DisableParallelization = true)]
public class ChannelsTests : IClassFixture<RestGuildFixture>
{
private IGuild guild;
private readonly ITestOutputHelper output;
private readonly IGuild guild;
private readonly ITestOutputHelper _output;

public ChannelsTests(RestGuildFixture guildFixture, ITestOutputHelper output)
{
guild = guildFixture.Guild;
output = output;
output.WriteLine($"RestGuildFixture using guild: {guild.Id}");
_output = output;
_output.WriteLine($"RestGuildFixture using guild: {guild.Id}");
// capture all console output
guildFixture.Client.Log += LogAsync;
}
private Task LogAsync(LogMessage message)
{
output.WriteLine(message.ToString());
_output.WriteLine(message.ToString());
return Task.CompletedTask;
}

@@ -100,7 +100,7 @@ namespace Discord
public async Task ModifyChannelCategories()
{
// util method for checking if a category is set
async Task CheckAsync(INestedChannel channel, ICategoryChannel cat)
static async Task CheckAsync(INestedChannel channel, ICategoryChannel cat)
{
// check that the category is not set
if (cat == null)


+ 6
- 6
test/Discord.Net.Tests.Integration/GuildTests.cs View File

@@ -10,21 +10,21 @@ namespace Discord
[CollectionDefinition("GuildTests", DisableParallelization = true)]
public class GuildTests : IClassFixture<RestGuildFixture>
{
private IDiscordClient client;
private IGuild guild;
private readonly ITestOutputHelper output;
private readonly IDiscordClient client;
private readonly IGuild guild;
private readonly ITestOutputHelper _output;

public GuildTests(RestGuildFixture guildFixture, ITestOutputHelper output)
{
client = guildFixture.Client;
guild = guildFixture.Guild;
output = output;
output.WriteLine($"RestGuildFixture using guild: {guild.Id}");
_output = output;
_output.WriteLine($"RestGuildFixture using guild: {guild.Id}");
guildFixture.Client.Log += LogAsync;
}
private Task LogAsync(LogMessage message)
{
output.WriteLine(message.ToString());
_output.WriteLine(message.ToString());
return Task.CompletedTask;
}
/// <summary>


+ 1
- 0
test/Discord.Net.Tests.Unit/ColorTests.cs View File

@@ -10,6 +10,7 @@ namespace Discord
/// </summary>
public class ColorTests
{
[Fact]
public void Color_New()
{
Assert.Equal(0u, new Color().RawValue);


Loading…
Cancel
Save