API: implement #77

This commit is contained in:
mavolin 2020-05-17 01:35:57 +02:00
parent ff8ebcbacf
commit b3fabae701
No known key found for this signature in database
GPG Key ID: D8681218EDF216DF
4 changed files with 270 additions and 119 deletions

View File

@ -103,29 +103,95 @@ func (c *Client) GuildWithCount(id discord.Snowflake) (*discord.Guild, error) {
)
}
// Guilds returns all guilds, automatically paginating. Be careful, as this
// method may abuse the API by requesting thousands or millions of guilds. For
// lower-level access, use GuildsRange. Guilds returned have some fields
// filled only (ID, Name, Icon, Owner, Permissions).
// Guilds returns a list of partial guild objects the current user is a member
// of. This method automatically paginates until it reaches the passed limit,
// or, if the limit is set to 0, has fetched all guilds within the passed
// range.
//
// Max can be 0, in which case the function will try and fetch all guilds.
func (c *Client) Guilds(max uint) ([]discord.Guild, error) {
var guilds []discord.Guild
var after discord.Snowflake = 0
// As the underlying endpoint has a maximum of 100 guilds per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more guilds are available.
//
// When fetching the guilds, those with the smallest ID will be fetched first.
//
// Also note that 100 is the maximum number of guilds a non-bot user can join.
// Therefore, pagination is not needed for integrations that need to get a list
// of the users' guilds.
//
// Requires the guilds OAuth2 scope.
func (c *Client) Guilds(limit uint) ([]discord.Guild, error) {
return c.GuildsAfter(0, limit)
}
// GuildsBefore returns a list of partial guild objects the current user is a
// member of. This method automatically paginates until it reaches the
// passed limit, or, if the limit is set to 0, has fetched all guilds within
// the passed range.
//
// As the underlying endpoint has a maximum of 100 guilds per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more guilds are available.
//
// Requires the guilds OAuth2 scope.
func (c *Client) GuildsBefore(before discord.Snowflake, limit uint) ([]discord.Guild, error) {
var guilds []discord.Guild
// this is the limit of max guilds per request,as imposed by Discord
const hardLimit int = 100
unlimited := max == 0
unlimited := limit == 0
for fetch := uint(hardLimit); max > 0 || unlimited; fetch = uint(hardLimit) {
if max > 0 {
if fetch > max {
fetch = max
for fetch := uint(hardLimit); limit > 0 || unlimited; fetch = uint(hardLimit) {
if limit > 0 {
if fetch > limit {
fetch = limit
}
max -= fetch
limit -= fetch
}
g, err := c.GuildsAfter(after, fetch)
g, err := c.guildsRange(before, 0, fetch)
if err != nil {
return guilds, err
}
guilds = append(g, guilds...)
if len(g) < hardLimit {
break
}
before = g[0].ID
}
return guilds, nil
}
// GuildsAfter returns a list of partial guild objects the current user is a
// member of. This method automatically paginates until it reaches the
// passed limit, or, if the limit is set to 0, has fetched all guilds within
// the passed range.
//
// As the underlying endpoint has a maximum of 100 guilds per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more guilds are available.
//
// Requires the guilds OAuth2 scope.
func (c *Client) GuildsAfter(after discord.Snowflake, limit uint) ([]discord.Guild, error) {
var guilds []discord.Guild
// this is the limit of max guilds per request, as imposed by Discord
const hardLimit int = 100
unlimited := limit == 0
for fetch := uint(hardLimit); limit > 0 || unlimited; fetch = uint(hardLimit) {
if limit > 0 {
if fetch > limit {
fetch = limit
}
limit -= fetch
}
g, err := c.guildsRange(0, after, fetch)
if err != nil {
return guilds, err
}
@ -141,29 +207,8 @@ func (c *Client) Guilds(max uint) ([]discord.Guild, error) {
return guilds, nil
}
// GuildsBefore fetches guilds before the specified ID. Check GuildsRange.
func (c *Client) GuildsBefore(before discord.Snowflake, limit uint) ([]discord.Guild, error) {
return c.GuildsRange(before, 0, limit)
}
// GuildsAfter fetches guilds after the specified ID. Check GuildsRange.
func (c *Client) GuildsAfter(after discord.Snowflake, limit uint) ([]discord.Guild, error) {
return c.GuildsRange(0, after, limit)
}
// GuildsRange returns a list of partial guild objects the current user is a
// member of. Requires the guilds OAuth2 scope.
//
// This endpoint returns 100 guilds by default, which is the maximum number
// of guilds a non-bot user can join. Therefore, pagination is not needed
// for integrations that need to get a list of the users' guilds.
func (c *Client) GuildsRange(before, after discord.Snowflake, limit uint) ([]discord.Guild, error) {
switch {
case limit == 0:
limit = 100
case limit > 100:
limit = 100
}
func (c *Client) guildsRange(
before, after discord.Snowflake, limit uint) ([]discord.Guild, error) {
var param struct {
Before discord.Snowflake `schema:"before,omitempty"`

View File

@ -12,33 +12,50 @@ func (c *Client) Member(guildID, userID discord.Snowflake) (*discord.Member, err
return m, c.RequestJSON(&m, "GET", EndpointGuilds+guildID.String()+"/members/"+userID.String())
}
// Members returns members until it reaches max. This function automatically
// paginates, meaning the normal 1000 limit is handled internally.
// Members returns a list of members of the guild with the passed id. This
// method automatically paginates until it reaches the passed limit, or, if the
// limit is set to 0, has fetched all members within the passed range.
//
// Max can be 0, in which case the function will try and fetch all members.
func (c *Client) Members(guildID discord.Snowflake, max uint) ([]discord.Member, error) {
// As the underlying endpoint has a maximum of 1000 members per request, at
// maximum a total of limit/1000 rounded up requests will be made, although
// they may be less, if no more members are available.
//
// When fetching the members, those with the smallest ID will be fetched first.
func (c *Client) Members(guildID discord.Snowflake, limit uint) ([]discord.Member, error) {
return c.MembersAfter(guildID, 0, limit)
}
// MembersAfter returns a list of members of the guild with the passed id. This
// method automatically paginates until it reaches the passed limit, or, if the
// limit is set to 0, has fetched all members within the passed range.
//
// As the underlying endpoint has a maximum of 1000 members per request, at
// maximum a total of limit/1000 rounded up requests will be made, although
// they may be less, if no more members are available.
func (c *Client) MembersAfter(
guildID, after discord.Snowflake, limit uint) ([]discord.Member, error) {
var mems []discord.Member
var after discord.Snowflake = 0
const hardLimit int = 1000
unlimited := max == 0
unlimited := limit == 0
for fetch := uint(hardLimit); max > 0 || unlimited; fetch = uint(hardLimit) {
if max > 0 {
if fetch > max {
fetch = max
for fetch := uint(hardLimit); limit > 0 || unlimited; fetch = uint(hardLimit) {
if limit > 0 {
if fetch > limit {
fetch = limit
}
max -= fetch
limit -= fetch
}
m, err := c.MembersAfter(guildID, after, fetch)
m, err := c.membersAfter(guildID, after, fetch)
if err != nil {
return mems, err
}
mems = append(mems, m...)
// There aren't any to fetch, even if this is less than max.
// There aren't any to fetch, even if this is less than limit.
if len(mems) < hardLimit {
break
}
@ -49,9 +66,7 @@ func (c *Client) Members(guildID discord.Snowflake, max uint) ([]discord.Member,
return mems, nil
}
// MembersAfter returns a list of all guild members, from 1-1000 for limits. The
// default limit is 1 and the maximum limit is 1000.
func (c *Client) MembersAfter(
func (c *Client) membersAfter(
guildID, after discord.Snowflake, limit uint) ([]discord.Member, error) {
switch {

View File

@ -6,25 +6,93 @@ import (
"github.com/diamondburned/arikawa/utils/json/option"
)
// Messages gets all messages, automatically paginating. Use with care, as
// this could get as many as hundred thousands of messages, making a lot of
// queries.
// Messages returns a list of messages sent in the channel with the passed ID.
// This method automatically paginates until it reaches the passed limit, or,
// if the limit is set to 0, has fetched all guilds within the passed ange.
//
// Max can be 0, in which case the function will try and fetch all messages.
func (c *Client) Messages(channelID discord.Snowflake, max uint) ([]discord.Message, error) {
var msgs []discord.Message
var after discord.Snowflake = 0
// As the underlying endpoint has a maximum of 100 messages per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more messages are available.
//
// When fetching the messages, those with the smallest ID will be fetched
// first.
func (c *Client) Messages(channelID discord.Snowflake, limit uint) ([]discord.Message, error) {
return c.MessagesAfter(channelID, 0, limit)
}
// MessagesAround returns messages around the ID, with a limit of 100.
func (c *Client) MessagesAround(
channelID, around discord.Snowflake, limit uint) ([]discord.Message, error) {
return c.messagesRange(channelID, 0, 0, around, limit)
}
// MessagesBefore returns a list messages sent in the channel with the passed
// ID. This method automatically paginates until it reaches the passed limit,
// or, if the limit is set to 0, has fetched all guilds within the passed
// range.
//
// As the underlying endpoint has a maximum of 100 messages per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more messages are available.
func (c *Client) MessagesBefore(
channelID, before discord.Snowflake, limit uint) ([]discord.Message, error) {
var msgs []discord.Message
// this is the limit of max messages per request, as imposed by Discord
const hardLimit int = 100
unlimited := max == 0
unlimited := limit == 0
for fetch := uint(hardLimit); max > 0 || unlimited; fetch = uint(hardLimit) {
if max > 0 {
if fetch > max {
fetch = max
for fetch := uint(hardLimit); limit > 0 || unlimited; fetch = uint(hardLimit) {
if limit > 0 {
if fetch > limit {
fetch = limit
}
max -= fetch
limit -= fetch
}
m, err := c.messagesRange(channelID, before, 0, 0, fetch)
if err != nil {
return msgs, err
}
msgs = append(m, msgs...)
if len(m) < hardLimit {
break
}
before = m[0].Author.ID
}
return msgs, nil
}
// MessagesAfter returns a list messages sent in the channel with the passed
// ID. This method automatically paginates until it reaches the passed limit,
// or, if the limit is set to 0, has fetched all guilds within the passed
// range.
//
// As the underlying endpoint has a maximum of 100 messages per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more messages are available.
func (c *Client) MessagesAfter(
channelID, after discord.Snowflake, limit uint) ([]discord.Message, error) {
var msgs []discord.Message
// this is the limit of max messages per request, as imposed by Discord
const hardLimit int = 100
unlimited := limit == 0
for fetch := uint(hardLimit); limit > 0 || unlimited; fetch = uint(hardLimit) {
if limit > 0 {
if fetch > limit {
fetch = limit
}
limit -= fetch
}
m, err := c.messagesRange(channelID, 0, after, 0, fetch)
@ -43,30 +111,8 @@ func (c *Client) Messages(channelID discord.Snowflake, max uint) ([]discord.Mess
return msgs, nil
}
// MessagesAround returns messages around the ID, with a limit of 1-100.
func (c *Client) MessagesAround(
channelID, around discord.Snowflake, limit uint) ([]discord.Message, error) {
return c.messagesRange(channelID, 0, 0, around, limit)
}
// MessagesBefore returns messages before the ID, with a limit of 1-100.
func (c *Client) MessagesBefore(
channelID, before discord.Snowflake, limit uint) ([]discord.Message, error) {
return c.messagesRange(channelID, before, 0, 0, limit)
}
// MessagesAfter returns messages after the ID, with a limit of 1-100.
func (c *Client) MessagesAfter(
channelID, after discord.Snowflake, limit uint) ([]discord.Message, error) {
return c.messagesRange(channelID, 0, after, 0, limit)
}
func (c *Client) messagesRange(
channelID, before, after, around discord.Snowflake,
limit uint) ([]discord.Message, error) {
channelID, before, after, around discord.Snowflake, limit uint) ([]discord.Message, error) {
switch {
case limit == 0:

View File

@ -25,27 +25,88 @@ func (c *Client) Unreact(chID, msgID discord.Snowflake, emoji Emoji) error {
return c.DeleteUserReaction(chID, msgID, 0, emoji)
}
// Reactions returns reactions up to the specified limit. It will paginate
// automatically.
// Reactions returns a list of users that reacted with the passed Emoji. This
// method automatically paginates until it reaches the passed limit, or, if the
// limit is set to 0, has fetched all users within the passed range.
//
// Max can be 0, in which case the function will try and fetch all reactions.
// As the underlying endpoint has a maximum of 100 users per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more guilds are available.
//
// When fetching the users, those with the smallest ID will be fetched first.
func (c *Client) Reactions(
channelID, messageID discord.Snowflake, max uint, emoji Emoji) ([]discord.User, error) {
channelID, messageID discord.Snowflake, limit uint, emoji Emoji) ([]discord.User, error) {
return c.ReactionsAfter(channelID, messageID, 0, limit, emoji)
}
// ReactionsBefore returns a list of users that reacted with the passed Emoji.
// This method automatically paginates until it reaches the passed limit, or,
// if the limit is set to 0, has fetched all users within the passed range.
//
// As the underlying endpoint has a maximum of 100 users per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more guilds are available.
func (c *Client) ReactionsBefore(
channelID, messageID, before discord.Snowflake,
limit uint, emoji Emoji) ([]discord.User, error) {
var users []discord.User
var after discord.Snowflake = 0
const hardLimit int = 100
for fetch := uint(hardLimit); max > 0; fetch = uint(hardLimit) {
if max > 0 {
if fetch > max {
fetch = max
unlimited := limit == 0
for fetch := uint(hardLimit); limit > 0 || unlimited; fetch = uint(hardLimit) {
if limit > 0 {
if fetch > limit {
fetch = limit
}
max -= fetch
limit -= fetch
}
r, err := c.ReactionsRange(channelID, messageID, 0, after, fetch, emoji)
r, err := c.reactionsRange(channelID, messageID, before, 0, fetch, emoji)
if err != nil {
return users, err
}
users = append(users, r...)
if len(r) < hardLimit {
break
}
before = r[0].ID
}
return users, nil
}
// ReactionsAfter returns a list of users that reacted with the passed Emoji.
// This method automatically paginates until it reaches the passed limit, or,
// if the limit is set to 0, has fetched all users within the passed range.
//
// As the underlying endpoint has a maximum of 100 users per request, at
// maximum a total of limit/100 rounded up requests will be made, although they
// may be less, if no more guilds are available.
func (c *Client) ReactionsAfter(
channelID, messageID, after discord.Snowflake, limit uint, emoji Emoji,
) ([]discord.User, error) {
var users []discord.User
const hardLimit int = 100
unlimited := limit == 0
for fetch := uint(hardLimit); limit > 0 || unlimited; fetch = uint(hardLimit) {
if limit > 0 {
if fetch > limit {
fetch = limit
}
limit -= fetch
}
r, err := c.reactionsRange(channelID, messageID, 0, after, fetch, emoji)
if err != nil {
return users, err
}
@ -61,25 +122,9 @@ func (c *Client) Reactions(
return users, nil
}
// ReactionsBefore gets all reactions before the passed user ID.
func (c *Client) ReactionsBefore(
channelID, messageID, before discord.Snowflake,
limit uint, emoji Emoji) ([]discord.User, error) {
return c.ReactionsRange(channelID, messageID, before, 0, limit, emoji)
}
// Refer to ReactionsRange.
func (c *Client) ReactionsAfter(
channelID, messageID, after discord.Snowflake,
limit uint, emoji Emoji) ([]discord.User, error) {
return c.ReactionsRange(channelID, messageID, 0, after, limit, emoji)
}
// ReactionsRange get users before and after IDs. Before, after, and limit are
// reactionsRange get users before and after IDs. Before, after, and limit are
// optional. A maximum limit of only 100 reactions could be returned.
func (c *Client) ReactionsRange(
func (c *Client) reactionsRange(
channelID, messageID, before, after discord.Snowflake,
limit uint, emoji Emoji) ([]discord.User, error) {