예제 #1
0
            public async Task <(IReadOnlyDictionary <ulong, int> Data, DateTimeOffset?WhenCached)> GetOrFillAsync(SocketGuild guild, TimeSpan maxAge, Func <double, Task> onProgress = null)
            {
                if (maxAge < TimeSpan.Zero)
                {
                    throw new ArgumentException("Can't be negative", nameof(maxAge));
                }

                using (await _lock.ClaimAsync())
                {
                    if (_data != null && _updated + maxAge > DateTimeOffset.UtcNow && _boundGuildId == guild.Id)
                    {
                        return(_data, _updated);
                    }

                    _data         = new Dictionary <ulong, int>();
                    _updated      = DateTimeOffset.UtcNow;
                    _boundGuildId = guild.Id;

                    foreach (var role in guild.Roles.Select(x => x.Id))
                    {
                        _data[role] = 0;
                    }

                    if (onProgress != null)
                    {
                        await onProgress(0);
                    }

                    var processed = 0;
                    var batches   = 0;
                    await foreach (var batch in guild.GetUsersAsync())
                    {
                        _logger.LogInformation("Fetched {Count} users", batch.Count);
                        foreach (var user in batch)
                        {
                            foreach (var role in user.RoleIds)
                            {
                                if (_data.TryGetValue(role, out var value))
                                {
                                    _data[role] = value + 1;
                                }

                                // No else to track only existing roles (sometimes Discord is stupid and keeps deleted roles on users)
                            }
                        }

                        processed += batch.Count;
                        batches++;
                        if (onProgress != null && batches % 3 == 0)
                        {
                            await onProgress((double)processed / guild.MemberCount);
                        }
                    }

                    return(_data, null);
                }
            }