1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-30 10:43:30 +00:00

Moved Discord structs to package discord

This commit is contained in:
diamondburned 2020-01-02 11:53:08 -08:00
parent 09d9651507
commit e41a2c7c42
22 changed files with 433 additions and 430 deletions

View file

@ -8,80 +8,13 @@ import (
const EndpointChannels = Endpoint + "channels/"
type Channel struct {
ID discord.Snowflake `json:"id,string"`
Type ChannelType `json:"type"`
// Fields below may not appear
GuildID discord.Snowflake `json:"guild_id,string,omitempty"`
Position int `json:"position,omitempty"`
Name string `json:"name,omitempty"` // 2-100 chars
Topic string `json:"topic,omitempty"` // 0-1024 chars
NSFW bool `json:"nsfw"`
Icon discord.Hash `json:"icon,omitempty"`
// Direct Messaging fields
DMOwnerID discord.Snowflake `json:"owner_id,omitempty"`
DMRecipients []User `json:"recipients,omitempty"`
// AppID of the group DM creator if it's bot-created
AppID discord.Snowflake `json:"application_id,omitempty"`
// ID of the category the channel is in, if any.
CategoryID discord.Snowflake `json:"parent_id,omitempty"`
LastPinTime discord.Timestamp `json:"last_pin_timestamp,omitempty"`
// Explicit permission overrides for members and roles.
Permissions []Overwrite `json:"permission_overwrites,omitempty"`
// ID of the last message, may not point to a valid one.
LastMessageID discord.Snowflake `json:"last_message_id,omitempty"`
// Slow mode duration. Bots and people with "manage_messages" or
// "manage_channel" permissions are unaffected.
UserRateLimit discord.Seconds `json:"rate_limit_per_user,omitempty"`
// Voice, so GuildVoice only
VoiceBitrate int `json:"bitrate,omitempty"`
VoiceUserLimit int `json:"user_limit,omitempty"`
}
type ChannelType uint8
const (
GuildText ChannelType = iota
DirectMessage
GuildVoice
GroupDM
GuildCategory
GuildNews
GuildStore
)
type Overwrite struct {
ID discord.Snowflake `json:"id,omitempty"`
Type OverwriteType `json:"type"`
Allow uint64 `json:"allow"`
Deny uint64 `json:"deny"`
}
type OverwriteType string
const (
OverwriteRole OverwriteType = "role"
OverwriteMember OverwriteType = "member"
)
type ChannelModifier struct {
ChannelID discord.Snowflake `json:"id,omitempty"`
// All types
Name string `json:"name,omitempty"`
Position json.OptionInt `json:"position,omitempty"`
Permissions []Overwrite `json:"permission_overwrites,omitempty"`
Name string `json:"name,omitempty"`
Position json.OptionInt `json:"position,omitempty"`
Permissions []discord.Overwrite `json:"permission_overwrites,omitempty"`
// Text only
Topic json.OptionString `json:"topic,omitempty"`
@ -100,8 +33,8 @@ type ChannelModifier struct {
ParentID discord.Snowflake `json:"parent_id,omitempty"`
}
func (c *Client) Channel(channelID discord.Snowflake) (*Channel, error) {
var channel *Channel
func (c *Client) Channel(channelID discord.Snowflake) (*discord.Channel, error) {
var channel *discord.Channel
return channel,
c.RequestJSON(&channel, "POST", EndpointChannels+channelID.String())
@ -119,7 +52,7 @@ func (c *Client) DeleteChannel(channelID discord.Snowflake) error {
}
func (c *Client) EditChannelPermission(channelID discord.Snowflake,
overwrite Overwrite) error {
overwrite discord.Overwrite) error {
url := EndpointChannels + channelID.String() + "/permissions/" +
overwrite.ID.String()
@ -143,9 +76,9 @@ func (c *Client) Typing(channelID discord.Snowflake) error {
}
func (c *Client) PinnedMessages(
channelID discord.Snowflake) ([]Message, error) {
channelID discord.Snowflake) ([]discord.Message, error) {
var pinned []Message
var pinned []discord.Message
return pinned, c.RequestJSON(&pinned, "GET",
EndpointChannels+channelID.String()+"/pins")
}

View file

@ -1,25 +1,9 @@
package api
import (
"strings"
"git.sr.ht/~diamondburned/arikawa/discord"
)
type Emoji struct {
ID discord.Snowflake `json:"id"` // 0 for Unicode emojis
Name string `json:"name"`
// These fields are optional
RoleIDs []discord.Snowflake `json:"roles,omitempty"`
User User `json:"user,omitempty"`
RequireColons bool `json:"require_colons,omitempty"`
Managed bool `json:"managed,omitempty"`
Animated bool `json:"animated,omitempty"`
}
// EmojiAPI is a special format that the API wants.
type EmojiAPI = string
@ -31,28 +15,20 @@ func FormatEmojiAPI(id discord.Snowflake, name string) string {
return id.String() + ":" + name
}
// APIString returns a string usable for sending over to the API.
func (e Emoji) APIString() EmojiAPI {
if e.ID == 0 {
return e.Name // is unicode
}
func (c *Client) Emojis(
guildID discord.Snowflake) ([]discord.Emoji, error) {
return e.ID.String() + ":" + e.Name
var emjs []discord.Emoji
return emjs, c.RequestJSON(&emjs, "GET",
EndpointGuilds+guildID.String()+"/emojis")
}
// String formats the string like how the client does.
func (e Emoji) String() string {
if e.ID == 0 {
return e.Name
}
func (c *Client) Emoji(
guildID, emojiID discord.Snowflake) (*discord.Emoji, error) {
var parts = []string{
"", e.Name, e.ID.String(),
}
if e.Animated {
parts[0] = "a"
}
return "<" + strings.Join(parts, ":") + ">"
var emj *discord.Emoji
return emj, c.RequestJSON(&emj, "GET",
EndpointGuilds+guildID.String()+"/emojis/"+emojiID.String())
}
// func (c *Client) CreateEmoji()

View file

@ -1,22 +0,0 @@
package api
import (
"fmt"
)
type ErrOverbound struct {
Count int
Max int
Thing string
}
var _ error = (*ErrOverbound)(nil)
func (e ErrOverbound) Error() string {
if e.Thing == "" {
return fmt.Sprintf("Overbound error: %d > %d", e.Count, e.Max)
}
return fmt.Sprintf(e.Thing+" overbound: %d > %d", e.Count, e.Max)
}

View file

@ -1,7 +1,3 @@
package api
const EndpointGuilds = Endpoint + "guilds/"
type Guild struct{}
type GuildMember struct{}

View file

@ -1,13 +1,16 @@
package api
import "git.sr.ht/~diamondburned/arikawa/discord"
import (
"git.sr.ht/~diamondburned/arikawa/discord"
)
const EndpointInvites = Endpoint + "invites/"
// Still unsure what this is
type MetaInvite struct {
Inviter User `json:"user"`
Uses uint `json:"uses"`
MaxUses uint `json:"max_uses"`
Inviter discord.User `json:"user"`
Uses uint `json:"uses"`
MaxUses uint `json:"max_uses"`
MaxAge discord.Seconds `json:"max_age"`
@ -15,28 +18,7 @@ type MetaInvite struct {
CreatedAt discord.Timestamp `json:"created_at"`
}
type Invite struct {
Code string `json:"code"`
Channel Channel `json:"channel"` // partial
Guild *Guild `json:"guild,omitempty"` // partial
ApproxMembers uint `json:"approximate_members_count,omitempty"`
Target *User `json:"target_user,omitempty"` // partial
TargetType InviteUserType `json:"target_user_type,omitempty"`
// Only available if Target is
ApproxPresences uint `json:"approximate_presence_count,omitempty"`
}
type InviteUserType uint8
const (
InviteNormalUser InviteUserType = iota
InviteUserStream
)
func (c *Client) Invite(code string) (*Invite, error) {
func (c *Client) Invite(code string) (*discord.Invite, error) {
var params struct {
WithCounts bool `json:"with_counts,omitempty"`
}
@ -44,13 +26,13 @@ func (c *Client) Invite(code string) (*Invite, error) {
// Nothing says I can't!
params.WithCounts = true
var inv *Invite
var inv *discord.Invite
return inv, c.RequestJSON(&inv, "GET", EndpointInvites+code)
}
// Invites is only for guild channels.
func (c *Client) Invites(channelID discord.Snowflake) ([]Invite, error) {
var invs []Invite
func (c *Client) Invites(channelID discord.Snowflake) ([]discord.Invite, error) {
var invs []discord.Invite
return invs, c.RequestJSON(&invs, "GET",
EndpointChannels+channelID.String()+"/invites")
}
@ -63,7 +45,7 @@ func (c *Client) Invites(channelID discord.Snowflake) ([]Invite, error) {
// temporary membership. Unique, if true, tries not to reuse a similar invite,
// useful for creating unique one time use invites.
func (c *Client) CreateInvite(channelID discord.Snowflake,
maxAge discord.Seconds, maxUses uint, temp, unique bool) (*Invite, error) {
maxAge discord.Seconds, maxUses uint, temp, unique bool) (*discord.Invite, error) {
var params struct {
MaxAge uint `json:"max_age"`
@ -77,14 +59,14 @@ func (c *Client) CreateInvite(channelID discord.Snowflake,
params.Temporary = temp
params.Unique = unique
var inv *Invite
var inv *discord.Invite
return inv, c.RequestJSON(&inv, "POST",
EndpointChannels+channelID.String()+"/invites")
}
// DeleteInvite requires either MANAGE_CHANNELS on the target channel, or
// MANAGE_GUILD to remove any invite in the guild.
func (c *Client) DeleteInvite(code string) (*Invite, error) {
var inv *Invite
func (c *Client) DeleteInvite(code string) (*discord.Invite, error) {
var inv *discord.Invite
return inv, c.RequestJSON(&inv, "DELETE", EndpointInvites+code)
}

View file

@ -8,177 +8,30 @@ import (
"github.com/pkg/errors"
)
type Message struct {
ID discord.Snowflake `json:"id"`
Type MessageType `json:"type"`
ChannelID discord.Snowflake `json:"channel_id"`
GuildID discord.Snowflake `json:"guild_id,omitempty"`
// The author object follows the structure of the user object, but is only
// a valid user in the case where the message is generated by a user or bot
// user. If the message is generated by a webhook, the author object
// corresponds to the webhook's id, username, and avatar. You can tell if a
// message is generated by a webhook by checking for the webhook_id on the
// message object.
Author User `json:"author"`
// The member object exists in MESSAGE_CREATE and MESSAGE_UPDATE
// events from text-based guild channels.
Member *GuildMember `json:"member,omitempty"`
Content string `json:"content"`
Timestamp discord.Timestamp `json:"timestamp,omitempty"`
EditedTimestamp *discord.Timestamp `json:"edited_timestamp,omitempty"`
TTS bool `json:"tts"`
Pinned bool `json:"pinned"`
// The user objects in the mentions array will only have the partial
// member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from
// text-based guild channels.
Mentions []GuildUser `json:"mentions"`
MentionRoleIDs []discord.Snowflake `json:"mention_roles"`
MentionEveryone bool `json:"mention_everyone"`
// Not all channel mentions in a message will appear in mention_channels.
MentionChannels []ChannelMention `json:"mention_channels,omitempty"`
Attachments []Attachment `json:"attachments"`
Embeds []Embed `json:"embeds"`
Reactions []Reaction `json:"reaction,omitempty"`
// Used for validating a message was sent
Nonce string `json:"nonce,omitempty"`
WebhookID discord.Snowflake `json:"webhook_id,omitempty"`
Activity *MessageActivity `json:"activity,omitempty"`
Application *MessageApplication `json:"application,omitempty"`
Reference *MessageReference `json:"message_reference,omitempty"`
Flags MessageFlags `json:"flags"`
}
type MessageType uint8
const (
DefaultMessage MessageType = iota
RecipientAddMessage
RecipientRemoveMessage
CallMessage
ChannelNameChangeMessage
ChannelIconChangeMessage
ChannelPinnedMessage
GuildMemberJoinMessage
NitroBoostMessage
NitroTier1Message
NitroTier2Message
NitroTier3Message
ChannelFollowAddMessage
)
type MessageFlags uint8
const (
CrosspostedMessage MessageFlags = 1 << iota
MessageIsCrosspost
SuppressEmbeds
SourceMessageDeleted
UrgentMessage
)
type ChannelMention struct {
ChannelID discord.Snowflake `json:"id"`
GuildID discord.Snowflake `json:"guild_id"`
ChannelType ChannelType `json:"type"`
ChannelName string `json:"name"`
}
type GuildUser struct {
User
Member *GuildMember `json:"member,omitempty"`
}
//
type MessageActivity struct {
Type MessageActivityType `json:"type"`
// From a Rich Presence event
PartyID string `json:"party_id,omitempty"`
}
type MessageActivityType uint8
const (
JoinMessage MessageActivityType = iota + 1
SpectateMessage
ListenMessage
JoinRequestMessage
)
//
type MessageApplication struct {
ID discord.Snowflake `json:"id"`
CoverID string `json:"cover_image,omitempty"`
Description string `json:"description"`
Icon string `json:"icon"`
Name string `json:"name"`
}
//
type MessageReference struct {
ChannelID discord.Snowflake `json:"channel_id"`
// Field might not be provided
MessageID discord.Snowflake `json:"message_id,omitempty"`
GuildID discord.Snowflake `json:"guild_id,omitempty"`
}
//
type Attachment struct {
ID discord.Snowflake `json:"id"`
Filename string `json:"filename"`
Size uint64 `json:"size"`
URL discord.URL `json:"url"`
Proxy discord.URL `json:"proxy_url"`
// Only if Image
Height uint `json:"height,omitempty"`
Width uint `json:"width,omitempty"`
}
//
func (c *Client) Messages(
channelID discord.Snowflake, limit uint) ([]Message, error) {
func (c *Client) Messages(channelID discord.Snowflake,
limit uint) ([]discord.Message, error) {
return c.messages(channelID, limit, nil)
}
func (c *Client) MessagesAround(
channelID, around discord.Snowflake, limit uint) ([]Message, error) {
func (c *Client) MessagesAround(channelID, around discord.Snowflake,
limit uint) ([]discord.Message, error) {
return c.messages(channelID, limit, map[string]interface{}{
"around": around,
})
}
func (c *Client) MessagesBefore(
channelID, before discord.Snowflake, limit uint) ([]Message, error) {
func (c *Client) MessagesBefore(channelID, before discord.Snowflake,
limit uint) ([]discord.Message, error) {
return c.messages(channelID, limit, map[string]interface{}{
"before": before,
})
}
func (c *Client) MessagesAfter(
channelID, after discord.Snowflake, limit uint) ([]Message, error) {
func (c *Client) MessagesAfter(channelID, after discord.Snowflake,
limit uint) ([]discord.Message, error) {
return c.messages(channelID, limit, map[string]interface{}{
"after": after,
@ -186,7 +39,7 @@ func (c *Client) MessagesAfter(
}
func (c *Client) messages(channelID discord.Snowflake,
limit uint, body map[string]interface{}) ([]Message, error) {
limit uint, body map[string]interface{}) ([]discord.Message, error) {
if body == nil {
body = map[string]interface{}{}
@ -201,21 +54,21 @@ func (c *Client) messages(channelID discord.Snowflake,
body["limit"] = limit
var msgs []Message
var msgs []discord.Message
return msgs, c.RequestJSON(&msgs, "GET",
EndpointChannels+channelID.String(), httputil.WithJSONBody(c, body))
}
func (c *Client) Message(
channelID, messageID discord.Snowflake) (*Message, error) {
channelID, messageID discord.Snowflake) (*discord.Message, error) {
var msg *Message
var msg *discord.Message
return msg, c.RequestJSON(&msg, "GET",
EndpointChannels+channelID.String()+"/messages/"+messageID.String())
}
func (c *Client) SendMessage(channelID discord.Snowflake,
content string, embed *Embed) (*Message, error) {
content string, embed *discord.Embed) (*discord.Message, error) {
return c.SendMessageComplex(channelID, SendMessageData{
Content: content,
@ -224,7 +77,7 @@ func (c *Client) SendMessage(channelID discord.Snowflake,
}
func (c *Client) SendMessageComplex(channelID discord.Snowflake,
data SendMessageData) (*Message, error) {
data SendMessageData) (*discord.Message, error) {
if data.Embed != nil {
if err := data.Embed.Validate(); err != nil {
@ -233,7 +86,7 @@ func (c *Client) SendMessageComplex(channelID discord.Snowflake,
}
var URL = EndpointChannels + channelID.String()
var msg *Message
var msg *discord.Message
if len(data.Files) == 0 {
// No files, no need for streaming
@ -256,21 +109,22 @@ func (c *Client) SendMessageComplex(channelID discord.Snowflake,
}
func (c *Client) EditMessage(channelID, messageID discord.Snowflake,
content string, embed *Embed, suppressEmbeds bool) (*Message, error) {
content string, embed *discord.Embed, suppressEmbeds bool,
) (*discord.Message, error) {
var param struct {
Content string `json:"content,omitempty"`
Embed *Embed `json:"embed,omitempty"`
Flags MessageFlags `json:"flags,omitempty"`
Content string `json:"content,omitempty"`
Embed *discord.Embed `json:"embed,omitempty"`
Flags discord.MessageFlags `json:"flags,omitempty"`
}
param.Content = content
param.Embed = embed
if suppressEmbeds {
param.Flags = SuppressEmbeds
param.Flags = discord.SuppressEmbeds
}
var msg *Message
var msg *discord.Message
return msg, c.RequestJSON(
&msg, "PATCH",
EndpointChannels+channelID.String()+"/messages/"+messageID.String(),

View file

@ -5,12 +5,6 @@ import (
"git.sr.ht/~diamondburned/arikawa/httputil"
)
type Reaction struct {
Count int `json:"count"`
Me bool `json:"me"` // for current user
Emoji Emoji `json:"emoji"`
}
// React adds a reaction to the message. This requires READ_MESSAGE_HISTORY (and
// additionally ADD_REACTIONS) to react.
func (c *Client) React(chID, msgID discord.Snowflake,
@ -23,15 +17,16 @@ func (c *Client) React(chID, msgID discord.Snowflake,
}
func (c *Client) Reactions(chID, msgID discord.Snowflake,
limit uint, emoji EmojiAPI) ([]User, error) {
limit uint, emoji EmojiAPI) ([]discord.User, error) {
return c.ReactionRange(chID, msgID, 0, 0, limit, emoji)
}
// ReactionRange get users before and after IDs. Before, after, and limit are
// optional.
func (c *Client) ReactionRange(chID, msgID, before, after discord.Snowflake,
limit uint, emoji EmojiAPI) ([]User, error) {
func (c *Client) ReactionRange(
chID, msgID, before, after discord.Snowflake,
limit uint, emoji EmojiAPI) ([]discord.User, error) {
if limit == 0 {
limit = 25
@ -48,7 +43,7 @@ func (c *Client) ReactionRange(chID, msgID, before, after discord.Snowflake,
Limit uint `json:"limit"`
}
var users []User
var users []discord.User
var msgURL = EndpointChannels + chID.String() +
"/messages/" + msgID.String() +
"/reactions/" + emoji

View file

@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"git.sr.ht/~diamondburned/arikawa/discord"
"git.sr.ht/~diamondburned/arikawa/json"
"github.com/pkg/errors"
)
@ -17,7 +18,8 @@ type SendMessageData struct {
Content string `json:"content"`
Nonce string `json:"nonce"`
TTS bool `json:"tts"`
Embed *Embed `json:"embed"`
Embed *discord.Embed `json:"embed"`
Files []SendMessageFile `json:"-"`
}
@ -53,7 +55,7 @@ func (data *SendMessageData) WriteMultipart(c json.Driver, w io.Writer) error {
for i, file := range data.Files {
h := textproto.MIMEHeader{}
h.Set("Content-Disposition", fmt.Sprintf(
`form-data; name="file%s"; filename="%s"`,
`form-data; name="file%d"; filename="%s"`,
i, quoteEscaper.Replace(file.Name),
))

68
discord/channel.go Normal file
View file

@ -0,0 +1,68 @@
package discord
type Channel struct {
ID Snowflake `json:"id,string"`
Type ChannelType `json:"type"`
// Fields below may not appear
GuildID Snowflake `json:"guild_id,string,omitempty"`
Position int `json:"position,omitempty"`
Name string `json:"name,omitempty"` // 2-100 chars
Topic string `json:"topic,omitempty"` // 0-1024 chars
NSFW bool `json:"nsfw"`
Icon Hash `json:"icon,omitempty"`
// Direct Messaging fields
DMOwnerID Snowflake `json:"owner_id,omitempty"`
DMRecipients []User `json:"recipients,omitempty"`
// AppID of the group DM creator if it's bot-created
AppID Snowflake `json:"application_id,omitempty"`
// ID of the category the channel is in, if any.
CategoryID Snowflake `json:"parent_id,omitempty"`
LastPinTime Timestamp `json:"last_pin_timestamp,omitempty"`
// Explicit permission overrides for members and roles.
Permissions []Overwrite `json:"permission_overwrites,omitempty"`
// ID of the last message, may not point to a valid one.
LastMessageID Snowflake `json:"last_message_id,omitempty"`
// Slow mode duration. Bots and people with "manage_messages" or
// "manage_channel" permissions are unaffected.
UserRateLimit Seconds `json:"rate_limit_per_user,omitempty"`
// Voice, so GuildVoice only
VoiceBitrate int `json:"bitrate,omitempty"`
VoiceUserLimit int `json:"user_limit,omitempty"`
}
type ChannelType uint8
const (
GuildText ChannelType = iota
DirectMessage
GuildVoice
GroupDM
GuildCategory
GuildNews
GuildStore
)
type Overwrite struct {
ID Snowflake `json:"id,omitempty"`
Type OverwriteType `json:"type"`
Allow uint64 `json:"allow"`
Deny uint64 `json:"deny"`
}
type OverwriteType string
const (
OverwriteRole OverwriteType = "role"
OverwriteMember OverwriteType = "member"
)

View file

@ -1,5 +0,0 @@
package discord
type Color uint
const DefaultColor Color = 0x303030

43
discord/emoji.go Normal file
View file

@ -0,0 +1,43 @@
package discord
import "strings"
type Emoji struct {
ID Snowflake `json:"id"` // 0 for Unicode emojis
Name string `json:"name"`
// These fields are optional
RoleIDs []Snowflake `json:"roles,omitempty"`
User User `json:"user,omitempty"`
RequireColons bool `json:"require_colons,omitempty"`
Managed bool `json:"managed,omitempty"`
Animated bool `json:"animated,omitempty"`
}
// APIString returns a string usable for sending over to the API.
func (e Emoji) APIString() string {
if e.ID == 0 {
return e.Name // is unicode
}
return e.ID.String() + ":" + e.Name
}
// String formats the string like how the client does.
func (e Emoji) String() string {
if e.ID == 0 {
return e.Name
}
var parts = []string{
"", e.Name, e.ID.String(),
}
if e.Animated {
parts[0] = "a"
}
return "<" + strings.Join(parts, ":") + ">"
}

5
discord/guild.go Normal file
View file

@ -0,0 +1,5 @@
package discord
type Guild struct{}
type GuildMember struct{}

View file

@ -1,22 +0,0 @@
package discord
type Image string
const (
ImageBaseURL = "https://cdn.discordapp.com/"
)
type ImageType uint8
const (
CustomEmoji ImageType = iota
GuildIcon
GuildSplash
GuildBanner
DefaultUserAvatar
UserAvatar
ApplicationIcon
ApplicationAsset
AchievementIcon
TeamIcon
)

22
discord/invite.go Normal file
View file

@ -0,0 +1,22 @@
package discord
type Invite struct {
Code string `json:"code"`
Channel Channel `json:"channel"` // partial
Guild *Guild `json:"guild,omitempty"` // partial
ApproxMembers uint `json:"approximate_members_count,omitempty"`
Target *User `json:"target_user,omitempty"` // partial
TargetType InviteUserType `json:"target_user_type,omitempty"`
// Only available if Target is
ApproxPresences uint `json:"approximate_presence_count,omitempty"`
}
type InviteUserType uint8
const (
InviteNormalUser InviteUserType = iota
InviteUserStream
)

154
discord/message.go Normal file
View file

@ -0,0 +1,154 @@
package discord
type Message struct {
ID Snowflake `json:"id"`
Type MessageType `json:"type"`
ChannelID Snowflake `json:"channel_id"`
GuildID Snowflake `json:"guild_id,omitempty"`
// The author object follows the structure of the user object, but is only
// a valid user in the case where the message is generated by a user or bot
// user. If the message is generated by a webhook, the author object
// corresponds to the webhook's id, username, and avatar. You can tell if a
// message is generated by a webhook by checking for the webhook_id on the
// message object.
Author User `json:"author"`
// The member object exists in MESSAGE_CREATE and MESSAGE_UPDATE
// events from text-based guild channels.
Member *GuildMember `json:"member,omitempty"`
Content string `json:"content"`
Timestamp Timestamp `json:"timestamp,omitempty"`
EditedTimestamp *Timestamp `json:"edited_timestamp,omitempty"`
TTS bool `json:"tts"`
Pinned bool `json:"pinned"`
// The user objects in the mentions array will only have the partial
// member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from
// text-based guild channels.
Mentions []GuildUser `json:"mentions"`
MentionRoleIDs []Snowflake `json:"mention_roles"`
MentionEveryone bool `json:"mention_everyone"`
// Not all channel mentions in a message will appear in mention_channels.
MentionChannels []ChannelMention `json:"mention_channels,omitempty"`
Attachments []Attachment `json:"attachments"`
Embeds []Embed `json:"embeds"`
Reactions []Reaction `json:"reaction,omitempty"`
// Used for validating a message was sent
Nonce string `json:"nonce,omitempty"`
WebhookID Snowflake `json:"webhook_id,omitempty"`
Activity *MessageActivity `json:"activity,omitempty"`
Application *MessageApplication `json:"application,omitempty"`
Reference *MessageReference `json:"message_reference,omitempty"`
Flags MessageFlags `json:"flags"`
}
type MessageType uint8
const (
DefaultMessage MessageType = iota
RecipientAddMessage
RecipientRemoveMessage
CallMessage
ChannelNameChangeMessage
ChannelIconChangeMessage
ChannelPinnedMessage
GuildMemberJoinMessage
NitroBoostMessage
NitroTier1Message
NitroTier2Message
NitroTier3Message
ChannelFollowAddMessage
)
type MessageFlags uint8
const (
CrosspostedMessage MessageFlags = 1 << iota
MessageIsCrosspost
SuppressEmbeds
SourceMessageDeleted
UrgentMessage
)
type ChannelMention struct {
ChannelID Snowflake `json:"id"`
GuildID Snowflake `json:"guild_id"`
ChannelType ChannelType `json:"type"`
ChannelName string `json:"name"`
}
type GuildUser struct {
User
Member *GuildMember `json:"member,omitempty"`
}
//
type MessageActivity struct {
Type MessageActivityType `json:"type"`
// From a Rich Presence event
PartyID string `json:"party_id,omitempty"`
}
type MessageActivityType uint8
const (
JoinMessage MessageActivityType = iota + 1
SpectateMessage
ListenMessage
JoinRequestMessage
)
//
type MessageApplication struct {
ID Snowflake `json:"id"`
CoverID string `json:"cover_image,omitempty"`
Description string `json:"description"`
Icon string `json:"icon"`
Name string `json:"name"`
}
//
type MessageReference struct {
ChannelID Snowflake `json:"channel_id"`
// Field might not be provided
MessageID Snowflake `json:"message_id,omitempty"`
GuildID Snowflake `json:"guild_id,omitempty"`
}
//
type Attachment struct {
ID Snowflake `json:"id"`
Filename string `json:"filename"`
Size uint64 `json:"size"`
URL URL `json:"url"`
Proxy URL `json:"proxy_url"`
// Only if Image
Height uint `json:"height,omitempty"`
Width uint `json:"width,omitempty"`
}
//
type Reaction struct {
Count int `json:"count"`
Me bool `json:"me"` // for current user
Emoji Emoji `json:"emoji"`
}

View file

@ -1,20 +1,20 @@
package api
package discord
import (
"fmt"
import "fmt"
"git.sr.ht/~diamondburned/arikawa/discord"
)
type Color uint
const DefaultColor Color = 0x303030
type Embed struct {
Title string `json:"title,omitempty"`
Type EmbedType `json:"type,omitempty"`
Description string `json:"description,omitempty"`
URL discord.URL `json:"url,omitempty"`
URL URL `json:"url,omitempty"`
Timestamp discord.Timestamp `json:"timestamp,omitempty"`
Color discord.Color `json:"color,omitempty"`
Timestamp Timestamp `json:"timestamp,omitempty"`
Color Color `json:"color,omitempty"`
Footer *EmbedFooter `json:"footer,omitempty"`
Image *EmbedImage `json:"image,omitempty"`
@ -28,17 +28,34 @@ type Embed struct {
func NewEmbed() *Embed {
return &Embed{
Type: NormalEmbed,
Color: discord.DefaultColor,
Color: DefaultColor,
}
}
type ErrOverbound struct {
Count int
Max int
Thing string
}
var _ error = (*ErrOverbound)(nil)
func (e ErrOverbound) Error() string {
if e.Thing == "" {
return fmt.Sprintf("Overbound error: %d > %d", e.Count, e.Max)
}
return fmt.Sprintf(e.Thing+" overbound: %d > %d", e.Count, e.Max)
}
func (e *Embed) Validate() error {
if e.Type == "" {
e.Type = NormalEmbed
}
if e.Color == 0 {
e.Color = discord.DefaultColor
e.Color = DefaultColor
}
if len(e.Title) > 256 {
@ -104,39 +121,39 @@ const (
)
type EmbedFooter struct {
Text string `json:"text"`
Icon discord.URL `json:"icon_url,omitempty"`
ProxyIcon discord.URL `json:"proxy_icon_url,omitempty"`
Text string `json:"text"`
Icon URL `json:"icon_url,omitempty"`
ProxyIcon URL `json:"proxy_icon_url,omitempty"`
}
type EmbedImage struct {
URL discord.URL `json:"url"`
Proxy discord.URL `json:"proxy_url"`
URL URL `json:"url"`
Proxy URL `json:"proxy_url"`
}
type EmbedThumbnail struct {
URL discord.URL `json:"url,omitempty"`
Proxy discord.URL `json:"proxy_url,omitempty"`
Height uint `json:"height,omitempty"`
Width uint `json:"width,omitempty"`
URL URL `json:"url,omitempty"`
Proxy URL `json:"proxy_url,omitempty"`
Height uint `json:"height,omitempty"`
Width uint `json:"width,omitempty"`
}
type EmbedVideo struct {
URL discord.URL `json:"url"`
Height uint `json:"height"`
Width uint `json:"width"`
URL URL `json:"url"`
Height uint `json:"height"`
Width uint `json:"width"`
}
type EmbedProvider struct {
Name string `json:"name"`
URL discord.URL `json:"url"`
Name string `json:"name"`
URL URL `json:"url"`
}
type EmbedAuthor struct {
Name string `json:"name,omitempty"`
URL discord.URL `json:"url,omitempty"`
Icon discord.URL `json:"icon_url,omitempty"`
ProxyIcon discord.URL `json:"proxy_icon_url,omitempty"`
Name string `json:"name,omitempty"`
URL URL `json:"url,omitempty"`
Icon URL `json:"icon_url,omitempty"`
ProxyIcon URL `json:"proxy_icon_url,omitempty"`
}
type EmbedField struct {

View file

@ -1,17 +0,0 @@
package discord
import "time"
type Seconds uint
func DurationToSeconds(dura time.Duration) Seconds {
return Seconds(dura.Seconds())
}
func (s Seconds) String() string {
return s.Duration().String()
}
func (s Seconds) Duration() time.Duration {
return time.Duration(s) * time.Second
}

View file

@ -27,3 +27,17 @@ func (t *Timestamp) UnmarshalJSON(v []byte) error {
func (t Timestamp) MarshalJSON() ([]byte, error) {
return []byte(`"` + time.Time(t).Format(TimestampFormat) + `"`), nil
}
type Seconds uint
func DurationToSeconds(dura time.Duration) Seconds {
return Seconds(dura.Seconds())
}
func (s Seconds) String() string {
return s.Duration().String()
}
func (s Seconds) Duration() time.Duration {
return time.Duration(s) * time.Second
}

View file

@ -1,12 +1,10 @@
package api
import "git.sr.ht/~diamondburned/arikawa/discord"
package discord
type User struct {
UserID discord.Snowflake `json:"id"`
Username string `json:"username"`
Discriminator string `json:"discriminator"`
Avatar discord.Hash `json:"avatar"`
UserID Snowflake `json:"id"`
Username string `json:"username"`
Discriminator string `json:"discriminator"`
Avatar Hash `json:"avatar"`
// These fields may be omitted

5
go.mod
View file

@ -2,4 +2,7 @@ module git.sr.ht/~diamondburned/arikawa
go 1.13
require github.com/pkg/errors v0.8.1
require (
github.com/bwmarrin/discordgo v0.20.2
github.com/pkg/errors v0.8.1
)

6
go.sum
View file

@ -1,2 +1,8 @@
github.com/bwmarrin/discordgo v0.20.2 h1:nA7jiTtqUA9lT93WL2jPjUp8ZTEInRujBdx1C9gkr20=
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

View file

@ -56,6 +56,7 @@ func (c *Client) MeanwhileBody(bodyWriter func(io.Writer) error,
func (c *Client) FastRequest(
method, url string, opts ...RequestOption) error {
r, err := c.Request(method, url, opts...)
if err != nil {
return err