Added initial work for member downloading
This commit is contained in:
@@ -367,6 +367,10 @@ namespace Discord.API
|
||||
{
|
||||
await SendGateway(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false);
|
||||
}
|
||||
public async Task SendRequestMembers(IEnumerable<ulong> guildIds, RequestOptions options = null)
|
||||
{
|
||||
await SendGateway(GatewayOpCode.RequestGuildMembers, new RequestMembersParams { GuildIds = guildIds, Query = "", Limit = 0 }, options: options).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//Channels
|
||||
public async Task<Channel> GetChannel(ulong channelId, RequestOptions options = null)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Discord.API.Gateway
|
||||
{
|
||||
public class RequestMembersParams
|
||||
{
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong[] GuildId { get; set; }
|
||||
public IEnumerable<ulong> GuildIds { get; set; }
|
||||
[JsonProperty("query")]
|
||||
public string Query { get; set; }
|
||||
[JsonProperty("limit")]
|
||||
|
||||
@@ -17,9 +17,8 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
//TODO: Remove unnecessary `as` casts
|
||||
//TODO: Add event docstrings
|
||||
//TODO: Add reconnect logic (+ensure the heartbeat task shuts down)
|
||||
//TODO: Add reconnect logic (+ensure the heartbeat task to shut down)
|
||||
//TODO: Add resume logic
|
||||
public class DiscordSocketClient : DiscordClient, IDiscordClient
|
||||
{
|
||||
@@ -32,7 +31,7 @@ namespace Discord
|
||||
public event Func<IMessage, IMessage, Task> MessageUpdated;
|
||||
public event Func<IRole, Task> RoleCreated, RoleDeleted;
|
||||
public event Func<IRole, IRole, Task> RoleUpdated;
|
||||
public event Func<IGuild, Task> JoinedGuild, LeftGuild, GuildAvailable, GuildUnavailable;
|
||||
public event Func<IGuild, Task> JoinedGuild, LeftGuild, GuildAvailable, GuildUnavailable, GuildDownloadedMembers;
|
||||
public event Func<IGuild, IGuild, Task> GuildUpdated;
|
||||
public event Func<IUser, Task> UserJoined, UserLeft, UserBanned, UserUnbanned;
|
||||
public event Func<IUser, IUser, Task> UserUpdated;
|
||||
@@ -305,6 +304,47 @@ namespace Discord
|
||||
return user;
|
||||
}
|
||||
|
||||
/// <summary> Downloads the members list for all large guilds. </summary>
|
||||
public Task DownloadAllMembers()
|
||||
=> DownloadMembers(DataStore.Guilds.Where(x => !x.HasAllMembers));
|
||||
/// <summary> Downloads the members list for the provided guilds, if they don't have a complete list. </summary>
|
||||
public async Task DownloadMembers(IEnumerable<IGuild> guilds)
|
||||
{
|
||||
const short batchSize = 50;
|
||||
var cachedGuilds = guilds.Select(x => x as CachedGuild).ToArray();
|
||||
if (cachedGuilds.Length == 0)
|
||||
return;
|
||||
else if (cachedGuilds.Length == 1)
|
||||
{
|
||||
await cachedGuilds[0].DownloadMembers().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ulong[] batchIds = new ulong[Math.Min(batchSize, cachedGuilds.Length)];
|
||||
Task[] batchTasks = new Task[batchIds.Length];
|
||||
int batchCount = (cachedGuilds.Length + (batchSize - 1)) / batchSize;
|
||||
|
||||
for (int i = 0, k = 0; i < batchCount; i++)
|
||||
{
|
||||
bool isLast = i == batchCount - 1;
|
||||
int count = isLast ? (batchIds.Length - (batchCount - 1) * batchSize) : batchSize;
|
||||
|
||||
for (int j = 0; j < count; j++, k++)
|
||||
{
|
||||
var guild = cachedGuilds[k];
|
||||
batchIds[j] = guild.Id;
|
||||
batchTasks[j] = guild.DownloaderPromise;
|
||||
}
|
||||
|
||||
ApiClient.SendRequestMembers(batchIds);
|
||||
|
||||
if (isLast && batchCount > 1)
|
||||
await Task.WhenAll(batchTasks.Take(count)).ConfigureAwait(false);
|
||||
else
|
||||
await Task.WhenAll(batchTasks).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessMessage(GatewayOpCode opCode, int? seq, string type, object payload)
|
||||
{
|
||||
if (seq != null)
|
||||
@@ -367,11 +407,8 @@ namespace Discord
|
||||
type = "GUILD_AVAILABLE";
|
||||
else
|
||||
await JoinedGuild.Raise(guild).ConfigureAwait(false);
|
||||
|
||||
if (!data.Large)
|
||||
await GuildAvailable.Raise(guild);
|
||||
else
|
||||
_largeGuilds.Enqueue(data.Id);
|
||||
|
||||
await GuildAvailable.Raise(guild);
|
||||
}
|
||||
break;
|
||||
case "GUILD_UPDATE":
|
||||
@@ -781,15 +818,19 @@ namespace Discord
|
||||
}
|
||||
private async Task RunHeartbeat(int intervalMillis, CancellationToken cancelToken)
|
||||
{
|
||||
var state = ConnectionState;
|
||||
while (state == ConnectionState.Connecting || state == ConnectionState.Connected)
|
||||
try
|
||||
{
|
||||
//if (_heartbeatTime != 0) //TODO: Connection lost, reconnect
|
||||
var state = ConnectionState;
|
||||
while (state == ConnectionState.Connecting || state == ConnectionState.Connected)
|
||||
{
|
||||
//if (_heartbeatTime != 0) //TODO: Connection lost, reconnect
|
||||
|
||||
_heartbeatTime = Environment.TickCount;
|
||||
await ApiClient.SendHeartbeat(_lastSeq).ConfigureAwait(false);
|
||||
await Task.Delay(intervalMillis, cancelToken).ConfigureAwait(false);
|
||||
_heartbeatTime = Environment.TickCount;
|
||||
await ApiClient.SendHeartbeat(_lastSeq).ConfigureAwait(false);
|
||||
await Task.Delay(intervalMillis, cancelToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,6 +306,7 @@ namespace Discord
|
||||
IRole IGuild.EveryoneRole => EveryoneRole;
|
||||
IReadOnlyCollection<Emoji> IGuild.Emojis => Emojis;
|
||||
IReadOnlyCollection<string> IGuild.Features => Features;
|
||||
Task IGuild.DownloadUsers() { throw new NotSupportedException(); }
|
||||
|
||||
IRole IGuild.GetRole(ulong id) => GetRole(id);
|
||||
}
|
||||
|
||||
@@ -90,6 +90,9 @@ namespace Discord
|
||||
Task<IGuildUser> GetUser(ulong id);
|
||||
/// <summary> Gets the current user for this guild. </summary>
|
||||
Task<IGuildUser> GetCurrentUser();
|
||||
/// <summary> Downloads all users for this guild if the current list is incomplete. </summary>
|
||||
Task DownloadUsers();
|
||||
/// <summary> Removes all users from this guild if they have not logged on in a provided number of days or, if simulate is true, returns the number of users that would be removed. </summary>
|
||||
Task<int> PruneUsers(int days = 30, bool simulate = false);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ namespace Discord
|
||||
{
|
||||
internal class CachedGuild : Guild, ICachedEntity<ulong>
|
||||
{
|
||||
private TaskCompletionSource<bool> _downloaderPromise;
|
||||
private ConcurrentHashSet<ulong> _channels;
|
||||
private ConcurrentDictionary<ulong, CachedGuildUser> _members;
|
||||
private ConcurrentDictionary<ulong, Presence> _presences;
|
||||
@@ -23,6 +24,9 @@ namespace Discord
|
||||
|
||||
public bool Available { get; private set; } //TODO: Add to IGuild
|
||||
|
||||
public bool HasAllMembers => _downloaderPromise.Task.IsCompleted;
|
||||
public Task DownloaderPromise => _downloaderPromise.Task;
|
||||
|
||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||
public CachedGuildUser CurrentUser => GetCachedUser(Discord.CurrentUser.Id);
|
||||
public IReadOnlyCollection<ICachedGuildChannel> Channels => _channels.Select(x => GetCachedChannel(x)).ToReadOnlyCollection(_channels);
|
||||
@@ -30,6 +34,7 @@ namespace Discord
|
||||
|
||||
public CachedGuild(DiscordSocketClient discord, Model model) : base(discord, model)
|
||||
{
|
||||
_downloaderPromise = new TaskCompletionSource<bool>();
|
||||
}
|
||||
|
||||
public void Update(ExtendedModel model, UpdateSource source, DataStore dataStore)
|
||||
@@ -79,6 +84,9 @@ namespace Discord
|
||||
{
|
||||
for (int i = 0; i < model.Members.Length; i++)
|
||||
AddCachedUser(model.Members[i], members, dataStore);
|
||||
_downloaderPromise = new TaskCompletionSource<bool>();
|
||||
if (!model.Large)
|
||||
_downloaderPromise.SetResult(true);
|
||||
}
|
||||
_members = members;
|
||||
}
|
||||
@@ -153,6 +161,17 @@ namespace Discord
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task DownloadMembers()
|
||||
{
|
||||
if (!HasAllMembers)
|
||||
await Discord.ApiClient.SendRequestMembers(new ulong[] { Id }).ConfigureAwait(false);
|
||||
await _downloaderPromise.Task.ConfigureAwait(false);
|
||||
}
|
||||
public void CompleteDownloadMembers()
|
||||
{
|
||||
_downloaderPromise.SetResult(true);
|
||||
}
|
||||
|
||||
public CachedGuild Clone() => MemberwiseClone() as CachedGuild;
|
||||
|
||||
new internal ICachedGuildChannel ToChannel(ChannelModel model)
|
||||
|
||||
Reference in New Issue
Block a user