diff --git a/src/Discord.Net.Core/DiscordConfig.cs b/src/Discord.Net.Core/DiscordConfig.cs
index 1db3271e5..5cdf6a77e 100644
--- a/src/Discord.Net.Core/DiscordConfig.cs
+++ b/src/Discord.Net.Core/DiscordConfig.cs
@@ -1,4 +1,4 @@
-using System.Reflection;
+using System.Reflection;
namespace Discord
{
@@ -20,6 +20,7 @@ namespace Discord
public const int MaxMessagesPerBatch = 100;
public const int MaxUsersPerBatch = 1000;
public const int MaxGuildsPerBatch = 100;
+ public const int MaxUserReactionsPerBatch = 100;
public const int MaxAuditLogEntriesPerBatch = 100;
/// Gets or sets how a request should act in the case of an error, by default.
diff --git a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs
index 52df187f8..36ee725ff 100644
--- a/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs
+++ b/src/Discord.Net.Core/Entities/Messages/IUserMessage.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -23,7 +23,7 @@ namespace Discord
/// Removes all reactions from this message.
Task RemoveAllReactionsAsync(RequestOptions options = null);
/// Gets all users that reacted to a message with a given emote
- Task> GetReactionUsersAsync(IEmote emoji, int limit = 100, ulong? afterUserId = null, RequestOptions options = null);
+ IAsyncEnumerable> GetReactionUsersAsync(IEmote emoji, int limit, RequestOptions options = null);
/// Transforms this message's text into a human readable form by resolving its tags.
string Resolve(
diff --git a/src/Discord.Net.Rest/API/Rest/GetReactionUsersParams.cs b/src/Discord.Net.Rest/API/Rest/GetReactionUsersParams.cs
index d70da5632..a0967bb75 100644
--- a/src/Discord.Net.Rest/API/Rest/GetReactionUsersParams.cs
+++ b/src/Discord.Net.Rest/API/Rest/GetReactionUsersParams.cs
@@ -1,4 +1,4 @@
-namespace Discord.API.Rest
+namespace Discord.API.Rest
{
internal class GetReactionUsersParams
{
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index 8b641fb6a..85e04f962 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -618,11 +618,11 @@ namespace Discord.API
Preconditions.NotNullOrWhitespace(emoji, nameof(emoji));
Preconditions.NotNull(args, nameof(args));
Preconditions.GreaterThan(args.Limit, 0, nameof(args.Limit));
- Preconditions.AtMost(args.Limit, DiscordConfig.MaxUsersPerBatch, nameof(args.Limit));
+ Preconditions.AtMost(args.Limit, DiscordConfig.MaxUserReactionsPerBatch, nameof(args.Limit));
Preconditions.GreaterThan(args.AfterUserId, 0, nameof(args.AfterUserId));
options = RequestOptions.CreateOrClone(options);
- int limit = args.Limit.GetValueOrDefault(int.MaxValue);
+ int limit = args.Limit.GetValueOrDefault(DiscordConfig.MaxUserReactionsPerBatch);
ulong afterUserId = args.AfterUserId.GetValueOrDefault(0);
var ids = new BucketIds(channelId: channelId);
diff --git a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
index 8ae41cc37..f7ce3ded0 100644
--- a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
@@ -46,13 +46,38 @@ namespace Discord.Rest
await client.ApiClient.RemoveAllReactionsAsync(msg.Channel.Id, msg.Id, options);
}
- public static async Task> GetReactionUsersAsync(IMessage msg, IEmote emote,
- Action func, BaseDiscordClient client, RequestOptions options)
+ public static IAsyncEnumerable> GetReactionUsersAsync(IMessage msg, IEmote emote,
+ int? limit, BaseDiscordClient client, RequestOptions options)
{
- var args = new GetReactionUsersParams();
- func(args);
- string emoji = (emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name);
- return (await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false)).Select(u => RestUser.Create(client, u)).ToImmutableArray();
+ Preconditions.NotNull(emote, nameof(emote));
+ var emoji = (emote is Emote e ? $"{e.Name}:{e.Id}" : emote.Name);
+
+ return new PagedAsyncEnumerable(
+ DiscordConfig.MaxUserReactionsPerBatch,
+ async (info, ct) =>
+ {
+ var args = new GetReactionUsersParams
+ {
+ Limit = info.PageSize
+ };
+
+ if (info.Position != null)
+ args.AfterUserId = info.Position.Value;
+
+ var models = await client.ApiClient.GetReactionUsersAsync(msg.Channel.Id, msg.Id, emoji, args, options).ConfigureAwait(false);
+ return models.Select(x => RestUser.Create(client, x)).ToImmutableArray();
+ },
+ nextPage: (info, lastPage) =>
+ {
+ if (lastPage.Count != DiscordConfig.MaxUsersPerBatch)
+ return false;
+
+ info.Position = lastPage.Max(x => x.Id);
+ return true;
+ },
+ count: limit
+ );
+
}
public static async Task PinAsync(IMessage msg, BaseDiscordClient client,
diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
index 0d1f3be2b..7354cc4af 100644
--- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
@@ -136,8 +136,8 @@ namespace Discord.Rest
=> MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options);
public Task RemoveAllReactionsAsync(RequestOptions options = null)
=> MessageHelper.RemoveAllReactionsAsync(this, Discord, options);
- public Task> GetReactionUsersAsync(IEmote emote, int limit = 100, ulong? afterUserId = null, RequestOptions options = null)
- => MessageHelper.GetReactionUsersAsync(this, emote, x => { x.Limit = limit; x.AfterUserId = afterUserId ?? Optional.Create(); }, Discord, options);
+ public IAsyncEnumerable> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null)
+ => MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options);
public Task PinAsync(RequestOptions options = null)
diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
index 5489ad2bb..f8c15a986 100644
--- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
+++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
@@ -130,8 +130,8 @@ namespace Discord.WebSocket
=> MessageHelper.RemoveReactionAsync(this, user, emote, Discord, options);
public Task RemoveAllReactionsAsync(RequestOptions options = null)
=> MessageHelper.RemoveAllReactionsAsync(this, Discord, options);
- public Task> GetReactionUsersAsync(IEmote emote, int limit = 100, ulong? afterUserId = null, RequestOptions options = null)
- => MessageHelper.GetReactionUsersAsync(this, emote, x => { x.Limit = limit; x.AfterUserId = afterUserId ?? Optional.Create(); }, Discord, options);
+ public IAsyncEnumerable> GetReactionUsersAsync(IEmote emote, int limit, RequestOptions options = null)
+ => MessageHelper.GetReactionUsersAsync(this, emote, limit, Discord, options);
public Task PinAsync(RequestOptions options = null)
=> MessageHelper.PinAsync(this, Discord, options);