* Fix Ready and AlwaysDownloadUsers Ready could fire before downloading all guild data and downloading guild users one guild per time without gateway intents is a waste of a gateway request that can support up to 1000. * Reduce batchSize and fix count * Fix typo * Split xml docs line Co-authored-by: Christopher Felegy <cfelegy@riseup.net>pull/1570/head
@@ -21,7 +21,13 @@ namespace Discord.WebSocket | |||||
remove { _disconnectedEvent.Remove(value); } | remove { _disconnectedEvent.Remove(value); } | ||||
} | } | ||||
private readonly AsyncEvent<Func<Exception, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, Task>>(); | private readonly AsyncEvent<Func<Exception, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, Task>>(); | ||||
/// <summary> Fired when guild data has finished downloading. </summary> | |||||
/// <summary> | |||||
/// Fired when guild data has finished downloading. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// It is possible that some guilds might be unsynced if <see cref="DiscordSocketConfig.MaxWaitBetweenGuildAvailablesBeforeReady" /> | |||||
/// was not long enough to receive all GUILD_AVAILABLEs before READY. | |||||
/// </remarks> | |||||
public event Func<Task> Ready | public event Func<Task> Ready | ||||
{ | { | ||||
add { _readyEvent.Add(value); } | add { _readyEvent.Add(value); } | ||||
@@ -169,7 +169,7 @@ namespace Discord.WebSocket | |||||
GuildAvailable += g => | GuildAvailable += g => | ||||
{ | { | ||||
if (ConnectionState == ConnectionState.Connected && AlwaysDownloadUsers && !g.HasAllMembers) | |||||
if (_guildDownloadTask?.IsCompleted == true && ConnectionState == ConnectionState.Connected && AlwaysDownloadUsers && !g.HasAllMembers) | |||||
{ | { | ||||
var _ = g.DownloadUsersAsync(); | var _ = g.DownloadUsersAsync(); | ||||
} | } | ||||
@@ -370,7 +370,7 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
var cachedGuilds = guilds.ToImmutableArray(); | var cachedGuilds = guilds.ToImmutableArray(); | ||||
const short batchSize = 50; | |||||
const short batchSize = 100; //TODO: Gateway Intents will limit to a maximum of 1 guild_id | |||||
ulong[] batchIds = new ulong[Math.Min(batchSize, cachedGuilds.Length)]; | ulong[] batchIds = new ulong[Math.Min(batchSize, cachedGuilds.Length)]; | ||||
Task[] batchTasks = new Task[batchIds.Length]; | Task[] batchTasks = new Task[batchIds.Length]; | ||||
int batchCount = (cachedGuilds.Length + (batchSize - 1)) / batchSize; | int batchCount = (cachedGuilds.Length + (batchSize - 1)) / batchSize; | ||||
@@ -378,7 +378,7 @@ namespace Discord.WebSocket | |||||
for (int i = 0, k = 0; i < batchCount; i++) | for (int i = 0, k = 0; i < batchCount; i++) | ||||
{ | { | ||||
bool isLast = i == batchCount - 1; | bool isLast = i == batchCount - 1; | ||||
int count = isLast ? (batchIds.Length - (batchCount - 1) * batchSize) : batchSize; | |||||
int count = isLast ? (cachedGuilds.Length - (batchCount - 1) * batchSize) : batchSize; | |||||
for (int j = 0; j < count; j++, k++) | for (int j = 0; j < count; j++, k++) | ||||
{ | { | ||||
@@ -578,6 +578,9 @@ namespace Discord.WebSocket | |||||
} | } | ||||
else if (_connection.CancelToken.IsCancellationRequested) | else if (_connection.CancelToken.IsCancellationRequested) | ||||
return; | return; | ||||
if (BaseConfig.AlwaysDownloadUsers) | |||||
_ = DownloadUsersAsync(Guilds.Where(x => x.IsAvailable && !x.HasAllMembers)); | |||||
await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false); | await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false); | ||||
await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false); | await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false); | ||||
@@ -1772,7 +1775,7 @@ namespace Discord.WebSocket | |||||
try | try | ||||
{ | { | ||||
await logger.DebugAsync("GuildDownloader Started").ConfigureAwait(false); | await logger.DebugAsync("GuildDownloader Started").ConfigureAwait(false); | ||||
while ((_unavailableGuildCount != 0) && (Environment.TickCount - _lastGuildAvailableTime < 2000)) | |||||
while ((_unavailableGuildCount != 0) && (Environment.TickCount - _lastGuildAvailableTime < BaseConfig.MaxWaitBetweenGuildAvailablesBeforeReady)) | |||||
await Task.Delay(500, cancelToken).ConfigureAwait(false); | await Task.Delay(500, cancelToken).ConfigureAwait(false); | ||||
await logger.DebugAsync("GuildDownloader Stopped").ConfigureAwait(false); | await logger.DebugAsync("GuildDownloader Stopped").ConfigureAwait(false); | ||||
} | } | ||||
@@ -126,6 +126,31 @@ namespace Discord.WebSocket | |||||
public bool GuildSubscriptions { get; set; } = true; | public bool GuildSubscriptions { get; set; } = true; | ||||
/// <summary> | /// <summary> | ||||
/// Gets or sets the maximum wait time in milliseconds between GUILD_AVAILABLE events before firing READY. | |||||
/// | |||||
/// If zero, READY will fire as soon as it is received and all guilds will be unavailable. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// <para>This property is measured in milliseconds, negative values will throw an exception.</para> | |||||
/// <para>If a guild is not received before READY, it will be unavailable.</para> | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// The maximum wait time in milliseconds between GUILD_AVAILABLE events before firing READY. | |||||
/// </returns> | |||||
/// <exception cref="System.ArgumentException">Value must be at least 0.</exception> | |||||
public int MaxWaitBetweenGuildAvailablesBeforeReady { | |||||
get | |||||
{ | |||||
return _maxWaitForGuildAvailable; | |||||
} | |||||
set | |||||
{ | |||||
Preconditions.AtLeast(value, 0, nameof(MaxWaitBetweenGuildAvailablesBeforeReady)); | |||||
_maxWaitForGuildAvailable = value; | |||||
} | |||||
} | |||||
private int _maxWaitForGuildAvailable = 10000; | |||||
/// Gets or sets gateway intents to limit what events are sent from Discord. Allows for more granular control than the <see cref="GuildSubscriptions"/> property. | /// Gets or sets gateway intents to limit what events are sent from Discord. Allows for more granular control than the <see cref="GuildSubscriptions"/> property. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||