public async Task <IReadOnlyCollection <ISocketMessage> > DownloadAsync(ulong?fromId, Direction dir, int limit) { //TODO: Test heavily, especially the ordering of messages if (limit < 0) { throw new ArgumentOutOfRangeException(nameof(limit)); } if (limit == 0) { return(ImmutableArray <ISocketMessage> .Empty); } var cachedMessages = GetMany(fromId, dir, limit); if (cachedMessages.Count == limit) { return(cachedMessages); } else if (cachedMessages.Count > limit) { return(cachedMessages.Skip(cachedMessages.Count - limit).ToImmutableArray()); } else { var args = new GetChannelMessagesParams { Limit = limit - cachedMessages.Count, RelativeDirection = dir }; if (cachedMessages.Count == 0) { if (fromId != null) { args.RelativeMessageId = fromId.Value; } } else { args.RelativeMessageId = dir == Direction.Before ? cachedMessages[0].Id : cachedMessages[cachedMessages.Count - 1].Id; } var downloadedMessages = await _discord.ApiClient.GetChannelMessagesAsync(_channel.Id, args).ConfigureAwait(false); var guild = (_channel as ISocketGuildChannel)?.Guild; return(cachedMessages.Concat(downloadedMessages.Select(x => { IUser user = _channel.GetUser(x.Author.Value.Id, true); if (user == null) { var newUser = new User(x.Author.Value); if (guild != null) { user = new GuildUser(guild, newUser); } else { user = newUser; } } return Create(user, x); })).ToImmutableArray()); } }