@@ -13,7 +13,7 @@ namespace Discord.Commands | |||
public override async Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | |||
{ | |||
var results = new Dictionary<ulong, TypeReaderValue>(); | |||
IReadOnlyCollection<IUser> channelUsers = (await context.Channel.GetUsersAsync(CacheMode.CacheOnly).Flatten().ConfigureAwait(false)).ToArray(); //TODO: must be a better way? | |||
IAsyncEnumerable<IUser> channelUsers = context.Channel.GetUsersAsync(CacheMode.CacheOnly).Flatten(); // it's better | |||
IReadOnlyCollection<IGuildUser> guildUsers = ImmutableArray.Create<IGuildUser>(); | |||
ulong id; | |||
@@ -45,7 +45,7 @@ namespace Discord.Commands | |||
string username = input.Substring(0, index); | |||
if (ushort.TryParse(input.Substring(index + 1), out ushort discriminator)) | |||
{ | |||
var channelUser = channelUsers.FirstOrDefault(x => x.DiscriminatorValue == discriminator && | |||
var channelUser = await channelUsers.FirstOrDefault(x => x.DiscriminatorValue == discriminator && | |||
string.Equals(username, x.Username, StringComparison.OrdinalIgnoreCase)); | |||
AddResult(results, channelUser as T, channelUser?.Username == username ? 0.85f : 0.75f); | |||
@@ -57,8 +57,9 @@ namespace Discord.Commands | |||
//By Username (0.5-0.6) | |||
{ | |||
foreach (var channelUser in channelUsers.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase))) | |||
AddResult(results, channelUser as T, channelUser.Username == input ? 0.65f : 0.55f); | |||
await channelUsers | |||
.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase)) | |||
.ForEachAsync(channelUser => AddResult(results, channelUser as T, channelUser.Username == input ? 0.65f : 0.55f)); | |||
foreach (var guildUser in guildUsers.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase))) | |||
AddResult(results, guildUser as T, guildUser.Username == input ? 0.60f : 0.50f); | |||
@@ -66,8 +67,9 @@ namespace Discord.Commands | |||
//By Nickname (0.5-0.6) | |||
{ | |||
foreach (var channelUser in channelUsers.Where(x => string.Equals(input, (x as IGuildUser)?.Nickname, StringComparison.OrdinalIgnoreCase))) | |||
AddResult(results, channelUser as T, (channelUser as IGuildUser).Nickname == input ? 0.65f : 0.55f); | |||
await channelUsers | |||
.Where(x => string.Equals(input, (x as IGuildUser)?.Nickname, StringComparison.OrdinalIgnoreCase)) | |||
.ForEachAsync(channelUser => AddResult(results, channelUser as T, (channelUser as IGuildUser).Nickname == input ? 0.65f : 0.55f)); | |||
foreach (var guildUser in guildUsers.Where(x => string.Equals(input, (x as IGuildUser).Nickname, StringComparison.OrdinalIgnoreCase))) | |||
AddResult(results, guildUser as T, (guildUser as IGuildUser).Nickname == input ? 0.60f : 0.50f); | |||
@@ -1,14 +1,64 @@ | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
public static class AsyncEnumerableExtensions | |||
{ | |||
public static async Task<IEnumerable<T>> Flatten<T>(this IAsyncEnumerable<IReadOnlyCollection<T>> source) | |||
/// <summary> | |||
/// Flattens the specified pages into one <see cref="IEnumerable{T}"/> asynchronously | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="source"></param> | |||
/// <returns></returns> | |||
public static async Task<IEnumerable<T>> FlattenAsync<T>(this IAsyncEnumerable<IEnumerable<T>> source) | |||
{ | |||
return (await source.ToArray().ConfigureAwait(false)).SelectMany(x => x); | |||
return await source.Flatten().ToArray().ConfigureAwait(false); | |||
} | |||
public static IAsyncEnumerable<T> Flatten<T>(this IAsyncEnumerable<IEnumerable<T>> source) | |||
{ | |||
return new PagedCollectionEnumerator<T>(source); | |||
} | |||
internal class PagedCollectionEnumerator<T> : IAsyncEnumerator<T>, IAsyncEnumerable<T> | |||
{ | |||
readonly IAsyncEnumerator<IEnumerable<T>> _source; | |||
IEnumerator<T> _enumerator; | |||
public IAsyncEnumerator<T> GetEnumerator() => this; | |||
internal PagedCollectionEnumerator(IAsyncEnumerable<IEnumerable<T>> source) | |||
{ | |||
_source = source.GetEnumerator(); | |||
} | |||
public T Current => _enumerator.Current; | |||
public void Dispose() | |||
{ | |||
_enumerator?.Dispose(); | |||
_source.Dispose(); | |||
} | |||
public async Task<bool> MoveNext(CancellationToken cancellationToken) | |||
{ | |||
cancellationToken.ThrowIfCancellationRequested(); | |||
if(!_enumerator?.MoveNext() ?? true) | |||
{ | |||
if (!await _source.MoveNext(cancellationToken).ConfigureAwait(false)) | |||
return false; | |||
_enumerator?.Dispose(); | |||
_enumerator = _source.Current.GetEnumerator(); | |||
return _enumerator.MoveNext(); | |||
} | |||
return true; | |||
} | |||
} | |||
} | |||
} |
@@ -79,7 +79,7 @@ namespace Discord.Rest | |||
ulong? fromGuildId, int? limit, RequestOptions options) | |||
{ | |||
return new PagedAsyncEnumerable<RestUserGuild>( | |||
DiscordConfig.MaxUsersPerBatch, | |||
DiscordConfig.MaxGuildsPerBatch, | |||
async (info, ct) => | |||
{ | |||
var args = new GetGuildSummariesParams | |||
@@ -106,7 +106,7 @@ namespace Discord.Rest | |||
} | |||
public static async Task<IReadOnlyCollection<RestGuild>> GetGuildsAsync(BaseDiscordClient client, RequestOptions options) | |||
{ | |||
var summaryModels = await GetGuildSummariesAsync(client, null, null, options).Flatten(); | |||
var summaryModels = await GetGuildSummariesAsync(client, null, null, options).FlattenAsync().ConfigureAwait(false); | |||
var guilds = ImmutableArray.CreateBuilder<RestGuild>(); | |||
foreach (var summaryModel in summaryModels) | |||
{ | |||
@@ -413,7 +413,7 @@ namespace Discord.Rest | |||
async Task<IReadOnlyCollection<IGuildUser>> IGuild.GetUsersAsync(CacheMode mode, RequestOptions options) | |||
{ | |||
if (mode == CacheMode.AllowDownload) | |||
return (await GetUsersAsync(options).Flatten().ConfigureAwait(false)).ToImmutableArray(); | |||
return (await GetUsersAsync(options).FlattenAsync().ConfigureAwait(false)).ToImmutableArray(); | |||
else | |||
return ImmutableArray.Create<IGuildUser>(); | |||
} | |||