Visitar URL original
getMessages returns now a IAsyncEnumerable by Plerx2493 · Pull Request #1641 · DSharpPlus/DSharpPlus · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions DSharpPlus/Entities/Channel/DiscordChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ public async Task ModifyPositionAsync(int position, string reason = null, bool?
/// <exception cref="NotFoundException">Thrown when the channel does not exist.</exception>
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
public Task<IReadOnlyList<DiscordMessage>> GetMessagesBeforeAsync(ulong before, int limit = 100)
public IAsyncEnumerable<DiscordMessage> GetMessagesBeforeAsync(ulong before, int limit = 100)
=> this.GetMessagesInternalAsync(limit, before, null, null);

/// <summary>
Expand All @@ -490,7 +490,7 @@ public Task<IReadOnlyList<DiscordMessage>> GetMessagesBeforeAsync(ulong before,
/// <exception cref="NotFoundException">Thrown when the channel does not exist.</exception>
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
public Task<IReadOnlyList<DiscordMessage>> GetMessagesAfterAsync(ulong after, int limit = 100)
public IAsyncEnumerable<DiscordMessage> GetMessagesAfterAsync(ulong after, int limit = 100)
=> this.GetMessagesInternalAsync(limit, null, after, null);

/// <summary>
Expand All @@ -502,7 +502,7 @@ public Task<IReadOnlyList<DiscordMessage>> GetMessagesAfterAsync(ulong after, in
/// <exception cref="NotFoundException">Thrown when the channel does not exist.</exception>
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
public Task<IReadOnlyList<DiscordMessage>> GetMessagesAroundAsync(ulong around, int limit = 100)
public IAsyncEnumerable<DiscordMessage> GetMessagesAroundAsync(ulong around, int limit = 100)
=> this.GetMessagesInternalAsync(limit, null, null, around);

/// <summary>
Expand All @@ -513,10 +513,10 @@ public Task<IReadOnlyList<DiscordMessage>> GetMessagesAroundAsync(ulong around,
/// <exception cref="NotFoundException">Thrown when the channel does not exist.</exception>
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
public Task<IReadOnlyList<DiscordMessage>> GetMessagesAsync(int limit = 100) =>
public IAsyncEnumerable<DiscordMessage> GetMessagesAsync(int limit = 100) =>
this.GetMessagesInternalAsync(limit, null, null, null);

private async Task<IReadOnlyList<DiscordMessage>> GetMessagesInternalAsync(int limit = 100, ulong? before = null, ulong? after = null, ulong? around = null)
private async IAsyncEnumerable<DiscordMessage> GetMessagesInternalAsync(int limit = 100, ulong? before = null, ulong? after = null, ulong? around = null)
{
if (!Utilities.IsTextableChannel(this))
{
Expand All @@ -530,7 +530,7 @@ private async Task<IReadOnlyList<DiscordMessage>> GetMessagesInternalAsync(int l

if (limit == 0)
{
return Array.Empty<DiscordMessage>();
yield break;
}

//return this.Discord.ApiClient.GetChannelMessagesAsync(this.Id, limit, before, after, around);
Expand All @@ -542,31 +542,35 @@ private async Task<IReadOnlyList<DiscordMessage>> GetMessagesInternalAsync(int l
List<DiscordMessage> msgs = new(limit);
int remaining = limit;
ulong? last = null;
bool isAfter = after != null;
bool isbefore = before != null;

int lastCount;
do
{
int fetchSize = remaining > 100 ? 100 : remaining;
IReadOnlyList<DiscordMessage> fetch = await this.Discord.ApiClient.GetChannelMessagesAsync(this.Id, fetchSize, !isAfter ? last ?? before : null, isAfter ? last ?? after : null, around);
IReadOnlyList<DiscordMessage> fetch = await this.Discord.ApiClient.GetChannelMessagesAsync(this.Id, fetchSize, isbefore ? last ?? before : null, !isbefore ? last ?? after : null, around);

lastCount = fetch.Count;
remaining -= lastCount;

if (!isAfter)
if (!isbefore)
{
msgs.AddRange(fetch);
foreach (DiscordMessage msg in fetch)
{
yield return msg;
}
last = fetch.LastOrDefault()?.Id;
}
else
{
msgs.InsertRange(0, fetch);
for (int i = fetch.Count - 1; i >= 0; i--)
{
yield return fetch[i];
}
last = fetch.FirstOrDefault()?.Id;
}
}
while (remaining > 0 && lastCount > 0);

return new ReadOnlyCollection<DiscordMessage>(msgs);
}

/// <summary>
Expand Down
21 changes: 13 additions & 8 deletions DSharpPlus/Net/Rest/RateLimitPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

namespace DSharpPlus.Net;

using System.Collections.Generic;

internal class RateLimitPolicy : AsyncPolicy<HttpResponseMessage>
{
private readonly RateLimitBucket globalBucket;
Expand Down Expand Up @@ -120,20 +122,23 @@ protected override async Task<HttpResponseMessage> ImplementationAsync
// make the actual request

HttpResponseMessage response = await action(context, cancellationToken);
bool hasBucketHeader = response.Headers.TryGetValues("X-RateLimit-Bucket", out IEnumerable<string>? hashHeader);

hash = response.Headers.GetValues("X-RateLimit-Bucket").SingleOrDefault() ?? "UNKNOWN";

if (!RateLimitBucket.TryExtractRateLimitBucket(response.Headers, out RateLimitBucket? extracted))
if (!exemptFromGlobalLimit && hasBucketHeader)
{
return response;
}
hash = hashHeader?.Single();

if(!RateLimitBucket.TryExtractRateLimitBucket(response.Headers, out RateLimitBucket? extracted))
{
return response;
}

this.cache.CreateEntry(route)
this.cache.CreateEntry(route)
.SetValue(extracted.Value)
.Dispose();

this.routeHashes.AddOrUpdate(route, hash, (_, _) => hash);

this.routeHashes.AddOrUpdate(route, hash, (_, _) => hash);
}
return response;
}
}
32 changes: 17 additions & 15 deletions DSharpPlus/Net/Rest/RestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,22 +109,24 @@ TRequest request
{
await this.GlobalRateLimitEvent.WaitAsync();

using HttpRequestMessage req = request.Build();

Context context = new()
{
["route"] = request.Route,
["exempt-from-global-limit"] = request.IsExemptFromGlobalLimit
};

using HttpResponseMessage response = await this.RateLimitPolicy.ExecuteAsync
(
async (_) => await this.HttpClient.SendAsync
(
req,
HttpCompletionOption.ResponseContentRead,
CancellationToken.None
),
async (_) =>
{
using HttpRequestMessage req = request.Build();
return await this.HttpClient.SendAsync
(
req,
HttpCompletionOption.ResponseContentRead,
CancellationToken.None
);
},
context
);

Expand All @@ -135,25 +137,25 @@ TRequest request
_ = response.StatusCode switch
{
HttpStatusCode.BadRequest or HttpStatusCode.MethodNotAllowed =>
throw new BadRequestException(req, response, content),
throw new BadRequestException(request.Build(), response, content),

HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden =>
throw new UnauthorizedException(req, response, content),
throw new UnauthorizedException(request.Build(), response, content),

HttpStatusCode.NotFound =>
throw new NotFoundException(req, response, content),
throw new NotFoundException(request.Build(), response, content),

HttpStatusCode.RequestEntityTooLarge =>
throw new RequestSizeException(req, response, content),
throw new RequestSizeException(request.Build(), response, content),

HttpStatusCode.TooManyRequests =>
throw new RateLimitException(req, response, content),
throw new RateLimitException(request.Build(), response, content),

HttpStatusCode.InternalServerError
or HttpStatusCode.BadGateway
or HttpStatusCode.ServiceUnavailable
or HttpStatusCode.GatewayTimeout =>
throw new ServerErrorException(req, response, content),
throw new ServerErrorException(request.Build(), response, content),

// we need to keep the c# compiler happy, and not all branches can/should throw here.
_ => 0
Expand Down
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all"/>
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
<PackageVersion Include="ConcurrentHashSet" Version="1.3.0" />
<PackageVersion Include="DSharpPlus.VoiceNext.Natives" Version="1.0.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Polly" Version="7.2.3" />
<PackageVersion Include="Polly" Version="8.0.0" />
</ItemGroup>
</Project>