mirror of
https://github.com/diamondburned/arikawa.git
synced 2024-09-30 06:01:17 +00:00
302 lines
7.5 KiB
Go
302 lines
7.5 KiB
Go
|
package api
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
|
||
|
"git.sr.ht/~diamondburned/arikawa/discord"
|
||
|
"git.sr.ht/~diamondburned/arikawa/httputil"
|
||
|
"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) {
|
||
|
|
||
|
return c.messages(channelID, limit, nil)
|
||
|
}
|
||
|
|
||
|
func (c *Client) MessagesAround(
|
||
|
channelID, around discord.Snowflake, limit uint) ([]Message, error) {
|
||
|
|
||
|
return c.messages(channelID, limit, map[string]interface{}{
|
||
|
"around": around,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (c *Client) MessagesBefore(
|
||
|
channelID, before discord.Snowflake, limit uint) ([]Message, error) {
|
||
|
|
||
|
return c.messages(channelID, limit, map[string]interface{}{
|
||
|
"before": before,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (c *Client) MessagesAfter(
|
||
|
channelID, after discord.Snowflake, limit uint) ([]Message, error) {
|
||
|
|
||
|
return c.messages(channelID, limit, map[string]interface{}{
|
||
|
"after": after,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (c *Client) messages(channelID discord.Snowflake,
|
||
|
limit uint, body map[string]interface{}) ([]Message, error) {
|
||
|
|
||
|
if body == nil {
|
||
|
body = map[string]interface{}{}
|
||
|
}
|
||
|
|
||
|
switch {
|
||
|
case limit == 0:
|
||
|
limit = 50
|
||
|
case limit > 100:
|
||
|
limit = 100
|
||
|
}
|
||
|
|
||
|
body["limit"] = limit
|
||
|
|
||
|
var msgs []Message
|
||
|
return msgs, c.RequestJSON(&msgs, "GET",
|
||
|
EndpointChannels+channelID.String(), httputil.WithJSONBody(c, body))
|
||
|
}
|
||
|
|
||
|
func (c *Client) Message(
|
||
|
channelID, messageID discord.Snowflake) (*Message, error) {
|
||
|
|
||
|
var msg *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) {
|
||
|
|
||
|
return c.SendMessageComplex(channelID, SendMessageData{
|
||
|
Content: content,
|
||
|
Embed: embed,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (c *Client) SendMessageComplex(channelID discord.Snowflake,
|
||
|
data SendMessageData) (*Message, error) {
|
||
|
|
||
|
if data.Embed != nil {
|
||
|
if err := data.Embed.Validate(); err != nil {
|
||
|
return nil, errors.Wrap(err, "Embed error")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var URL = EndpointChannels + channelID.String()
|
||
|
var msg *Message
|
||
|
|
||
|
if len(data.Files) == 0 {
|
||
|
// No files, no need for streaming
|
||
|
return msg, c.RequestJSON(&msg, "POST", URL,
|
||
|
httputil.WithJSONBody(c, data))
|
||
|
}
|
||
|
|
||
|
writer := func(w io.Writer) error {
|
||
|
return data.WriteMultipart(c, w)
|
||
|
}
|
||
|
|
||
|
resp, err := c.MeanwhileBody(writer, "POST", URL)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
return msg, c.DecodeStream(resp.Body, &msg)
|
||
|
}
|
||
|
|
||
|
func (c *Client) EditMessage(channelID, messageID discord.Snowflake,
|
||
|
content string, embed *Embed, suppressEmbeds bool) (*Message, error) {
|
||
|
|
||
|
var param struct {
|
||
|
Content string `json:"content,omitempty"`
|
||
|
Embed *Embed `json:"embed,omitempty"`
|
||
|
Flags MessageFlags `json:"flags,omitempty"`
|
||
|
}
|
||
|
|
||
|
param.Content = content
|
||
|
param.Embed = embed
|
||
|
if suppressEmbeds {
|
||
|
param.Flags = SuppressEmbeds
|
||
|
}
|
||
|
|
||
|
var msg *Message
|
||
|
return msg, c.RequestJSON(
|
||
|
&msg, "PATCH",
|
||
|
EndpointChannels+channelID.String()+"/messages/"+messageID.String(),
|
||
|
httputil.WithJSONBody(c, param),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
// DeleteMessage deletes a message. Requires MANAGE_MESSAGES if the message is
|
||
|
// not made by yourself.
|
||
|
func (c *Client) DeleteMessage(channelID, messageID discord.Snowflake) error {
|
||
|
return c.FastRequest("DELETE", EndpointChannels+channelID.String()+
|
||
|
"/messages/"+messageID.String())
|
||
|
}
|
||
|
|
||
|
// DeleteMessages only works for bots. It can't delete messages older than 2
|
||
|
// weeks, and will fail if tried. This endpoint requires MANAGE_MESSAGES.
|
||
|
func (c *Client) DeleteMessages(channelID discord.Snowflake,
|
||
|
messageIDs []discord.Snowflake) error {
|
||
|
|
||
|
var param struct {
|
||
|
Messages []discord.Snowflake `json:"messages"`
|
||
|
}
|
||
|
|
||
|
param.Messages = messageIDs
|
||
|
|
||
|
return c.FastRequest("POST", EndpointChannels+channelID.String()+
|
||
|
"/messages/bulk-delete", httputil.WithJSONBody(c, param))
|
||
|
}
|