Switch to discordgo upstream again (#1759)

* Switch to upstream discordgo again

* Fix discord api changes
pull/1760/head
Wim 2 years ago committed by GitHub
parent 9c203327c0
commit e4c0ca0f48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,8 +10,8 @@ import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/discord/transmitter"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/bwmarrin/discordgo"
lru "github.com/hashicorp/golang-lru"
"github.com/matterbridge/discordgo"
)
const (

@ -2,8 +2,8 @@ package bdiscord
import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/bwmarrin/discordgo"
"github.com/davecgh/go-spew/spew"
"github.com/matterbridge/discordgo"
)
func (b *Bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { //nolint:unparam
@ -56,7 +56,7 @@ func (b *Bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdat
return
}
// only when message is actually edited
if m.Message.EditedTimestamp != "" {
if m.Message.EditedTimestamp != nil {
b.Log.Debugf("Sending edit message")
m.Content += b.GetString("EditSuffix")
msg := &discordgo.MessageCreate{

@ -3,7 +3,7 @@ package bdiscord
import (
"testing"
"github.com/matterbridge/discordgo"
"github.com/bwmarrin/discordgo"
"github.com/stretchr/testify/assert"
)

@ -6,7 +6,7 @@ import (
"strings"
"unicode"
"github.com/matterbridge/discordgo"
"github.com/bwmarrin/discordgo"
)
func (b *Bdiscord) getAllowedMentions() *discordgo.MessageAllowedMentions {

@ -20,7 +20,7 @@ import (
"sync"
"time"
"github.com/matterbridge/discordgo"
"github.com/bwmarrin/discordgo"
log "github.com/sirupsen/logrus"
)

@ -1,7 +1,7 @@
package transmitter
import (
"github.com/matterbridge/discordgo"
"github.com/bwmarrin/discordgo"
)
// isDiscordPermissionError returns false for nil, and true if a Discord RESTError with code discordgo.ErrorCodeMissionPermissions

@ -5,7 +5,7 @@ import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/matterbridge/discordgo"
"github.com/bwmarrin/discordgo"
)
// shouldMessageUseWebhooks checks if have a channel specific webhook, if we're not using auto webhooks
@ -89,7 +89,7 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg
&discordgo.WebhookParams{
Username: msg.Username,
AvatarURL: msg.Avatar,
File: &file,
Files: []*discordgo.File{&file},
Content: content,
AllowedMentions: b.getAllowedMentions(),
},

@ -7,6 +7,7 @@ require (
github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c
github.com/SevereCloud/vksdk/v2 v2.13.1
github.com/bwmarrin/discordgo v0.24.0
github.com/d5/tengo/v2 v2.10.0
github.com/davecgh/go-spew v1.1.1
github.com/fsnotify/fsnotify v1.5.1
@ -24,7 +25,6 @@ require (
github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696
github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be
github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75
github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba

@ -290,6 +290,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bwmarrin/discordgo v0.24.0 h1:Gw4MYxqHdvhO99A3nXnSLy97z5pmIKHZVJ1JY5ZDPqY=
github.com/bwmarrin/discordgo v0.24.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -1079,8 +1081,6 @@ github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxI
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696 h1:pmPKkN3RJM9wVMZidR99epzK0+gatQiqVtvP1FacZcQ=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7 h1:4J2YZuY8dIYrxbLMsWGqPZb/B59ygCwSBkyZHez5PSY=
github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7/go.mod h1:411nZYv0UMMrtppR5glXop1foboJiFAowy+42U+Ahvw=
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be h1:zlirT+LngOJ60G6FVzI87DljGZLUnfNzmXja61EjtYM=
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419 h1:dx8x2J3EsVwP3hBGNmVT/otz4b42p7TRQ6Cu4BK2910=
@ -1791,6 +1791,7 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=

@ -0,0 +1,5 @@
# IDE-specific metadata
.idea/
# Environment variables. Useful for examples.
.env

@ -0,0 +1,19 @@
linters:
disable-all: true
enable:
# - staticcheck
# - unused
- golint
linters-settings:
staticcheck:
go: "1.13"
checks: ["all"]
unused:
go: "1.13"
issues:
include:
- EXC0002

@ -3,6 +3,7 @@ go:
- 1.13.x
- 1.14.x
- 1.15.x
- 1.16.x
env:
- GO111MODULE=on
install:

@ -1,8 +1,8 @@
# DiscordGo
[![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo) [![Go report](http://goreportcard.com/badge/bwmarrin/discordgo)](http://goreportcard.com/report/bwmarrin/discordgo) [![Build Status](https://travis-ci.org/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.org/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/0f1SbxBZjYoCtNPP) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.com/invite/discord-api)
[![Go Reference](https://pkg.go.dev/badge/github.com/bwmarrin/discordgo.svg)](https://pkg.go.dev/github.com/bwmarrin/discordgo) [![Go Report Card](https://goreportcard.com/badge/github.com/bwmarrin/discordgo)](https://goreportcard.com/report/github.com/bwmarrin/discordgo) [![Build Status](https://travis-ci.com/bwmarrin/discordgo.svg?branch=master)](https://travis-ci.com/bwmarrin/discordgo) [![Discord Gophers](https://img.shields.io/badge/Discord%20Gophers-%23discordgo-blue.svg)](https://discord.gg/golang) [![Discord API](https://img.shields.io/badge/Discord%20API-%23go_discordgo-blue.svg)](https://discord.com/invite/discord-api)
<img align="right" src="http://bwmarrin.github.io/discordgo/img/discordgo.png">
<img align="right" alt="DiscordGo logo" src="docs/img/discordgo.svg" width="400">
DiscordGo is a [Go](https://golang.org/) package that provides low level
bindings to the [Discord](https://discord.com/) chat client API. DiscordGo
@ -22,7 +22,7 @@ tool that wraps `ffmpeg` to create opus encoded audio appropriate for use with
Discord (and DiscordGo).
**For help with this package or general Go discussion, please join the [Discord
Gophers](https://discord.gg/0f1SbxBZjYq9jLBk) chat server.**
Gophers](https://discord.gg/golang) chat server.**
## Getting Started
@ -64,8 +64,8 @@ The DiscordGo code is fairly well documented at this point and is currently
the only documentation available. Both GoDoc and GoWalker (below) present
that information in a nice format.
- [![GoDoc](https://godoc.org/github.com/bwmarrin/discordgo?status.svg)](https://godoc.org/github.com/bwmarrin/discordgo)
- [![Go Walker](http://gowalker.org/api/v1/badge)](https://gowalker.org/github.com/bwmarrin/discordgo)
- [![Go Reference](https://pkg.go.dev/badge/github.com/bwmarrin/discordgo.svg)](https://pkg.go.dev/github.com/bwmarrin/discordgo)
- [![Go Walker](https://gowalker.org/api/v1/badge)](https://gowalker.org/github.com/bwmarrin/discordgo)
- Hand crafted documentation coming eventually.

@ -0,0 +1,241 @@
package discordgo
import (
"encoding/json"
"fmt"
)
// ComponentType is type of component.
type ComponentType uint
// MessageComponent types.
const (
ActionsRowComponent ComponentType = 1
ButtonComponent ComponentType = 2
SelectMenuComponent ComponentType = 3
TextInputComponent ComponentType = 4
)
// MessageComponent is a base interface for all message components.
type MessageComponent interface {
json.Marshaler
Type() ComponentType
}
type unmarshalableMessageComponent struct {
MessageComponent
}
// UnmarshalJSON is a helper function to unmarshal MessageComponent object.
func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error {
var v struct {
Type ComponentType `json:"type"`
}
err := json.Unmarshal(src, &v)
if err != nil {
return err
}
switch v.Type {
case ActionsRowComponent:
umc.MessageComponent = &ActionsRow{}
case ButtonComponent:
umc.MessageComponent = &Button{}
case SelectMenuComponent:
umc.MessageComponent = &SelectMenu{}
case TextInputComponent:
umc.MessageComponent = &TextInput{}
default:
return fmt.Errorf("unknown component type: %d", v.Type)
}
return json.Unmarshal(src, umc.MessageComponent)
}
// MessageComponentFromJSON is a helper function for unmarshaling message components
func MessageComponentFromJSON(b []byte) (MessageComponent, error) {
var u unmarshalableMessageComponent
err := u.UnmarshalJSON(b)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal into MessageComponent: %w", err)
}
return u.MessageComponent, nil
}
// ActionsRow is a container for components within one row.
type ActionsRow struct {
Components []MessageComponent `json:"components"`
}
// MarshalJSON is a method for marshaling ActionsRow to a JSON object.
func (r ActionsRow) MarshalJSON() ([]byte, error) {
type actionsRow ActionsRow
return json.Marshal(struct {
actionsRow
Type ComponentType `json:"type"`
}{
actionsRow: actionsRow(r),
Type: r.Type(),
})
}
// UnmarshalJSON is a helper function to unmarshal Actions Row.
func (r *ActionsRow) UnmarshalJSON(data []byte) error {
var v struct {
RawComponents []unmarshalableMessageComponent `json:"components"`
}
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
r.Components = make([]MessageComponent, len(v.RawComponents))
for i, v := range v.RawComponents {
r.Components[i] = v.MessageComponent
}
return err
}
// Type is a method to get the type of a component.
func (r ActionsRow) Type() ComponentType {
return ActionsRowComponent
}
// ButtonStyle is style of button.
type ButtonStyle uint
// Button styles.
const (
// PrimaryButton is a button with blurple color.
PrimaryButton ButtonStyle = 1
// SecondaryButton is a button with grey color.
SecondaryButton ButtonStyle = 2
// SuccessButton is a button with green color.
SuccessButton ButtonStyle = 3
// DangerButton is a button with red color.
DangerButton ButtonStyle = 4
// LinkButton is a special type of button which navigates to a URL. Has grey color.
LinkButton ButtonStyle = 5
)
// ComponentEmoji represents button emoji, if it does have one.
type ComponentEmoji struct {
Name string `json:"name,omitempty"`
ID string `json:"id,omitempty"`
Animated bool `json:"animated,omitempty"`
}
// Button represents button component.
type Button struct {
Label string `json:"label"`
Style ButtonStyle `json:"style"`
Disabled bool `json:"disabled"`
Emoji ComponentEmoji `json:"emoji"`
// NOTE: Only button with LinkButton style can have link. Also, URL is mutually exclusive with CustomID.
URL string `json:"url,omitempty"`
CustomID string `json:"custom_id,omitempty"`
}
// MarshalJSON is a method for marshaling Button to a JSON object.
func (b Button) MarshalJSON() ([]byte, error) {
type button Button
if b.Style == 0 {
b.Style = PrimaryButton
}
return json.Marshal(struct {
button
Type ComponentType `json:"type"`
}{
button: button(b),
Type: b.Type(),
})
}
// Type is a method to get the type of a component.
func (Button) Type() ComponentType {
return ButtonComponent
}
// SelectMenuOption represents an option for a select menu.
type SelectMenuOption struct {
Label string `json:"label,omitempty"`
Value string `json:"value"`
Description string `json:"description"`
Emoji ComponentEmoji `json:"emoji"`
// Determines whenever option is selected by default or not.
Default bool `json:"default"`
}
// SelectMenu represents select menu component.
type SelectMenu struct {
CustomID string `json:"custom_id,omitempty"`
// The text which will be shown in the menu if there's no default options or all options was deselected and component was closed.
Placeholder string `json:"placeholder"`
// This value determines the minimal amount of selected items in the menu.
MinValues *int `json:"min_values,omitempty"`
// This value determines the maximal amount of selected items in the menu.
// If MaxValues or MinValues are greater than one then the user can select multiple items in the component.
MaxValues int `json:"max_values,omitempty"`
Options []SelectMenuOption `json:"options"`
Disabled bool `json:"disabled"`
}
// Type is a method to get the type of a component.
func (SelectMenu) Type() ComponentType {
return SelectMenuComponent
}
// MarshalJSON is a method for marshaling SelectMenu to a JSON object.
func (m SelectMenu) MarshalJSON() ([]byte, error) {
type selectMenu SelectMenu
return json.Marshal(struct {
selectMenu
Type ComponentType `json:"type"`
}{
selectMenu: selectMenu(m),
Type: m.Type(),
})
}
// TextInput represents text input component.
type TextInput struct {
CustomID string `json:"custom_id"`
Label string `json:"label"`
Style TextInputStyle `json:"style"`
Placeholder string `json:"placeholder,omitempty"`
Value string `json:"value,omitempty"`
Required bool `json:"required,omitempty"`
MinLength int `json:"min_length,omitempty"`
MaxLength int `json:"max_length,omitempty"`
}
// Type is a method to get the type of a component.
func (TextInput) Type() ComponentType {
return TextInputComponent
}
// MarshalJSON is a method for marshaling TextInput to a JSON object.
func (m TextInput) MarshalJSON() ([]byte, error) {
type inputText TextInput
return json.Marshal(struct {
inputText
Type ComponentType `json:"type"`
}{
inputText: inputText(m),
Type: m.Type(),
})
}
// TextInputStyle is style of text in TextInput component.
type TextInputStyle uint
// Text styles
const (
TextInputShort TextInputStyle = 1
TextInputParagraph TextInputStyle = 2
)

@ -0,0 +1,60 @@
// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo
// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains high level helper functions and easy entry points for the
// entire discordgo package. These functions are being developed and are very
// experimental at this point. They will most likely change so please use the
// low level functions if that's a problem.
// Package discordgo provides Discord binding for Go
package discordgo
import (
"net/http"
"runtime"
"time"
)
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
const VERSION = "0.24.0"
// New creates a new Discord session with provided token.
// If the token is for a bot, it must be prefixed with "Bot "
// e.g. "Bot ..."
// Or if it is an OAuth2 token, it must be prefixed with "Bearer "
// e.g. "Bearer ..."
func New(token string) (s *Session, err error) {
// Create an empty Session interface.
s = &Session{
State: NewState(),
Ratelimiter: NewRatelimiter(),
StateEnabled: true,
Compress: true,
ShouldReconnectOnError: true,
ShardID: 0,
ShardCount: 1,
MaxRestRetries: 3,
Client: &http.Client{Timeout: (20 * time.Second)},
UserAgent: "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")",
sequence: new(int64),
LastHeartbeatAck: time.Now().UTC(),
}
// Initilize the Identify Package with defaults
// These can be modified prior to calling Open()
s.Identify.Compress = true
s.Identify.LargeThreshold = 250
s.Identify.GuildSubscriptions = true
s.Identify.Properties.OS = runtime.GOOS
s.Identify.Properties.Browser = "DiscordGo v" + VERSION
s.Identify.Intents = IntentsAllWithoutPrivileged
s.Identify.Token = token
s.Token = token
return
}

@ -0,0 +1,210 @@
// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo
// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains variables for all known Discord end points. All functions
// throughout the Discordgo package use these variables for all connections
// to Discord. These are all exported and you may modify them if needed.
package discordgo
import "strconv"
// APIVersion is the Discord API version used for the REST and Websocket API.
var APIVersion = "9"
// Known Discord API Endpoints.
var (
EndpointStatus = "https://status.discord.com/api/v2/"
EndpointSm = EndpointStatus + "scheduled-maintenances/"
EndpointSmActive = EndpointSm + "active.json"
EndpointSmUpcoming = EndpointSm + "upcoming.json"
EndpointDiscord = "https://discord.com/"
EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/"
EndpointGuilds = EndpointAPI + "guilds/"
EndpointChannels = EndpointAPI + "channels/"
EndpointUsers = EndpointAPI + "users/"
EndpointGateway = EndpointAPI + "gateway"
EndpointGatewayBot = EndpointGateway + "/bot"
EndpointWebhooks = EndpointAPI + "webhooks/"
EndpointStickers = EndpointAPI + "stickers/"
EndpointCDN = "https://cdn.discordapp.com/"
EndpointCDNAttachments = EndpointCDN + "attachments/"
EndpointCDNAvatars = EndpointCDN + "avatars/"
EndpointCDNIcons = EndpointCDN + "icons/"
EndpointCDNSplashes = EndpointCDN + "splashes/"
EndpointCDNChannelIcons = EndpointCDN + "channel-icons/"
EndpointCDNBanners = EndpointCDN + "banners/"
EndpointCDNGuilds = EndpointCDN + "guilds/"
EndpointVoice = EndpointAPI + "/voice/"
EndpointVoiceRegions = EndpointVoice + "regions"
// TODO: EndpointUserGuildMember
EndpointUser = func(uID string) string { return EndpointUsers + uID }
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
EndpointDefaultUserAvatar = func(uDiscriminator string) string {
uDiscriminatorInt, _ := strconv.Atoi(uDiscriminator)
return EndpointCDN + "embed/avatars/" + strconv.Itoa(uDiscriminatorInt%5) + ".png"
}
EndpointUserBanner = func(uID, cID string) string {
return EndpointCDNBanners + uID + "/" + cID + ".png"
}
EndpointUserBannerAnimated = func(uID, cID string) string {
return EndpointCDNBanners + uID + "/" + cID + ".gif"
}
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
EndpointGuildThreads = func(gID string) string { return EndpointGuild(gID) + "/threads" }
EndpointGuildActiveThreads = func(gID string) string { return EndpointGuildThreads(gID) + "/active" }
EndpointGuildPreview = func(gID string) string { return EndpointGuilds + gID + "/preview" }
EndpointGuildChannels = func(gID string) string { return EndpointGuilds + gID + "/channels" }
EndpointGuildMembers = func(gID string) string { return EndpointGuilds + gID + "/members" }
EndpointGuildMember = func(gID, uID string) string { return EndpointGuilds + gID + "/members/" + uID }
EndpointGuildMemberRole = func(gID, uID, rID string) string { return EndpointGuilds + gID + "/members/" + uID + "/roles/" + rID }
EndpointGuildBans = func(gID string) string { return EndpointGuilds + gID + "/bans" }
EndpointGuildBan = func(gID, uID string) string { return EndpointGuilds + gID + "/bans/" + uID }
EndpointGuildIntegrations = func(gID string) string { return EndpointGuilds + gID + "/integrations" }
EndpointGuildIntegration = func(gID, iID string) string { return EndpointGuilds + gID + "/integrations/" + iID }
EndpointGuildRoles = func(gID string) string { return EndpointGuilds + gID + "/roles" }
EndpointGuildRole = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID }
EndpointGuildInvites = func(gID string) string { return EndpointGuilds + gID + "/invites" }
EndpointGuildWidget = func(gID string) string { return EndpointGuilds + gID + "/widget" }
EndpointGuildEmbed = EndpointGuildWidget
EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" }
EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
EndpointGuildSplash = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" }
EndpointGuildWebhooks = func(gID string) string { return EndpointGuilds + gID + "/webhooks" }
EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" }
EndpointGuildEmojis = func(gID string) string { return EndpointGuilds + gID + "/emojis" }
EndpointGuildEmoji = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID }
EndpointGuildBanner = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" }
EndpointGuildStickers = func(gID string) string { return EndpointGuilds + gID + "/stickers" }
EndpointGuildSticker = func(gID, sID string) string { return EndpointGuilds + gID + "/stickers/" + sID }
EndpointGuildScheduledEvents = func(gID string) string { return EndpointGuilds + gID + "/scheduled-events" }
EndpointGuildScheduledEvent = func(gID, eID string) string { return EndpointGuilds + gID + "/scheduled-events/" + eID }
EndpointGuildScheduledEventUsers = func(gID, eID string) string { return EndpointGuildScheduledEvent(gID, eID) + "/users" }
EndpointGuildTemplate = func(tID string) string { return EndpointGuilds + "/templates/" + tID }
EndpointGuildTemplates = func(gID string) string { return EndpointGuilds + gID + "/templates" }
EndpointGuildTemplateSync = func(gID, tID string) string { return EndpointGuilds + gID + "/templates/" + tID }
EndpointGuildMemberAvatar = func(gId, uID, aID string) string {
return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".png"
}
EndpointGuildMemberAvatarAnimated = func(gId, uID, aID string) string {
return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".gif"
}
EndpointChannel = func(cID string) string { return EndpointChannels + cID }
EndpointChannelThreads = func(cID string) string { return EndpointChannel(cID) + "/threads" }
EndpointChannelActiveThreads = func(cID string) string { return EndpointChannelThreads(cID) + "/active" }
EndpointChannelPublicArchivedThreads = func(cID string) string { return EndpointChannelThreads(cID) + "/archived/public" }
EndpointChannelPrivateArchivedThreads = func(cID string) string { return EndpointChannelThreads(cID) + "/archived/private" }
EndpointChannelJoinedPrivateArchivedThreads = func(cID string) string { return EndpointChannel(cID) + "/users/@me/threads/archived/private" }
EndpointChannelPermissions = func(cID string) string { return EndpointChannels + cID + "/permissions" }
EndpointChannelPermission = func(cID, tID string) string { return EndpointChannels + cID + "/permissions/" + tID }
EndpointChannelInvites = func(cID string) string { return EndpointChannels + cID + "/invites" }
EndpointChannelTyping = func(cID string) string { return EndpointChannels + cID + "/typing" }
EndpointChannelMessages = func(cID string) string { return EndpointChannels + cID + "/messages" }
EndpointChannelMessage = func(cID, mID string) string { return EndpointChannels + cID + "/messages/" + mID }
EndpointChannelMessageThread = func(cID, mID string) string { return EndpointChannelMessage(cID, mID) + "/threads" }
EndpointChannelMessagesBulkDelete = func(cID string) string { return EndpointChannel(cID) + "/messages/bulk-delete" }
EndpointChannelMessagesPins = func(cID string) string { return EndpointChannel(cID) + "/pins" }
EndpointChannelMessagePin = func(cID, mID string) string { return EndpointChannel(cID) + "/pins/" + mID }
EndpointChannelMessageCrosspost = func(cID, mID string) string { return EndpointChannel(cID) + "/messages/" + mID + "/crosspost" }
EndpointChannelFollow = func(cID string) string { return EndpointChannel(cID) + "/followers" }
EndpointThreadMembers = func(tID string) string { return EndpointChannel(tID) + "/thread-members" }
EndpointThreadMember = func(tID, mID string) string { return EndpointThreadMembers(tID) + "/" + mID }
EndpointGroupIcon = func(cID, hash string) string { return EndpointCDNChannelIcons + cID + "/" + hash + ".png" }
EndpointSticker = func(sID string) string { return EndpointStickers + sID }
EndpointNitroStickersPacks = EndpointAPI + "/sticker-packs"
EndpointChannelWebhooks = func(cID string) string { return EndpointChannel(cID) + "/webhooks" }
EndpointWebhook = func(wID string) string { return EndpointWebhooks + wID }
EndpointWebhookToken = func(wID, token string) string { return EndpointWebhooks + wID + "/" + token }
EndpointWebhookMessage = func(wID, token, messageID string) string {
return EndpointWebhookToken(wID, token) + "/messages/" + messageID
}
EndpointMessageReactionsAll = func(cID, mID string) string {
return EndpointChannelMessage(cID, mID) + "/reactions"
}
EndpointMessageReactions = func(cID, mID, eID string) string {
return EndpointChannelMessage(cID, mID) + "/reactions/" + eID
}
EndpointMessageReaction = func(cID, mID, eID, uID string) string {
return EndpointMessageReactions(cID, mID, eID) + "/" + uID
}
EndpointApplicationGlobalCommands = func(aID string) string {
return EndpointApplication(aID) + "/commands"
}
EndpointApplicationGlobalCommand = func(aID, cID string) string {
return EndpointApplicationGlobalCommands(aID) + "/" + cID
}
EndpointApplicationGuildCommands = func(aID, gID string) string {
return EndpointApplication(aID) + "/guilds/" + gID + "/commands"
}
EndpointApplicationGuildCommand = func(aID, gID, cID string) string {
return EndpointApplicationGuildCommands(aID, gID) + "/" + cID
}
EndpointApplicationCommandPermissions = func(aID, gID, cID string) string {
return EndpointApplicationGuildCommand(aID, gID, cID) + "/permissions"
}
EndpointApplicationCommandsGuildPermissions = func(aID, gID string) string {
return EndpointApplicationGuildCommands(aID, gID) + "/permissions"
}
EndpointInteraction = func(aID, iToken string) string {
return EndpointAPI + "interactions/" + aID + "/" + iToken
}
EndpointInteractionResponse = func(iID, iToken string) string {
return EndpointInteraction(iID, iToken) + "/callback"
}
EndpointInteractionResponseActions = func(aID, iToken string) string {
return EndpointWebhookMessage(aID, iToken, "@original")
}
EndpointFollowupMessage = func(aID, iToken string) string {
return EndpointWebhookToken(aID, iToken)
}
EndpointFollowupMessageActions = func(aID, iToken, mID string) string {
return EndpointWebhookMessage(aID, iToken, mID)
}
EndpointGuildCreate = EndpointAPI + "guilds"
EndpointInvite = func(iID string) string { return EndpointAPI + "invites/" + iID }
EndpointEmoji = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".png" }
EndpointEmojiAnimated = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".gif" }
EndpointApplications = EndpointAPI + "applications"
EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID }
EndpointOAuth2 = EndpointAPI + "oauth2/"
EndpointOAuth2Applications = EndpointOAuth2 + "applications"
EndpointOAuth2Application = func(aID string) string { return EndpointOAuth2Applications + "/" + aID }
EndpointOAuth2ApplicationsBot = func(aID string) string { return EndpointOAuth2Applications + "/" + aID + "/bot" }
EndpointOAuth2ApplicationAssets = func(aID string) string { return EndpointOAuth2Applications + "/" + aID + "/assets" }
// TODO: Deprecated, remove in the next release
EndpointOauth2 = EndpointOAuth2
EndpointOauth2Applications = EndpointOAuth2Applications
EndpointOauth2Application = EndpointOAuth2Application
EndpointOauth2ApplicationsBot = EndpointOAuth2ApplicationsBot
EndpointOauth2ApplicationAssets = EndpointOAuth2ApplicationAssets
)

@ -157,7 +157,7 @@ func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance
onceHandlers := s.onceHandlers[t]
for i := range onceHandlers {
if onceHandlers[i] == ehi {
s.onceHandlers[t] = append(onceHandlers[:i], handlers[i+1:]...)
s.onceHandlers[t] = append(onceHandlers[:i], onceHandlers[i+1:]...)
}
}
}

@ -7,50 +7,62 @@ package discordgo
// Event type values are used to match the events returned by Discord.
// EventTypes surrounded by __ are synthetic and are internal to DiscordGo.
const (
channelCreateEventType = "CHANNEL_CREATE"
channelDeleteEventType = "CHANNEL_DELETE"
channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE"
channelUpdateEventType = "CHANNEL_UPDATE"
connectEventType = "__CONNECT__"
disconnectEventType = "__DISCONNECT__"
eventEventType = "__EVENT__"
guildBanAddEventType = "GUILD_BAN_ADD"
guildBanRemoveEventType = "GUILD_BAN_REMOVE"
guildCreateEventType = "GUILD_CREATE"
guildDeleteEventType = "GUILD_DELETE"
guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE"
guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE"
guildMemberAddEventType = "GUILD_MEMBER_ADD"
guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE"
guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE"
guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK"
guildRoleCreateEventType = "GUILD_ROLE_CREATE"
guildRoleDeleteEventType = "GUILD_ROLE_DELETE"
guildRoleUpdateEventType = "GUILD_ROLE_UPDATE"
guildUpdateEventType = "GUILD_UPDATE"
messageAckEventType = "MESSAGE_ACK"
messageCreateEventType = "MESSAGE_CREATE"
messageDeleteEventType = "MESSAGE_DELETE"
messageDeleteBulkEventType = "MESSAGE_DELETE_BULK"
messageReactionAddEventType = "MESSAGE_REACTION_ADD"
messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE"
messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
messageUpdateEventType = "MESSAGE_UPDATE"
presenceUpdateEventType = "PRESENCE_UPDATE"
presencesReplaceEventType = "PRESENCES_REPLACE"
rateLimitEventType = "__RATE_LIMIT__"
readyEventType = "READY"
relationshipAddEventType = "RELATIONSHIP_ADD"
relationshipRemoveEventType = "RELATIONSHIP_REMOVE"
resumedEventType = "RESUMED"
typingStartEventType = "TYPING_START"
userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE"
userNoteUpdateEventType = "USER_NOTE_UPDATE"
userSettingsUpdateEventType = "USER_SETTINGS_UPDATE"
userUpdateEventType = "USER_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE"
webhooksUpdateEventType = "WEBHOOKS_UPDATE"
channelCreateEventType = "CHANNEL_CREATE"
channelDeleteEventType = "CHANNEL_DELETE"
channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE"
channelUpdateEventType = "CHANNEL_UPDATE"
connectEventType = "__CONNECT__"
disconnectEventType = "__DISCONNECT__"
eventEventType = "__EVENT__"
guildBanAddEventType = "GUILD_BAN_ADD"
guildBanRemoveEventType = "GUILD_BAN_REMOVE"
guildCreateEventType = "GUILD_CREATE"
guildDeleteEventType = "GUILD_DELETE"
guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE"
guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE"
guildMemberAddEventType = "GUILD_MEMBER_ADD"
guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE"
guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE"
guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK"
guildRoleCreateEventType = "GUILD_ROLE_CREATE"
guildRoleDeleteEventType = "GUILD_ROLE_DELETE"
guildRoleUpdateEventType = "GUILD_ROLE_UPDATE"
guildUpdateEventType = "GUILD_UPDATE"
guildScheduledEventCreateEventType = "GUILD_SCHEDULED_EVENT_CREATE"
guildScheduledEventUpdateEventType = "GUILD_SCHEDULED_EVENT_UPDATE"
guildScheduledEventDeleteEventType = "GUILD_SCHEDULED_EVENT_DELETE"
interactionCreateEventType = "INTERACTION_CREATE"
inviteCreateEventType = "INVITE_CREATE"
inviteDeleteEventType = "INVITE_DELETE"
messageAckEventType = "MESSAGE_ACK"
messageCreateEventType = "MESSAGE_CREATE"
messageDeleteEventType = "MESSAGE_DELETE"
messageDeleteBulkEventType = "MESSAGE_DELETE_BULK"
messageReactionAddEventType = "MESSAGE_REACTION_ADD"
messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE"
messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
messageUpdateEventType = "MESSAGE_UPDATE"
presenceUpdateEventType = "PRESENCE_UPDATE"
presencesReplaceEventType = "PRESENCES_REPLACE"
rateLimitEventType = "__RATE_LIMIT__"
readyEventType = "READY"
relationshipAddEventType = "RELATIONSHIP_ADD"
relationshipRemoveEventType = "RELATIONSHIP_REMOVE"
resumedEventType = "RESUMED"
threadCreateEventType = "THREAD_CREATE"
threadDeleteEventType = "THREAD_DELETE"
threadListSyncEventType = "THREAD_LIST_SYNC"
threadMemberUpdateEventType = "THREAD_MEMBER_UPDATE"
threadMembersUpdateEventType = "THREAD_MEMBERS_UPDATE"
threadUpdateEventType = "THREAD_UPDATE"
typingStartEventType = "TYPING_START"
userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE"
userNoteUpdateEventType = "USER_NOTE_UPDATE"
userSettingsUpdateEventType = "USER_SETTINGS_UPDATE"
userUpdateEventType = "USER_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE"
webhooksUpdateEventType = "WEBHOOKS_UPDATE"
)
// channelCreateEventHandler is an event handler for ChannelCreate events.
@ -298,6 +310,66 @@ func (eh guildIntegrationsUpdateEventHandler) Handle(s *Session, i interface{})
}
}
// guildScheduledEventCreateEventHandler is an event handler for GuildScheduledEventCreate events.
type guildScheduledEventCreateEventHandler func(*Session, *GuildScheduledEventCreate)
// Type returns the event type for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Type() string {
return guildScheduledEventCreateEventType
}
// New returns a new instance of GuildScheduledEventCreate.
func (eh guildScheduledEventCreateEventHandler) New() interface{} {
return &GuildScheduledEventCreate{}
}
// Handle is the handler for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventCreate); ok {
eh(s, t)
}
}
// guildScheduledEventUpdateEventHandler is an event handler for GuildScheduledEventUpdate events.
type guildScheduledEventUpdateEventHandler func(*Session, *GuildScheduledEventUpdate)
// Type returns the event type for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Type() string {
return guildScheduledEventUpdateEventType
}
// New returns a new instance of GuildScheduledEventUpdate.
func (eh guildScheduledEventUpdateEventHandler) New() interface{} {
return &GuildScheduledEventUpdate{}
}
// Handle is the handler for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventUpdate); ok {
eh(s, t)
}
}
// guildScheduledEventDeleteEventHandler is an event handler for GuildScheduledEventDelete events.
type guildScheduledEventDeleteEventHandler func(*Session, *GuildScheduledEventDelete)
// Type returns the event type for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Type() string {
return guildScheduledEventDeleteEventType
}
// New returns a new instance of GuildScheduledEventDelete.
func (eh guildScheduledEventDeleteEventHandler) New() interface{} {
return &GuildScheduledEventDelete{}
}
// Handle is the handler for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventDelete); ok {
eh(s, t)
}
}
// guildMemberAddEventHandler is an event handler for GuildMemberAdd events.
type guildMemberAddEventHandler func(*Session, *GuildMemberAdd)
@ -458,6 +530,66 @@ func (eh guildUpdateEventHandler) Handle(s *Session, i interface{}) {
}
}
// interactionCreateEventHandler is an event handler for InteractionCreate events.
type interactionCreateEventHandler func(*Session, *InteractionCreate)
// Type returns the event type for InteractionCreate events.
func (eh interactionCreateEventHandler) Type() string {
return interactionCreateEventType
}
// New returns a new instance of InteractionCreate.
func (eh interactionCreateEventHandler) New() interface{} {
return &InteractionCreate{}
}
// Handle is the handler for InteractionCreate events.
func (eh interactionCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*InteractionCreate); ok {
eh(s, t)
}
}
// inviteCreateEventHandler is an event handler for InviteCreate events.
type inviteCreateEventHandler func(*Session, *InviteCreate)
// Type returns the event type for InviteCreate events.
func (eh inviteCreateEventHandler) Type() string {
return inviteCreateEventType
}
// New returns a new instance of InviteCreate.
func (eh inviteCreateEventHandler) New() interface{} {
return &InviteCreate{}
}
// Handle is the handler for InviteCreate events.
func (eh inviteCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*InviteCreate); ok {
eh(s, t)
}
}
// inviteDeleteEventHandler is an event handler for InviteDelete events.
type inviteDeleteEventHandler func(*Session, *InviteDelete)
// Type returns the event type for InviteDelete events.
func (eh inviteDeleteEventHandler) Type() string {
return inviteDeleteEventType
}
// New returns a new instance of InviteDelete.
func (eh inviteDeleteEventHandler) New() interface{} {
return &InviteDelete{}
}
// Handle is the handler for InviteDelete events.
func (eh inviteDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*InviteDelete); ok {
eh(s, t)
}
}
// messageAckEventHandler is an event handler for MessageAck events.
type messageAckEventHandler func(*Session, *MessageAck)
@ -753,6 +885,126 @@ func (eh resumedEventHandler) Handle(s *Session, i interface{}) {
}
}
// threadCreateEventHandler is an event handler for ThreadCreate events.
type threadCreateEventHandler func(*Session, *ThreadCreate)
// Type returns the event type for ThreadCreate events.
func (eh threadCreateEventHandler) Type() string {
return threadCreateEventType
}
// New returns a new instance of ThreadCreate.
func (eh threadCreateEventHandler) New() interface{} {
return &ThreadCreate{}
}
// Handle is the handler for ThreadCreate events.
func (eh threadCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*ThreadCreate); ok {
eh(s, t)
}
}
// threadDeleteEventHandler is an event handler for ThreadDelete events.
type threadDeleteEventHandler func(*Session, *ThreadDelete)
// Type returns the event type for ThreadDelete events.
func (eh threadDeleteEventHandler) Type() string {
return threadDeleteEventType
}
// New returns a new instance of ThreadDelete.
func (eh threadDeleteEventHandler) New() interface{} {
return &ThreadDelete{}
}
// Handle is the handler for ThreadDelete events.
func (eh threadDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*ThreadDelete); ok {
eh(s, t)
}
}
// threadListSyncEventHandler is an event handler for ThreadListSync events.
type threadListSyncEventHandler func(*Session, *ThreadListSync)
// Type returns the event type for ThreadListSync events.
func (eh threadListSyncEventHandler) Type() string {
return threadListSyncEventType
}
// New returns a new instance of ThreadListSync.
func (eh threadListSyncEventHandler) New() interface{} {
return &ThreadListSync{}
}
// Handle is the handler for ThreadListSync events.
func (eh threadListSyncEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*ThreadListSync); ok {
eh(s, t)
}
}
// threadMemberUpdateEventHandler is an event handler for ThreadMemberUpdate events.
type threadMemberUpdateEventHandler func(*Session, *ThreadMemberUpdate)
// Type returns the event type for ThreadMemberUpdate events.
func (eh threadMemberUpdateEventHandler) Type() string {
return threadMemberUpdateEventType
}
// New returns a new instance of ThreadMemberUpdate.
func (eh threadMemberUpdateEventHandler) New() interface{} {
return &ThreadMemberUpdate{}
}
// Handle is the handler for ThreadMemberUpdate events.
func (eh threadMemberUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*ThreadMemberUpdate); ok {
eh(s, t)
}
}
// threadMembersUpdateEventHandler is an event handler for ThreadMembersUpdate events.
type threadMembersUpdateEventHandler func(*Session, *ThreadMembersUpdate)
// Type returns the event type for ThreadMembersUpdate events.
func (eh threadMembersUpdateEventHandler) Type() string {
return threadMembersUpdateEventType
}
// New returns a new instance of ThreadMembersUpdate.
func (eh threadMembersUpdateEventHandler) New() interface{} {
return &ThreadMembersUpdate{}
}
// Handle is the handler for ThreadMembersUpdate events.
func (eh threadMembersUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*ThreadMembersUpdate); ok {
eh(s, t)
}
}
// threadUpdateEventHandler is an event handler for ThreadUpdate events.
type threadUpdateEventHandler func(*Session, *ThreadUpdate)
// Type returns the event type for ThreadUpdate events.
func (eh threadUpdateEventHandler) Type() string {
return threadUpdateEventType
}
// New returns a new instance of ThreadUpdate.
func (eh threadUpdateEventHandler) New() interface{} {
return &ThreadUpdate{}
}
// Handle is the handler for ThreadUpdate events.
func (eh threadUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*ThreadUpdate); ok {
eh(s, t)
}
}
// typingStartEventHandler is an event handler for TypingStart events.
type typingStartEventHandler func(*Session, *TypingStart)
@ -943,6 +1195,12 @@ func handlerForInterface(handler interface{}) EventHandler {
return guildEmojisUpdateEventHandler(v)
case func(*Session, *GuildIntegrationsUpdate):
return guildIntegrationsUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventCreate):
return guildScheduledEventCreateEventHandler(v)
case func(*Session, *GuildScheduledEventUpdate):
return guildScheduledEventUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventDelete):
return guildScheduledEventDeleteEventHandler(v)
case func(*Session, *GuildMemberAdd):
return guildMemberAddEventHandler(v)
case func(*Session, *GuildMemberRemove):
@ -959,6 +1217,12 @@ func handlerForInterface(handler interface{}) EventHandler {
return guildRoleUpdateEventHandler(v)
case func(*Session, *GuildUpdate):
return guildUpdateEventHandler(v)
case func(*Session, *InteractionCreate):
return interactionCreateEventHandler(v)
case func(*Session, *InviteCreate):
return inviteCreateEventHandler(v)
case func(*Session, *InviteDelete):
return inviteDeleteEventHandler(v)
case func(*Session, *MessageAck):
return messageAckEventHandler(v)
case func(*Session, *MessageCreate):
@ -989,6 +1253,18 @@ func handlerForInterface(handler interface{}) EventHandler {
return relationshipRemoveEventHandler(v)
case func(*Session, *Resumed):
return resumedEventHandler(v)
case func(*Session, *ThreadCreate):
return threadCreateEventHandler(v)
case func(*Session, *ThreadDelete):
return threadDeleteEventHandler(v)
case func(*Session, *ThreadListSync):
return threadListSyncEventHandler(v)
case func(*Session, *ThreadMemberUpdate):
return threadMemberUpdateEventHandler(v)
case func(*Session, *ThreadMembersUpdate):
return threadMembersUpdateEventHandler(v)
case func(*Session, *ThreadUpdate):
return threadUpdateEventHandler(v)
case func(*Session, *TypingStart):
return typingStartEventHandler(v)
case func(*Session, *UserGuildSettingsUpdate):
@ -1021,6 +1297,9 @@ func init() {
registerInterfaceProvider(guildDeleteEventHandler(nil))
registerInterfaceProvider(guildEmojisUpdateEventHandler(nil))
registerInterfaceProvider(guildIntegrationsUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventCreateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventDeleteEventHandler(nil))
registerInterfaceProvider(guildMemberAddEventHandler(nil))
registerInterfaceProvider(guildMemberRemoveEventHandler(nil))
registerInterfaceProvider(guildMemberUpdateEventHandler(nil))
@ -1029,6 +1308,9 @@ func init() {
registerInterfaceProvider(guildRoleDeleteEventHandler(nil))
registerInterfaceProvider(guildRoleUpdateEventHandler(nil))
registerInterfaceProvider(guildUpdateEventHandler(nil))
registerInterfaceProvider(interactionCreateEventHandler(nil))
registerInterfaceProvider(inviteCreateEventHandler(nil))
registerInterfaceProvider(inviteDeleteEventHandler(nil))
registerInterfaceProvider(messageAckEventHandler(nil))
registerInterfaceProvider(messageCreateEventHandler(nil))
registerInterfaceProvider(messageDeleteEventHandler(nil))
@ -1043,6 +1325,12 @@ func init() {
registerInterfaceProvider(relationshipAddEventHandler(nil))
registerInterfaceProvider(relationshipRemoveEventHandler(nil))
registerInterfaceProvider(resumedEventHandler(nil))
registerInterfaceProvider(threadCreateEventHandler(nil))
registerInterfaceProvider(threadDeleteEventHandler(nil))
registerInterfaceProvider(threadListSyncEventHandler(nil))
registerInterfaceProvider(threadMemberUpdateEventHandler(nil))
registerInterfaceProvider(threadMembersUpdateEventHandler(nil))
registerInterfaceProvider(threadUpdateEventHandler(nil))
registerInterfaceProvider(typingStartEventHandler(nil))
registerInterfaceProvider(userGuildSettingsUpdateEventHandler(nil))
registerInterfaceProvider(userNoteUpdateEventHandler(nil))

@ -73,6 +73,53 @@ type ChannelPinsUpdate struct {
GuildID string `json:"guild_id,omitempty"`
}
// ThreadCreate is the data for a ThreadCreate event.
type ThreadCreate struct {
*Channel
NewlyCreated bool `json:"newly_created"`
}
// ThreadUpdate is the data for a ThreadUpdate event.
type ThreadUpdate struct {
*Channel
BeforeUpdate *Channel `json:"-"`
}
// ThreadDelete is the data for a ThreadDelete event.
type ThreadDelete struct {
*Channel
}
// ThreadListSync is the data for a ThreadListSync event.
type ThreadListSync struct {
// The id of the guild
GuildID string `json:"guild_id"`
// The parent channel ids whose threads are being synced.
// If omitted, then threads were synced for the entire guild.
// This array may contain channel_ids that have no active threads as well, so you know to clear that data.
ChannelIDs []string `json:"channel_ids"`
// All active threads in the given channels that the current user can access
Threads []*Channel `json:"threads"`
// All thread member objects from the synced threads for the current user,
// indicating which threads the current user has been added to
Members []*ThreadMember `json:"members"`
}
// ThreadMemberUpdate is the data for a ThreadMemberUpdate event.
type ThreadMemberUpdate struct {
*ThreadMember
GuildID string `json:"guild_id"`
}
// ThreadMembersUpdate is the data for a ThreadMembersUpdate event.
type ThreadMembersUpdate struct {
ID string `json:"id"`
GuildID string `json:"guild_id"`
MemberCount int `json:"member_count"`
AddedMembers []AddedThreadMember `json:"added_members"`
RemovedMembers []string `json:"removed_member_ids"`
}
// GuildCreate is the data for a GuildCreate event.
type GuildCreate struct {
*Guild
@ -86,6 +133,7 @@ type GuildUpdate struct {
// GuildDelete is the data for a GuildDelete event.
type GuildDelete struct {
*Guild
BeforeDelete *Guild `json:"-"`
}
// GuildBanAdd is the data for a GuildBanAdd event.
@ -151,6 +199,21 @@ type GuildIntegrationsUpdate struct {
GuildID string `json:"guild_id"`
}
// GuildScheduledEventCreate is the data for a GuildScheduledEventCreate event.
type GuildScheduledEventCreate struct {
*GuildScheduledEvent
}
// GuildScheduledEventUpdate is the data for a GuildScheduledEventUpdate event.
type GuildScheduledEventUpdate struct {
*GuildScheduledEvent
}
// GuildScheduledEventDelete is the data for a GuildScheduledEventDelete event.
type GuildScheduledEventDelete struct {
*GuildScheduledEvent
}
// MessageAck is the data for a MessageAck event.
type MessageAck struct {
MessageID string `json:"message_id"`
@ -162,6 +225,11 @@ type MessageCreate struct {
*Message
}
// UnmarshalJSON is a helper function to unmarshal MessageCreate object.
func (m *MessageCreate) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &m.Message)
}
// MessageUpdate is the data for a MessageUpdate event.
type MessageUpdate struct {
*Message
@ -169,15 +237,26 @@ type MessageUpdate struct {
BeforeUpdate *Message `json:"-"`
}
// UnmarshalJSON is a helper function to unmarshal MessageUpdate object.
func (m *MessageUpdate) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &m.Message)
}
// MessageDelete is the data for a MessageDelete event.
type MessageDelete struct {
*Message
BeforeDelete *Message `json:"-"`
}
// UnmarshalJSON is a helper function to unmarshal MessageDelete object.
func (m *MessageDelete) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &m.Message)
}
// MessageReactionAdd is the data for a MessageReactionAdd event.
type MessageReactionAdd struct {
*MessageReaction
Member *Member `json:"member,omitempty"`
}
// MessageReactionRemove is the data for a MessageReactionRemove event.
@ -267,3 +346,27 @@ type WebhooksUpdate struct {
GuildID string `json:"guild_id"`
ChannelID string `json:"channel_id"`
}
// InteractionCreate is the data for a InteractionCreate event
type InteractionCreate struct {
*Interaction
}
// UnmarshalJSON is a helper function to unmarshal Interaction object.
func (i *InteractionCreate) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &i.Interaction)
}
// InviteCreate is the data for a InviteCreate event
type InviteCreate struct {
*Invite
ChannelID string `json:"channel_id"`
GuildID string `json:"guild_id"`
}
// InviteDelete is the data for a InviteDelete event
type InviteDelete struct {
ChannelID string `json:"channel_id"`
GuildID string `json:"guild_id"`
Code string `json:"code"`
}

@ -0,0 +1,568 @@
package discordgo
import (
"bytes"
"crypto/ed25519"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
)
// InteractionDeadline is the time allowed to respond to an interaction.
const InteractionDeadline = time.Second * 3
// ApplicationCommandType represents the type of application command.
type ApplicationCommandType uint8
// Application command types
const (
// ChatApplicationCommand is default command type. They are slash commands (i.e. called directly from the chat).
ChatApplicationCommand ApplicationCommandType = 1
// UserApplicationCommand adds command to user context menu.
UserApplicationCommand ApplicationCommandType = 2
// MessageApplicationCommand adds command to message context menu.
MessageApplicationCommand ApplicationCommandType = 3
)
// ApplicationCommand represents an application's slash command.
type ApplicationCommand struct {
ID string `json:"id,omitempty"`
ApplicationID string `json:"application_id,omitempty"`
Version string `json:"version,omitempty"`
Type ApplicationCommandType `json:"type,omitempty"`
Name string `json:"name"`
DefaultPermission *bool `json:"default_permission,omitempty"`
// NOTE: Chat commands only. Otherwise it mustn't be set.
Description string `json:"description,omitempty"`
Options []*ApplicationCommandOption `json:"options"`
}
// ApplicationCommandOptionType indicates the type of a slash command's option.
type ApplicationCommandOptionType uint8
// Application command option types.
const (
ApplicationCommandOptionSubCommand ApplicationCommandOptionType = 1
ApplicationCommandOptionSubCommandGroup ApplicationCommandOptionType = 2
ApplicationCommandOptionString ApplicationCommandOptionType = 3
ApplicationCommandOptionInteger ApplicationCommandOptionType = 4
ApplicationCommandOptionBoolean ApplicationCommandOptionType = 5
ApplicationCommandOptionUser ApplicationCommandOptionType = 6
ApplicationCommandOptionChannel ApplicationCommandOptionType = 7
ApplicationCommandOptionRole ApplicationCommandOptionType = 8
ApplicationCommandOptionMentionable ApplicationCommandOptionType = 9
ApplicationCommandOptionNumber ApplicationCommandOptionType = 10
ApplicationCommandOptionAttachment ApplicationCommandOptionType = 11
)
func (t ApplicationCommandOptionType) String() string {
switch t {
case ApplicationCommandOptionSubCommand:
return "SubCommand"
case ApplicationCommandOptionSubCommandGroup:
return "SubCommandGroup"
case ApplicationCommandOptionString:
return "String"
case ApplicationCommandOptionInteger:
return "Integer"
case ApplicationCommandOptionBoolean:
return "Boolean"
case ApplicationCommandOptionUser:
return "User"
case ApplicationCommandOptionChannel:
return "Channel"
case ApplicationCommandOptionRole:
return "Role"
case ApplicationCommandOptionMentionable:
return "Mentionable"
case ApplicationCommandOptionNumber:
return "Number"
case ApplicationCommandOptionAttachment:
return "Attachment"
}
return fmt.Sprintf("ApplicationCommandOptionType(%d)", t)
}
// ApplicationCommandOption represents an option/subcommand/subcommands group.
type ApplicationCommandOption struct {
Type ApplicationCommandOptionType `json:"type"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
// NOTE: This feature was on the API, but at some point developers decided to remove it.
// So I commented it, until it will be officially on the docs.
// Default bool `json:"default"`
ChannelTypes []ChannelType `json:"channel_types"`
Required bool `json:"required"`
Options []*ApplicationCommandOption `json:"options"`
// NOTE: mutually exclusive with Choices.
Autocomplete bool `json:"autocomplete"`
Choices []*ApplicationCommandOptionChoice `json:"choices"`
// Minimal value of number/integer option.
MinValue *float64 `json:"min_value,omitempty"`
// Maximum value of number/integer option.
MaxValue float64 `json:"max_value,omitempty"`
}
// ApplicationCommandOptionChoice represents a slash command option choice.
type ApplicationCommandOptionChoice struct {
Name string `json:"name"`
Value interface{} `json:"value"`
}
// ApplicationCommandPermissions represents a single user or role permission for a command.
type ApplicationCommandPermissions struct {
ID string `json:"id"`
Type ApplicationCommandPermissionType `json:"type"`
Permission bool `json:"permission"`
}
// ApplicationCommandPermissionsList represents a list of ApplicationCommandPermissions, needed for serializing to JSON.
type ApplicationCommandPermissionsList struct {
Permissions []*ApplicationCommandPermissions `json:"permissions"`
}
// GuildApplicationCommandPermissions represents all permissions for a single guild command.
type GuildApplicationCommandPermissions struct {
ID string `json:"id"`
ApplicationID string `json:"application_id"`
GuildID string `json:"guild_id"`
Permissions []*ApplicationCommandPermissions `json:"permissions"`
}
// ApplicationCommandPermissionType indicates whether a permission is user or role based.
type ApplicationCommandPermissionType uint8
// Application command permission types.
const (
ApplicationCommandPermissionTypeRole ApplicationCommandPermissionType = 1
ApplicationCommandPermissionTypeUser ApplicationCommandPermissionType = 2
)
// InteractionType indicates the type of an interaction event.
type InteractionType uint8
// Interaction types
const (
InteractionPing InteractionType = 1
InteractionApplicationCommand InteractionType = 2
InteractionMessageComponent InteractionType = 3
InteractionApplicationCommandAutocomplete InteractionType = 4
InteractionModalSubmit InteractionType = 5
)
func (t InteractionType) String() string {
switch t {
case InteractionPing:
return "Ping"
case InteractionApplicationCommand:
return "ApplicationCommand"
case InteractionMessageComponent:
return "MessageComponent"
case InteractionModalSubmit:
return "ModalSubmit"
}
return fmt.Sprintf("InteractionType(%d)", t)
}
// Interaction represents data of an interaction.
type Interaction struct {
ID string `json:"id"`
Type InteractionType `json:"type"`
Data InteractionData `json:"data"`
GuildID string `json:"guild_id"`
ChannelID string `json:"channel_id"`
// The message on which interaction was used.
// NOTE: this field is only filled when a button click triggered the interaction. Otherwise it will be nil.
Message *Message `json:"message"`
// The member who invoked this interaction.
// NOTE: this field is only filled when the slash command was invoked in a guild;
// if it was invoked in a DM, the `User` field will be filled instead.
// Make sure to check for `nil` before using this field.
Member *Member `json:"member"`
// The user who invoked this interaction.
// NOTE: this field is only filled when the slash command was invoked in a DM;
// if it was invoked in a guild, the `Member` field will be filled instead.
// Make sure to check for `nil` before using this field.
User *User `json:"user"`
// The user's discord client locale.
Locale Locale `json:"locale"`
// The guild's locale. This defaults to EnglishUS
// NOTE: this field is only filled when the interaction was invoked in a guild.
GuildLocale *Locale `json:"guild_locale"`
Token string `json:"token"`
Version int `json:"version"`
}
type interaction Interaction
type rawInteraction struct {
interaction
Data json.RawMessage `json:"data"`
}
// UnmarshalJSON is a method for unmarshalling JSON object to Interaction.
func (i *Interaction) UnmarshalJSON(raw []byte) error {
var tmp rawInteraction
err := json.Unmarshal(raw, &tmp)
if err != nil {
return err
}
*i = Interaction(tmp.interaction)
switch tmp.Type {
case InteractionApplicationCommand, InteractionApplicationCommandAutocomplete:
v := ApplicationCommandInteractionData{}
err = json.Unmarshal(tmp.Data, &v)
if err != nil {
return err
}
i.Data = v
case InteractionMessageComponent:
v := MessageComponentInteractionData{}
err = json.Unmarshal(tmp.Data, &v)
if err != nil {
return err
}
i.Data = v
case InteractionModalSubmit:
v := ModalSubmitInteractionData{}
err = json.Unmarshal(tmp.Data, &v)
if err != nil {
return err
}
i.Data = v
}
return nil
}
// MessageComponentData is helper function to assert the inner InteractionData to MessageComponentInteractionData.
// Make sure to check that the Type of the interaction is InteractionMessageComponent before calling.
func (i Interaction) MessageComponentData() (data MessageComponentInteractionData) {
if i.Type != InteractionMessageComponent {
panic("MessageComponentData called on interaction of type " + i.Type.String())
}
return i.Data.(MessageComponentInteractionData)
}
// ApplicationCommandData is helper function to assert the inner InteractionData to ApplicationCommandInteractionData.
// Make sure to check that the Type of the interaction is InteractionApplicationCommand before calling.
func (i Interaction) ApplicationCommandData() (data ApplicationCommandInteractionData) {
if i.Type != InteractionApplicationCommand && i.Type != InteractionApplicationCommandAutocomplete {
panic("ApplicationCommandData called on interaction of type " + i.Type.String())
}
return i.Data.(ApplicationCommandInteractionData)
}
// ModalSubmitData is helper function to assert the inner InteractionData to ModalSubmitInteractionData.
// Make sure to check that the Type of the interaction is InteractionModalSubmit before calling.
func (i Interaction) ModalSubmitData() (data ModalSubmitInteractionData) {
if i.Type != InteractionModalSubmit {
panic("ModalSubmitData called on interaction of type " + i.Type.String())
}
return i.Data.(ModalSubmitInteractionData)
}
// InteractionData is a common interface for all types of interaction data.
type InteractionData interface {
Type() InteractionType
}
// ApplicationCommandInteractionData contains the data of application command interaction.
type ApplicationCommandInteractionData struct {
ID string `json:"id"`
Name string `json:"name"`
Resolved *ApplicationCommandInteractionDataResolved `json:"resolved"`
// Slash command options
Options []*ApplicationCommandInteractionDataOption `json:"options"`
// Target (user/message) id on which context menu command was called.
// The details are stored in Resolved according to command type.
TargetID string `json:"target_id"`
}
// ApplicationCommandInteractionDataResolved contains resolved data of command execution.
// Partial Member objects are missing user, deaf and mute fields.
// Partial Channel objects only have id, name, type and permissions fields.
type ApplicationCommandInteractionDataResolved struct {
Users map[string]*User `json:"users"`
Members map[string]*Member `json:"members"`
Roles map[string]*Role `json:"roles"`
Channels map[string]*Channel `json:"channels"`
Messages map[string]*Message `json:"messages"`
Attachments map[string]*MessageAttachment `json:"attachments"`
}
// Type returns the type of interaction data.
func (ApplicationCommandInteractionData) Type() InteractionType {
return InteractionApplicationCommand
}
// MessageComponentInteractionData contains the data of message component interaction.
type MessageComponentInteractionData struct {
CustomID string `json:"custom_id"`
ComponentType ComponentType `json:"component_type"`
// NOTE: Only filled when ComponentType is SelectMenuComponent (3). Otherwise is nil.
Values []string `json:"values"`
}
// Type returns the type of interaction data.
func (MessageComponentInteractionData) Type() InteractionType {
return InteractionMessageComponent
}
// ModalSubmitInteractionData contains the data of modal submit interaction.
type ModalSubmitInteractionData struct {
CustomID string `json:"custom_id"`
Components []MessageComponent `json:"-"`
}
// Type returns the type of interaction data.
func (ModalSubmitInteractionData) Type() InteractionType {
return InteractionModalSubmit
}
// UnmarshalJSON is a helper function to correctly unmarshal Components.
func (d *ModalSubmitInteractionData) UnmarshalJSON(data []byte) error {
type modalSubmitInteractionData ModalSubmitInteractionData
var v struct {
modalSubmitInteractionData
RawComponents []unmarshalableMessageComponent `json:"components"`
}
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
*d = ModalSubmitInteractionData(v.modalSubmitInteractionData)
d.Components = make([]MessageComponent, len(v.RawComponents))
for i, v := range v.RawComponents {
d.Components[i] = v.MessageComponent
}
return err
}
// ApplicationCommandInteractionDataOption represents an option of a slash command.
type ApplicationCommandInteractionDataOption struct {
Name string `json:"name"`
Type ApplicationCommandOptionType `json:"type"`
// NOTE: Contains the value specified by Type.
Value interface{} `json:"value,omitempty"`
Options []*ApplicationCommandInteractionDataOption `json:"options,omitempty"`
// NOTE: autocomplete interaction only.
Focused bool `json:"focused,omitempty"`
}
// IntValue is a utility function for casting option value to integer
func (o ApplicationCommandInteractionDataOption) IntValue() int64 {
if o.Type != ApplicationCommandOptionInteger {
panic("IntValue called on data option of type " + o.Type.String())
}
return int64(o.Value.(float64))
}
// UintValue is a utility function for casting option value to unsigned integer
func (o ApplicationCommandInteractionDataOption) UintValue() uint64 {
if o.Type != ApplicationCommandOptionInteger {
panic("UintValue called on data option of type " + o.Type.String())
}
return uint64(o.Value.(float64))
}
// FloatValue is a utility function for casting option value to float
func (o ApplicationCommandInteractionDataOption) FloatValue() float64 {
if o.Type != ApplicationCommandOptionNumber {
panic("FloatValue called on data option of type " + o.Type.String())
}
return o.Value.(float64)
}
// StringValue is a utility function for casting option value to string
func (o ApplicationCommandInteractionDataOption) StringValue() string {
if o.Type != ApplicationCommandOptionString {
panic("StringValue called on data option of type " + o.Type.String())
}
return o.Value.(string)
}
// BoolValue is a utility function for casting option value to bool
func (o ApplicationCommandInteractionDataOption) BoolValue() bool {
if o.Type != ApplicationCommandOptionBoolean {
panic("BoolValue called on data option of type " + o.Type.String())
}
return o.Value.(bool)
}
// ChannelValue is a utility function for casting option value to channel object.
// s : Session object, if not nil, function additionally fetches all channel's data
func (o ApplicationCommandInteractionDataOption) ChannelValue(s *Session) *Channel {
if o.Type != ApplicationCommandOptionChannel {
panic("ChannelValue called on data option of type " + o.Type.String())
}
chanID := o.Value.(string)
if s == nil {
return &Channel{ID: chanID}
}
ch, err := s.State.Channel(chanID)
if err != nil {
ch, err = s.Channel(chanID)
if err != nil {
return &Channel{ID: chanID}
}
}
return ch
}
// RoleValue is a utility function for casting option value to role object.
// s : Session object, if not nil, function additionally fetches all role's data
func (o ApplicationCommandInteractionDataOption) RoleValue(s *Session, gID string) *Role {
if o.Type != ApplicationCommandOptionRole && o.Type != ApplicationCommandOptionMentionable {
panic("RoleValue called on data option of type " + o.Type.String())
}
roleID := o.Value.(string)
if s == nil || gID == "" {
return &Role{ID: roleID}
}
r, err := s.State.Role(roleID, gID)
if err != nil {
roles, err := s.GuildRoles(gID)
if err == nil {
for _, r = range roles {
if r.ID == roleID {
return r
}
}
}
return &Role{ID: roleID}
}
return r
}
// UserValue is a utility function for casting option value to user object.
// s : Session object, if not nil, function additionally fetches all user's data
func (o ApplicationCommandInteractionDataOption) UserValue(s *Session) *User {
if o.Type != ApplicationCommandOptionUser && o.Type != ApplicationCommandOptionMentionable {
panic("UserValue called on data option of type " + o.Type.String())
}
userID := o.Value.(string)
if s == nil {
return &User{ID: userID}
}
u, err := s.User(userID)
if err != nil {
return &User{ID: userID}
}
return u
}
// InteractionResponseType is type of interaction response.
type InteractionResponseType uint8
// Interaction response types.
const (
// InteractionResponsePong is for ACK ping event.
InteractionResponsePong InteractionResponseType = 1
// InteractionResponseChannelMessageWithSource is for responding with a message, showing the user's input.
InteractionResponseChannelMessageWithSource InteractionResponseType = 4
// InteractionResponseDeferredChannelMessageWithSource acknowledges that the event was received, and that a follow-up will come later.
InteractionResponseDeferredChannelMessageWithSource InteractionResponseType = 5
// InteractionResponseDeferredMessageUpdate acknowledges that the message component interaction event was received, and message will be updated later.
InteractionResponseDeferredMessageUpdate InteractionResponseType = 6
// InteractionResponseUpdateMessage is for updating the message to which message component was attached.
InteractionResponseUpdateMessage InteractionResponseType = 7
// InteractionApplicationCommandAutocompleteResult shows autocompletion results. Autocomplete interaction only.
InteractionApplicationCommandAutocompleteResult InteractionResponseType = 8
// InteractionResponseModal is for responding to an interaction with a modal window.
InteractionResponseModal InteractionResponseType = 9
)
// InteractionResponse represents a response for an interaction event.
type InteractionResponse struct {
Type InteractionResponseType `json:"type,omitempty"`
Data *InteractionResponseData `json:"data,omitempty"`
}
// InteractionResponseData is response data for an interaction.
type InteractionResponseData struct {
TTS bool `json:"tts"`
Content string `json:"content"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Flags uint64 `json:"flags,omitempty"`
Files []*File `json:"-"`
// NOTE: autocomplete interaction only.
Choices []*ApplicationCommandOptionChoice `json:"choices,omitempty"`
// NOTE: modal interaction only.
CustomID string `json:"custom_id,omitempty"`
Title string `json:"title,omitempty"`
}
// VerifyInteraction implements message verification of the discord interactions api
// signing algorithm, as documented here:
// https://discord.com/developers/docs/interactions/receiving-and-responding#security-and-authorization
func VerifyInteraction(r *http.Request, key ed25519.PublicKey) bool {
var msg bytes.Buffer
signature := r.Header.Get("X-Signature-Ed25519")
if signature == "" {
return false
}
sig, err := hex.DecodeString(signature)
if err != nil {
return false
}
if len(sig) != ed25519.SignatureSize {
return false
}
timestamp := r.Header.Get("X-Signature-Timestamp")
if timestamp == "" {
return false
}
msg.WriteString(timestamp)
defer r.Body.Close()
var body bytes.Buffer
// at the end of the function, copy the original body back into the request
defer func() {
r.Body = ioutil.NopCloser(&body)
}()
// copy body into buffers
_, err = io.Copy(&msg, io.TeeReader(r.Body, &body))
if err != nil {
return false
}
return ed25519.Verify(key, msg.Bytes(), sig)
}

@ -0,0 +1,83 @@
package discordgo
// Locale represents the accepted languages for Discord.
// https://discord.com/developers/docs/reference#locales
type Locale string
// String returns the human-readable string of the locale
func (l Locale) String() string {
if name, ok := Locales[l]; ok {
return name
}
return Unknown.String()
}
// All defined locales in Discord
const (
EnglishUS Locale = "en-US"
EnglishGB Locale = "en-GB"
Bulgarian Locale = "bg"
ChineseCN Locale = "zh-CN"
ChineseTW Locale = "zh-TW"
Croatian Locale = "hr"
Czech Locale = "cs"
Danish Locale = "da"
Dutch Locale = "nl"
Finnish Locale = "fi"
French Locale = "fr"
German Locale = "de"
Greek Locale = "el"
Hindi Locale = "hi"
Hungarian Locale = "hu"
Italian Locale = "it"
Japanese Locale = "ja"
Korean Locale = "ko"
Lithuanian Locale = "lt"
Norwegian Locale = "no"
Polish Locale = "pl"
PortugueseBR Locale = "pt-BR"
Romanian Locale = "ro"
Russian Locale = "ru"
SpanishES Locale = "es-ES"
Swedish Locale = "sv-SE"
Thai Locale = "th"
Turkish Locale = "tr"
Ukrainian Locale = "uk"
Vietnamese Locale = "vi"
Unknown Locale = ""
)
// Locales is a map of all the languages codes to their names.
var Locales = map[Locale]string{
EnglishUS: "English (United States)",
EnglishGB: "English (Great Britain)",
Bulgarian: "Bulgarian",
ChineseCN: "Chinese (China)",
ChineseTW: "Chinese (Taiwan)",
Croatian: "Croatian",
Czech: "Czech",
Danish: "Danish",
Dutch: "Dutch",
Finnish: "Finnish",
French: "French",
German: "German",
Greek: "Greek",
Hindi: "Hindi",
Hungarian: "Hungarian",
Italian: "Italian",
Japanese: "Japanese",
Korean: "Korean",
Lithuanian: "Lithuanian",
Norwegian: "Norwegian",
Polish: "Polish",
PortugueseBR: "Portuguese (Brazil)",
Romanian: "Romanian",
Russian: "Russian",
SpanishES: "Spanish (Spain)",
Swedish: "Swedish",
Thai: "Thai",
Turkish: "Turkish",
Ukrainian: "Ukrainian",
Vietnamese: "Vietnamese",
Unknown: "unknown",
}

@ -10,9 +10,11 @@
package discordgo
import (
"encoding/json"
"io"
"regexp"
"strings"
"time"
)
// MessageType is the type of Message
@ -21,23 +23,26 @@ type MessageType int
// Block contains the valid known MessageType values
const (
MessageTypeDefault MessageType = iota
MessageTypeRecipientAdd
MessageTypeRecipientRemove
MessageTypeCall
MessageTypeChannelNameChange
MessageTypeChannelIconChange
MessageTypeChannelPinnedMessage
MessageTypeGuildMemberJoin
MessageTypeUserPremiumGuildSubscription
MessageTypeUserPremiumGuildSubscriptionTierOne
MessageTypeUserPremiumGuildSubscriptionTierTwo
MessageTypeUserPremiumGuildSubscriptionTierThree
MessageTypeChannelFollowAdd
MessageTypeGuildDiscoveryDisqualified = iota + 1
MessageTypeGuildDiscoveryRequalified
MessageTypeReply = iota + 4
MessageTypeApplicationCommand
MessageTypeDefault MessageType = 0
MessageTypeRecipientAdd MessageType = 1
MessageTypeRecipientRemove MessageType = 2
MessageTypeCall MessageType = 3
MessageTypeChannelNameChange MessageType = 4
MessageTypeChannelIconChange MessageType = 5
MessageTypeChannelPinnedMessage MessageType = 6
MessageTypeGuildMemberJoin MessageType = 7
MessageTypeUserPremiumGuildSubscription MessageType = 8
MessageTypeUserPremiumGuildSubscriptionTierOne MessageType = 9
MessageTypeUserPremiumGuildSubscriptionTierTwo MessageType = 10
MessageTypeUserPremiumGuildSubscriptionTierThree MessageType = 11
MessageTypeChannelFollowAdd MessageType = 12
MessageTypeGuildDiscoveryDisqualified MessageType = 14
MessageTypeGuildDiscoveryRequalified MessageType = 15
MessageTypeThreadCreated MessageType = 18
MessageTypeReply MessageType = 19
MessageTypeChatInputCommand MessageType = 20
MessageTypeThreadStarterMessage MessageType = 21
MessageTypeContextMenuCommand MessageType = 23
)
// A Message stores all data related to a specific Discord message.
@ -58,11 +63,11 @@ type Message struct {
// CAUTION: this field may be removed in a
// future API version; it is safer to calculate
// the creation time via the ID.
Timestamp Timestamp `json:"timestamp"`
Timestamp time.Time `json:"timestamp"`
// The time at which the last edit of the message
// occurred, if it has been edited.
EditedTimestamp Timestamp `json:"edited_timestamp"`
EditedTimestamp *time.Time `json:"edited_timestamp"`
// The roles mentioned in the message.
MentionRoles []string `json:"mention_roles"`
@ -80,8 +85,10 @@ type Message struct {
// A list of attachments present in the message.
Attachments []*MessageAttachment `json:"attachments"`
// A list of embeds present in the message. Multiple
// embeds can currently only be sent by webhooks.
// A list of components attached to the message.
Components []MessageComponent `json:"-"`
// A list of embeds present in the message.
Embeds []*MessageEmbed `json:"embeds"`
// A list of users mentioned in the message.
@ -116,13 +123,70 @@ type Message struct {
// Is sent with Rich Presence-related chat embeds
Application *MessageApplication `json:"application"`
// MessageReference contains reference data sent with crossposted messages
// MessageReference contains reference data sent with crossposted or reply messages.
// This does not contain the reference *to* this message; this is for when *this* message references another.
// To generate a reference to this message, use (*Message).Reference().
MessageReference *MessageReference `json:"message_reference"`
// The message associated with the message_reference
// NOTE: This field is only returned for messages with a type of 19 (REPLY) or 21 (THREAD_STARTER_MESSAGE).
// If the message is a reply but the referenced_message field is not present,
// the backend did not attempt to fetch the message that was being replied to, so its state is unknown.
// If the field exists but is null, the referenced message was deleted.
ReferencedMessage *Message `json:"referenced_message"`
// Is sent when the message is a response to an Interaction, without an existing message.
// This means responses to message component interactions do not include this property,
// instead including a MessageReference, as components exist on preexisting messages.
Interaction *MessageInteraction `json:"interaction"`
// The flags of the message, which describe extra features of a message.
// This is a combination of bit masks; the presence of a certain permission can
// be checked by performing a bitwise AND between this int and the flag.
Flags MessageFlags `json:"flags"`
// The thread that was started from this message, includes thread member object
Thread *Channel `json:"thread,omitempty"`
// An array of Sticker objects, if any were sent.
StickerItems []*Sticker `json:"sticker_items"`
}
// UnmarshalJSON is a helper function to unmarshal the Message.
func (m *Message) UnmarshalJSON(data []byte) error {
type message Message
var v struct {
message
RawComponents []unmarshalableMessageComponent `json:"components"`
}
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
*m = Message(v.message)
m.Components = make([]MessageComponent, len(v.RawComponents))
for i, v := range v.RawComponents {
m.Components[i] = v.MessageComponent
}
return err
}
// GetCustomEmojis pulls out all the custom (Non-unicode) emojis from a message and returns a Slice of the Emoji struct.
func (m *Message) GetCustomEmojis() []*Emoji {
var toReturn []*Emoji
emojis := EmojiRegex.FindAllString(m.Content, -1)
if len(emojis) < 1 {
return toReturn
}
for _, em := range emojis {
parts := strings.Split(em, ":")
toReturn = append(toReturn, &Emoji{
ID: parts[2][:len(parts[2])-1],
Name: parts[1],
Animated: strings.HasPrefix(em, "<a:"),
})
}
return toReturn
}
// MessageFlags is the flags of "message" (see MessageFlags* consts)
@ -131,11 +195,24 @@ type MessageFlags int
// Valid MessageFlags values
const (
MessageFlagsCrossPosted MessageFlags = 1 << iota
MessageFlagsIsCrossPosted
MessageFlagsSupressEmbeds
MessageFlagsSourceMessageDeleted
MessageFlagsUrgent
// MessageFlagsCrossPosted This message has been published to subscribed channels (via Channel Following).
MessageFlagsCrossPosted MessageFlags = 1 << 0
// MessageFlagsIsCrossPosted this message originated from a message in another channel (via Channel Following).
MessageFlagsIsCrossPosted MessageFlags = 1 << 1
// MessageFlagsSupressEmbeds do not include any embeds when serializing this message.
MessageFlagsSupressEmbeds MessageFlags = 1 << 2
// MessageFlagsSourceMessageDeleted the source message for this crosspost has been deleted (via Channel Following).
MessageFlagsSourceMessageDeleted MessageFlags = 1 << 3
// MessageFlagsUrgent this message came from the urgent message system.
MessageFlagsUrgent MessageFlags = 1 << 4
// MessageFlagsHasThread this message has an associated thread, with the same id as the message.
MessageFlagsHasThread MessageFlags = 1 << 5
// MessageFlagsEphemeral this message is only visible to the user who invoked the Interaction.
MessageFlagsEphemeral MessageFlags = 1 << 6
// MessageFlagsLoading this message is an Interaction Response and the bot is "thinking".
MessageFlagsLoading MessageFlags = 1 << 7
// MessageFlagsFailedToMentionSomeRolesInThread this message failed to mention some roles and add their members to the thread.
MessageFlagsFailedToMentionSomeRolesInThread MessageFlags = 1 << 8
)
// File stores info about files you e.g. send in messages.
@ -148,25 +225,33 @@ type File struct {
// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
Content string `json:"content,omitempty"`
Embed *MessageEmbed `json:"embed,omitempty"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
TTS bool `json:"tts"`
Components []MessageComponent `json:"components"`
Files []*File `json:"-"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Reference *MessageReference `json:"message_reference,omitempty"`
// TODO: Remove this when compatibility is not required.
File *File `json:"-"`
// TODO: Remove this when compatibility is not required.
Embed *MessageEmbed `json:"-"`
}
// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
// is also where you should get the instance from.
type MessageEdit struct {
Content *string `json:"content,omitempty"`
Embed *MessageEmbed `json:"embed,omitempty"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
ID string
Channel string
// TODO: Remove this when compatibility is not required.
Embed *MessageEmbed `json:"-"`
}
// NewMessageEdit returns a MessageEdit struct, initialized
@ -188,7 +273,14 @@ func (m *MessageEdit) SetContent(str string) *MessageEdit {
// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
m.Embed = embed
m.Embeds = []*MessageEmbed{embed}
return m
}
// SetEmbeds is a convenience function for setting the embeds,
// so you can chain commands.
func (m *MessageEdit) SetEmbeds(embeds []*MessageEmbed) *MessageEdit {
m.Embeds = embeds
return m
}
@ -230,13 +322,15 @@ type MessageAllowedMentions struct {
// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
ID string `json:"id"`
URL string `json:"url"`
ProxyURL string `json:"proxy_url"`
Filename string `json:"filename"`
Width int `json:"width"`
Height int `json:"height"`
Size int `json:"size"`
ID string `json:"id"`
URL string `json:"url"`
ProxyURL string `json:"proxy_url"`
Filename string `json:"filename"`
ContentType string `json:"content_type"`
Width int `json:"width"`
Height int `json:"height"`
Size int `json:"size"`
Ephemeral bool `json:"ephemeral"`
}
// MessageEmbedFooter is a part of a MessageEmbed struct.
@ -339,23 +433,10 @@ type MessageActivityType int
// Constants for the different types of Message Activity
const (
MessageActivityTypeJoin MessageActivityType = iota + 1
MessageActivityTypeSpectate
MessageActivityTypeListen
MessageActivityTypeJoinRequest
)
// MessageFlag describes an extra feature of the message
type MessageFlag int
// Constants for the different bit offsets of Message Flags
const (
// This message has been published to subscribed channels (via Channel Following)
MessageFlagCrossposted MessageFlag = 1 << iota
// This message originated from a message in another channel (via Channel Following)
MessageFlagIsCrosspost
// Do not include any embeds when serializing this message
MessageFlagSuppressEmbeds
MessageActivityTypeJoin MessageActivityType = 1
MessageActivityTypeSpectate MessageActivityType = 2
MessageActivityTypeListen MessageActivityType = 3
MessageActivityTypeJoinRequest MessageActivityType = 5
)
// MessageApplication is sent with Rich Presence-related chat embeds
@ -447,3 +528,14 @@ func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, e
})
return
}
// MessageInteraction contains information about the application command interaction which generated the message.
type MessageInteraction struct {
ID string `json:"id"`
Type InteractionType `json:"type"`
Name string `json:"name"`
User *User `json:"user"`
// Member is only present when the interaction is from a guild.
Member *Member `json:"member"`
}

@ -18,8 +18,8 @@ type MembershipState int
// Constants for the different stages of the MembershipState
const (
MembershipStateInvited MembershipState = iota + 1
MembershipStateAccepted
MembershipStateInvited MembershipState = 1
MembershipStateAccepted MembershipState = 2
)
// A TeamMember struct stores values for a single Team Member, extending the normal User data - note that the user field is partial
@ -40,28 +40,11 @@ type Team struct {
Members []*TeamMember `json:"members"`
}
// An Application struct stores values for a Discord OAuth2 Application
type Application struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
Secret string `json:"secret,omitempty"`
RedirectURIs *[]string `json:"redirect_uris,omitempty"`
BotRequireCodeGrant bool `json:"bot_require_code_grant,omitempty"`
BotPublic bool `json:"bot_public,omitempty"`
RPCApplicationState int `json:"rpc_application_state,omitempty"`
Flags int `json:"flags,omitempty"`
Owner *User `json:"owner"`
Bot *User `json:"bot"`
Team *Team `json:"team"`
}
// Application returns an Application structure of a specific Application
// appID : The ID of an Application
func (s *Session) Application(appID string) (st *Application, err error) {
body, err := s.RequestWithBucketID("GET", EndpointApplication(appID), nil, EndpointApplication(""))
body, err := s.RequestWithBucketID("GET", EndpointOAuth2Application(appID), nil, EndpointOAuth2Application(""))
if err != nil {
return
}
@ -73,7 +56,7 @@ func (s *Session) Application(appID string) (st *Application, err error) {
// Applications returns all applications for the authenticated user
func (s *Session) Applications() (st []*Application, err error) {
body, err := s.RequestWithBucketID("GET", EndpointApplications, nil, EndpointApplications)
body, err := s.RequestWithBucketID("GET", EndpointOAuth2Applications, nil, EndpointOAuth2Applications)
if err != nil {
return
}
@ -88,12 +71,11 @@ func (s *Session) Applications() (st []*Application, err error) {
func (s *Session) ApplicationCreate(ap *Application) (st *Application, err error) {
data := struct {
Name string `json:"name"`
Description string `json:"description"`
RedirectURIs *[]string `json:"redirect_uris,omitempty"`
}{ap.Name, ap.Description, ap.RedirectURIs}
Name string `json:"name"`
Description string `json:"description"`
}{ap.Name, ap.Description}
body, err := s.RequestWithBucketID("POST", EndpointApplications, data, EndpointApplications)
body, err := s.RequestWithBucketID("POST", EndpointOAuth2Applications, data, EndpointOAuth2Applications)
if err != nil {
return
}
@ -107,12 +89,11 @@ func (s *Session) ApplicationCreate(ap *Application) (st *Application, err error
func (s *Session) ApplicationUpdate(appID string, ap *Application) (st *Application, err error) {
data := struct {
Name string `json:"name"`
Description string `json:"description"`
RedirectURIs *[]string `json:"redirect_uris,omitempty"`
}{ap.Name, ap.Description, ap.RedirectURIs}
Name string `json:"name"`
Description string `json:"description"`
}{ap.Name, ap.Description}
body, err := s.RequestWithBucketID("PUT", EndpointApplication(appID), data, EndpointApplication(""))
body, err := s.RequestWithBucketID("PUT", EndpointOAuth2Application(appID), data, EndpointOAuth2Application(""))
if err != nil {
return
}
@ -125,7 +106,7 @@ func (s *Session) ApplicationUpdate(appID string, ap *Application) (st *Applicat
// appID : The ID of an Application
func (s *Session) ApplicationDelete(appID string) (err error) {
_, err = s.RequestWithBucketID("DELETE", EndpointApplication(appID), nil, EndpointApplication(""))
_, err = s.RequestWithBucketID("DELETE", EndpointOAuth2Application(appID), nil, EndpointOAuth2Application(""))
if err != nil {
return
}
@ -143,7 +124,7 @@ type Asset struct {
// ApplicationAssets returns an application's assets
func (s *Session) ApplicationAssets(appID string) (ass []*Asset, err error) {
body, err := s.RequestWithBucketID("GET", EndpointApplicationAssets(appID), nil, EndpointApplicationAssets(""))
body, err := s.RequestWithBucketID("GET", EndpointOAuth2ApplicationAssets(appID), nil, EndpointOAuth2ApplicationAssets(""))
if err != nil {
return
}
@ -163,7 +144,7 @@ func (s *Session) ApplicationAssets(appID string) (ass []*Asset, err error) {
// NOTE: func name may change, if I can think up something better.
func (s *Session) ApplicationBotCreate(appID string) (st *User, err error) {
body, err := s.RequestWithBucketID("POST", EndpointApplicationsBot(appID), nil, EndpointApplicationsBot(""))
body, err := s.RequestWithBucketID("POST", EndpointOAuth2ApplicationsBot(appID), nil, EndpointOAuth2ApplicationsBot(""))
if err != nil {
return
}

@ -33,7 +33,7 @@ func NewRatelimiter() *RateLimiter {
buckets: make(map[string]*Bucket),
global: new(int64),
customRateLimits: []*customRateLimit{
&customRateLimit{
{
suffix: "//reactions//",
requests: 1,
reset: 200 * time.Millisecond,

@ -38,13 +38,15 @@ type State struct {
Ready
// MaxMessageCount represents how many messages per channel the state will store.
MaxMessageCount int
TrackChannels bool
TrackEmojis bool
TrackMembers bool
TrackRoles bool
TrackVoice bool
TrackPresences bool
MaxMessageCount int
TrackChannels bool
TrackThreads bool
TrackEmojis bool
TrackMembers bool
TrackThreadMembers bool
TrackRoles bool
TrackVoice bool
TrackPresences bool
guildMap map[string]*Guild
channelMap map[string]*Channel
@ -58,15 +60,17 @@ func NewState() *State {
PrivateChannels: []*Channel{},
Guilds: []*Guild{},
},
TrackChannels: true,
TrackEmojis: true,
TrackMembers: true,
TrackRoles: true,
TrackVoice: true,
TrackPresences: true,
guildMap: make(map[string]*Guild),
channelMap: make(map[string]*Channel),
memberMap: make(map[string]map[string]*Member),
TrackChannels: true,
TrackThreads: true,
TrackEmojis: true,
TrackMembers: true,
TrackThreadMembers: true,
TrackRoles: true,
TrackVoice: true,
TrackPresences: true,
guildMap: make(map[string]*Guild),
channelMap: make(map[string]*Channel),
memberMap: make(map[string]map[string]*Member),
}
}
@ -93,6 +97,11 @@ func (s *State) GuildAdd(guild *Guild) error {
s.channelMap[c.ID] = c
}
// Add all the threads to the state in case of thread sync list.
for _, t := range guild.Threads {
s.channelMap[t.ID] = t
}
// If this guild contains a new member slice, we must regenerate the member map so the pointers stay valid
if guild.Members != nil {
s.createMemberMap(guild)
@ -122,6 +131,9 @@ func (s *State) GuildAdd(guild *Guild) error {
if guild.Channels == nil {
guild.Channels = g.Channels
}
if guild.Threads == nil {
guild.Threads = g.Threads
}
if guild.VoiceStates == nil {
guild.VoiceStates = g.VoiceStates
}
@ -180,21 +192,12 @@ func (s *State) Guild(guildID string) (*Guild, error) {
return nil, ErrStateNotFound
}
// PresenceAdd adds a presence to the current world state, or
// updates it if it already exists.
func (s *State) PresenceAdd(guildID string, presence *Presence) error {
if s == nil {
return ErrNilState
}
guild, err := s.Guild(guildID)
if err != nil {
return err
func (s *State) presenceAdd(guildID string, presence *Presence) error {
guild, ok := s.guildMap[guildID]
if !ok {
return ErrStateNotFound
}
s.Lock()
defer s.Unlock()
for i, p := range guild.Presences {
if p.User.ID == presence.User.ID {
//guild.Presences[i] = presence
@ -233,6 +236,19 @@ func (s *State) PresenceAdd(guildID string, presence *Presence) error {
return nil
}
// PresenceAdd adds a presence to the current world state, or
// updates it if it already exists.
func (s *State) PresenceAdd(guildID string, presence *Presence) error {
if s == nil {
return ErrNilState
}
s.Lock()
defer s.Unlock()
return s.presenceAdd(guildID, presence)
}
// PresenceRemove removes a presence from the current world state.
func (s *State) PresenceRemove(guildID string, presence *Presence) error {
if s == nil {
@ -279,21 +295,12 @@ func (s *State) Presence(guildID, userID string) (*Presence, error) {
// TODO: Consider moving Guild state update methods onto *Guild.
// MemberAdd adds a member to the current world state, or
// updates it if it already exists.
func (s *State) MemberAdd(member *Member) error {
if s == nil {
return ErrNilState
}
guild, err := s.Guild(member.GuildID)
if err != nil {
return err
func (s *State) memberAdd(member *Member) error {
guild, ok := s.guildMap[member.GuildID]
if !ok {
return ErrStateNotFound
}
s.Lock()
defer s.Unlock()
members, ok := s.memberMap[member.GuildID]
if !ok {
return ErrStateNotFound
@ -306,15 +313,27 @@ func (s *State) MemberAdd(member *Member) error {
} else {
// We are about to replace `m` in the state with `member`, but first we need to
// make sure we preserve any fields that the `member` doesn't contain from `m`.
if member.JoinedAt == "" {
if member.JoinedAt.IsZero() {
member.JoinedAt = m.JoinedAt
}
*m = *member
}
return nil
}
// MemberAdd adds a member to the current world state, or
// updates it if it already exists.
func (s *State) MemberAdd(member *Member) error {
if s == nil {
return ErrNilState
}
s.Lock()
defer s.Unlock()
return s.memberAdd(member)
}
// MemberRemove removes a member from current world state.
func (s *State) MemberRemove(member *Member) error {
if s == nil {
@ -465,6 +484,9 @@ func (s *State) ChannelAdd(channel *Channel) error {
if channel.PermissionOverwrites == nil {
channel.PermissionOverwrites = c.PermissionOverwrites
}
if channel.ThreadMetadata == nil {
channel.ThreadMetadata = c.ThreadMetadata
}
*c = *channel
return nil
@ -472,12 +494,18 @@ func (s *State) ChannelAdd(channel *Channel) error {
if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM {
s.PrivateChannels = append(s.PrivateChannels, channel)
} else {
guild, ok := s.guildMap[channel.GuildID]
if !ok {
return ErrStateNotFound
}
s.channelMap[channel.ID] = channel
return nil
}
guild, ok := s.guildMap[channel.GuildID]
if !ok {
return ErrStateNotFound
}
if channel.IsThread() {
guild.Threads = append(guild.Threads, channel)
} else {
guild.Channels = append(guild.Channels, channel)
}
@ -507,15 +535,26 @@ func (s *State) ChannelRemove(channel *Channel) error {
break
}
}
} else {
guild, err := s.Guild(channel.GuildID)
if err != nil {
return err
}
delete(s.channelMap, channel.ID)
return nil
}
s.Lock()
defer s.Unlock()
guild, err := s.Guild(channel.GuildID)
if err != nil {
return err
}
s.Lock()
defer s.Unlock()
if channel.IsThread() {
for i, t := range guild.Threads {
if t.ID == channel.ID {
guild.Threads = append(guild.Threads[:i], guild.Threads[i+1:]...)
break
}
}
} else {
for i, c := range guild.Channels {
if c.ID == channel.ID {
guild.Channels = append(guild.Channels[:i], guild.Channels[i+1:]...)
@ -529,6 +568,99 @@ func (s *State) ChannelRemove(channel *Channel) error {
return nil
}
// ThreadListSync syncs guild threads with provided ones.
func (s *State) ThreadListSync(tls *ThreadListSync) error {
guild, err := s.Guild(tls.GuildID)
if err != nil {
return err
}
s.Lock()
defer s.Unlock()
// This algorithm filters out archived or
// threads which are children of channels in channelIDs
// and then it adds all synced threads to guild threads and cache
index := 0
outer:
for _, t := range guild.Threads {
if !t.ThreadMetadata.Archived && tls.ChannelIDs != nil {
for _, v := range tls.ChannelIDs {
if t.ParentID == v {
delete(s.channelMap, t.ID)
continue outer
}
}
guild.Threads[index] = t
index++
} else {
delete(s.channelMap, t.ID)
}
}
guild.Threads = guild.Threads[:index]
for _, t := range tls.Threads {
s.channelMap[t.ID] = t
guild.Threads = append(guild.Threads, t)
}
for _, m := range tls.Members {
if c, ok := s.channelMap[m.ID]; ok {
c.Member = m
}
}
return nil
}
// ThreadMembersUpdate updates thread members list
func (s *State) ThreadMembersUpdate(tmu *ThreadMembersUpdate) error {
thread, err := s.Channel(tmu.ID)
if err != nil {
return err
}
s.Lock()
defer s.Unlock()
for idx, member := range thread.Members {
for _, removedMember := range tmu.RemovedMembers {
if member.ID == removedMember {
thread.Members = append(thread.Members[:idx], thread.Members[idx+1:]...)
break
}
}
}
for _, addedMember := range tmu.AddedMembers {
thread.Members = append(thread.Members, addedMember.ThreadMember)
if addedMember.Member != nil {
err = s.memberAdd(addedMember.Member)
if err != nil {
return err
}
}
if addedMember.Presence != nil {
err = s.presenceAdd(tmu.GuildID, addedMember.Presence)
if err != nil {
return err
}
}
}
thread.MemberCount = tmu.MemberCount
return nil
}
// ThreadMemberUpdate sets or updates member data for the current user.
func (s *State) ThreadMemberUpdate(mu *ThreadMemberUpdate) error {
thread, err := s.Channel(mu.ID)
if err != nil {
return err
}
thread.Member = mu.ThreadMember
return nil
}
// GuildChannel gets a channel by ID from a guild.
// This method is Deprecated, use Channel(channelID)
func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) {
@ -637,7 +769,7 @@ func (s *State) MessageAdd(message *Message) error {
if message.Content != "" {
m.Content = message.Content
}
if message.EditedTimestamp != "" {
if message.EditedTimestamp != nil {
m.EditedTimestamp = message.EditedTimestamp
}
if message.Mentions != nil {
@ -649,12 +781,15 @@ func (s *State) MessageAdd(message *Message) error {
if message.Attachments != nil {
m.Attachments = message.Attachments
}
if message.Timestamp != "" {
if !message.Timestamp.IsZero() {
m.Timestamp = message.Timestamp
}
if message.Author != nil {
m.Author = message.Author
}
if message.Components != nil {
m.Components = message.Components
}
return nil
}
@ -665,6 +800,7 @@ func (s *State) MessageAdd(message *Message) error {
if len(c.Messages) > s.MaxMessageCount {
c.Messages = c.Messages[len(c.Messages)-s.MaxMessageCount:]
}
return nil
}
@ -690,6 +826,7 @@ func (s *State) messageRemoveByID(channelID, messageID string) error {
for i, m := range c.Messages {
if m.ID == messageID {
c.Messages = append(c.Messages[:i], c.Messages[i+1:]...)
return nil
}
}
@ -833,6 +970,13 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
case *GuildUpdate:
err = s.GuildAdd(t.Guild)
case *GuildDelete:
var old *Guild
old, err = s.Guild(t.ID)
if err == nil {
oldCopy := *old
t.BeforeDelete = &oldCopy
}
err = s.GuildRemove(t.Guild)
case *GuildMemberAdd:
// Updates the MemberCount of the guild.
@ -903,6 +1047,35 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
if s.TrackChannels {
err = s.ChannelRemove(t.Channel)
}
case *ThreadCreate:
if s.TrackThreads {
err = s.ChannelAdd(t.Channel)
}
case *ThreadUpdate:
if s.TrackThreads {
old, err := s.Channel(t.ID)
if err == nil {
oldCopy := *old
t.BeforeUpdate = &oldCopy
}
err = s.ChannelAdd(t.Channel)
}
case *ThreadDelete:
if s.TrackThreads {
err = s.ChannelRemove(t.Channel)
}
case *ThreadMemberUpdate:
if s.TrackThreads {
err = s.ThreadMemberUpdate(t)
}
case *ThreadMembersUpdate:
if s.TrackThreadMembers {
err = s.ThreadMembersUpdate(t)
}
case *ThreadListSync:
if s.TrackThreads {
err = s.ThreadListSync(t)
}
case *MessageCreate:
if s.MaxMessageCount != 0 {
err = s.MessageAdd(t.Message)

File diff suppressed because it is too large Load Diff

@ -12,18 +12,8 @@ package discordgo
import (
"encoding/json"
"net/http"
"time"
)
// Timestamp stores a timestamp, as sent by the Discord API.
type Timestamp string
// Parse parses a timestamp string into a time.Time object.
// The only time this can fail is if Discord changes their timestamp format.
func (t Timestamp) Parse() (time.Time, error) {
return time.Parse(time.RFC3339, string(t))
}
// RESTError stores error information about a request with a bad response code.
// Message is not always present, there are cases where api calls can fail
// without returning a json message.

@ -1,26 +1,25 @@
package discordgo
import "strings"
// UserFlags is the flags of "user" (see UserFlags* consts)
// https://discord.com/developers/docs/resources/user#user-object-user-flags
type UserFlags int
// Valid UserFlags values
const (
UserFlagDiscordEmployee UserFlags = 1 << 0
UserFlagDiscordPartner = 1 << 1
UserFlagHypeSquadEvents = 1 << 2
UserFlagBugHunterLevel1 = 1 << 3
UserFlagHouseBravery = 1 << 6
UserFlagHouseBrilliance = 1 << 7
UserFlagHouseBalance = 1 << 8
UserFlagEarlySupporter = 1 << 9
UserFlagTeamUser = 1 << 10
UserFlagSystem = 1 << 12
UserFlagBugHunterLevel2 = 1 << 14
UserFlagVerifiedBot = 1 << 16
UserFlagVerifiedBotDeveloper = 1 << 17
UserFlagDiscordEmployee UserFlags = 1 << 0
UserFlagDiscordPartner UserFlags = 1 << 1
UserFlagHypeSquadEvents UserFlags = 1 << 2
UserFlagBugHunterLevel1 UserFlags = 1 << 3
UserFlagHouseBravery UserFlags = 1 << 6
UserFlagHouseBrilliance UserFlags = 1 << 7
UserFlagHouseBalance UserFlags = 1 << 8
UserFlagEarlySupporter UserFlags = 1 << 9
UserFlagTeamUser UserFlags = 1 << 10
UserFlagSystem UserFlags = 1 << 12
UserFlagBugHunterLevel2 UserFlags = 1 << 14
UserFlagVerifiedBot UserFlags = 1 << 16
UserFlagVerifiedBotDeveloper UserFlags = 1 << 17
UserFlagDiscordCertifiedModerator UserFlags = 1 << 18
)
// A User stores all data for an individual Discord user.
@ -55,6 +54,12 @@ type User struct {
// Whether the user has multi-factor authentication enabled.
MFAEnabled bool `json:"mfa_enabled"`
// The hash of the user's banner image.
Banner string `json:"banner"`
// User's banner color, encoded as an integer representation of hexadecimal color code
AccentColor int `json:"accent_color"`
// Whether the user is a bot.
Bot bool `json:"bot"`
@ -90,17 +95,13 @@ func (u *User) Mention() string {
// if size is an empty string, no size parameter will
// be added to the URL.
func (u *User) AvatarURL(size string) string {
var URL string
if u.Avatar == "" {
URL = EndpointDefaultUserAvatar(u.Discriminator)
} else if strings.HasPrefix(u.Avatar, "a_") {
URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
} else {
URL = EndpointUserAvatar(u.ID, u.Avatar)
}
if size != "" {
return URL + "?size=" + size
}
return URL
return avatarURL(u.Avatar, EndpointDefaultUserAvatar(u.Discriminator),
EndpointUserAvatar(u.ID, u.Avatar), EndpointUserAvatarAnimated(u.ID, u.Avatar), size)
}
// BannerURL returns the URL of the users's banner image.
// size: The size of the desired banner image as a power of two
// Image size can be any power of two between 16 and 4096.
func (u *User) BannerURL(size string) string {
return bannerURL(u.Banner, EndpointUserBanner(u.ID, u.Banner), EndpointUserBannerAnimated(u.ID, u.Banner), size)
}

@ -0,0 +1,110 @@
package discordgo
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/textproto"
"strconv"
"strings"
"time"
)
// SnowflakeTimestamp returns the creation time of a Snowflake ID relative to the creation of Discord.
func SnowflakeTimestamp(ID string) (t time.Time, err error) {
i, err := strconv.ParseInt(ID, 10, 64)
if err != nil {
return
}
timestamp := (i >> 22) + 1420070400000
t = time.Unix(0, timestamp*1000000)
return
}
// MultipartBodyWithJSON returns the contentType and body for a discord request
// data : The object to encode for payload_json in the multipart request
// files : Files to include in the request
func MultipartBodyWithJSON(data interface{}, files []*File) (requestContentType string, requestBody []byte, err error) {
body := &bytes.Buffer{}
bodywriter := multipart.NewWriter(body)
payload, err := json.Marshal(data)
if err != nil {
return
}
var p io.Writer
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", `form-data; name="payload_json"`)
h.Set("Content-Type", "application/json")
p, err = bodywriter.CreatePart(h)
if err != nil {
return
}
if _, err = p.Write(payload); err != nil {
return
}
for i, file := range files {
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file%d"; filename="%s"`, i, quoteEscaper.Replace(file.Name)))
contentType := file.ContentType
if contentType == "" {
contentType = "application/octet-stream"
}
h.Set("Content-Type", contentType)
p, err = bodywriter.CreatePart(h)
if err != nil {
return
}
if _, err = io.Copy(p, file.Reader); err != nil {
return
}
}
err = bodywriter.Close()
if err != nil {
return
}
return bodywriter.FormDataContentType(), body.Bytes(), nil
}
func avatarURL(avatarHash, defaultAvatarURL, staticAvatarURL, animatedAvatarURL, size string) string {
var URL string
if avatarHash == "" {
URL = defaultAvatarURL
} else if strings.HasPrefix(avatarHash, "a_") {
URL = animatedAvatarURL
} else {
URL = staticAvatarURL
}
if size != "" {
return URL + "?size=" + size
}
return URL
}
func bannerURL(bannerHash, staticBannerURL, animatedBannerURL, size string) string {
var URL string
if bannerHash == "" {
return ""
} else if strings.HasPrefix(bannerHash, "a_") {
URL = animatedBannerURL
} else {
URL = staticBannerURL
}
if size != "" {
return URL + "?size=" + size
}
return URL
}

@ -831,9 +831,15 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct
copy(nonce[:], recvbuf[0:12])
p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey)
if len(p.Opus) > 8 && recvbuf[0] == 0x90 {
// Extension bit is set, first 8 bytes is the extended header
p.Opus = p.Opus[8:]
// extension bit set, and not a RTCP packet
if ((recvbuf[0] & 0x10) == 0x10) && ((recvbuf[1] & 0x80) == 0) {
// get extended header length
extlen := binary.BigEndian.Uint16(p.Opus[2:4])
// 4 bytes (ext header header) + 4*extlen (ext header data)
shift := int(4 + 4*extlen)
if len(p.Opus) > shift {
p.Opus = p.Opus[shift:]
}
}
if c != nil {

@ -0,0 +1,49 @@
package discordgo
// Webhook stores the data for a webhook.
type Webhook struct {
ID string `json:"id"`
Type WebhookType `json:"type"`
GuildID string `json:"guild_id"`
ChannelID string `json:"channel_id"`
User *User `json:"user"`
Name string `json:"name"`
Avatar string `json:"avatar"`
Token string `json:"token"`
// ApplicationID is the bot/OAuth2 application that created this webhook
ApplicationID string `json:"application_id,omitempty"`
}
// WebhookType is the type of Webhook (see WebhookType* consts) in the Webhook struct
// https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-types
type WebhookType int
// Valid WebhookType values
const (
WebhookTypeIncoming WebhookType = 1
WebhookTypeChannelFollower WebhookType = 2
)
// WebhookParams is a struct for webhook params, used in the WebhookExecute command.
type WebhookParams struct {
Content string `json:"content,omitempty"`
Username string `json:"username,omitempty"`
AvatarURL string `json:"avatar_url,omitempty"`
TTS bool `json:"tts,omitempty"`
Files []*File `json:"-"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
// NOTE: Works only for followup messages.
Flags uint64 `json:"flags,omitempty"`
}
// WebhookEdit stores data for editing of a webhook message.
type WebhookEdit struct {
Content string `json:"content,omitempty"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
Files []*File `json:"-"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
}

@ -33,7 +33,7 @@ var ErrWSAlreadyOpen = errors.New("web socket already opened")
var ErrWSNotFound = errors.New("no websocket connection exists")
// ErrWSShardBounds is thrown when you try to use a shard ID that is
// less than the total shard count
// more than the total shard count
var ErrWSShardBounds = errors.New("ShardID must be less than ShardCount")
type resumePacket struct {
@ -383,6 +383,17 @@ func (s *Session) UpdateListeningStatus(name string) (err error) {
// UpdateStatusComplex allows for sending the raw status update data untouched by discordgo.
func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
// The comment does say "untouched by discordgo", but we might need to lie a bit here.
// The Discord documentation lists `activities` as being nullable, but in practice this
// doesn't seem to be the case. I had filed an issue about this at
// https://github.com/discord/discord-api-docs/issues/2559, but as of writing this
// haven't had any movement on it, so at this point I'm assuming this is an error,
// and am fixing this bug accordingly. Because sending `null` for `activities` instantly
// disconnects us, I think that disallowing it from being sent in `UpdateStatusComplex`
// isn't that big of an issue.
if usd.Activities == nil {
usd.Activities = make([]*Activity, 0)
}
s.RLock()
defer s.RUnlock()
@ -755,13 +766,13 @@ func (s *Session) identify() error {
s.log(LogDebug, "called")
// TODO: This is a temporary block of code to help
// maintain backwards compatability
// maintain backwards compatibility
if s.Compress == false {
s.Identify.Compress = false
}
// TODO: This is a temporary block of code to help
// maintain backwards compatability
// maintain backwards compatibility
if s.Token != "" && s.Identify.Token == "" {
s.Identify.Token = s.Token
}

@ -1,2 +0,0 @@
# IDE-specific metadata
.idea/

@ -1,161 +0,0 @@
// Discordgo - Discord bindings for Go
// Available at https://github.com/matterbridge/discordgo
// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains high level helper functions and easy entry points for the
// entire discordgo package. These functions are being developed and are very
// experimental at this point. They will most likely change so please use the
// low level functions if that's a problem.
// Package discordgo provides Discord binding for Go
package discordgo
import (
"errors"
"fmt"
"net/http"
"runtime"
"time"
)
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
const VERSION = "0.23.0"
// ErrMFA will be risen by New when the user has 2FA.
var ErrMFA = errors.New("account has 2FA enabled")
// New creates a new Discord session and will automate some startup
// tasks if given enough information to do so. Currently you can pass zero
// arguments and it will return an empty Discord session.
// There are 3 ways to call New:
// With a single auth token - All requests will use the token blindly
// (just tossing it into the HTTP Authorization header);
// no verification of the token will be done and requests may fail.
// IF THE TOKEN IS FOR A BOT, IT MUST BE PREFIXED WITH `BOT `
// eg: `"Bot <token>"`
// IF IT IS AN OAUTH2 ACCESS TOKEN, IT MUST BE PREFIXED WITH `Bearer `
// eg: `"Bearer <token>"`
// With an email and password - Discord will sign in with the provided
// credentials.
// With an email, password and auth token - Discord will verify the auth
// token, if it is invalid it will sign in with the provided
// credentials. This is the Discord recommended way to sign in.
//
// NOTE: While email/pass authentication is supported by DiscordGo it is
// HIGHLY DISCOURAGED by Discord. Please only use email/pass to obtain a token
// and then use that authentication token for all future connections.
// Also, doing any form of automation with a user (non Bot) account may result
// in that account being permanently banned from Discord.
func New(args ...interface{}) (s *Session, err error) {
// Create an empty Session interface.
s = &Session{
State: NewState(),
Ratelimiter: NewRatelimiter(),
StateEnabled: true,
Compress: true,
ShouldReconnectOnError: true,
ShardID: 0,
ShardCount: 1,
MaxRestRetries: 3,
Client: &http.Client{Timeout: (20 * time.Second)},
UserAgent: "DiscordBot (https://github.com/matterbridge/discordgo, v" + VERSION + ")",
sequence: new(int64),
LastHeartbeatAck: time.Now().UTC(),
}
// Initilize the Identify Package with defaults
// These can be modified prior to calling Open()
s.Identify.Compress = true
s.Identify.LargeThreshold = 250
s.Identify.GuildSubscriptions = true
s.Identify.Properties.OS = runtime.GOOS
s.Identify.Properties.Browser = "DiscordGo v" + VERSION
s.Identify.Intents = MakeIntent(IntentsAllWithoutPrivileged)
// If no arguments are passed return the empty Session interface.
if args == nil {
return
}
// Variables used below when parsing func arguments
var auth, pass string
// Parse passed arguments
for _, arg := range args {
switch v := arg.(type) {
case []string:
if len(v) > 3 {
err = fmt.Errorf("too many string parameters provided")
return
}
// First string is either token or username
if len(v) > 0 {
auth = v[0]
}
// If second string exists, it must be a password.
if len(v) > 1 {
pass = v[1]
}
// If third string exists, it must be an auth token.
if len(v) > 2 {
s.Identify.Token = v[2]
s.Token = v[2] // TODO: Remove, Deprecated - Kept for backwards compatibility.
}
case string:
// First string must be either auth token or username.
// Second string must be a password.
// Only 2 input strings are supported.
if auth == "" {
auth = v
} else if pass == "" {
pass = v
} else if s.Token == "" {
s.Identify.Token = v
s.Token = v // TODO: Remove, Deprecated - Kept for backwards compatibility.
} else {
err = fmt.Errorf("too many string parameters provided")
return
}
// case Config:
// TODO: Parse configuration struct
default:
err = fmt.Errorf("unsupported parameter type provided")
return
}
}
// If only one string was provided, assume it is an auth token.
// Otherwise get auth token from Discord, if a token was specified
// Discord will verify it for free, or log the user in if it is
// invalid.
if pass == "" {
s.Identify.Token = auth
s.Token = auth // TODO: Remove, Deprecated - Kept for backwards compatibility.
} else {
err = s.Login(auth, pass)
// TODO: Remove last s.Token part, Deprecated - Kept for backwards compatibility.
if err != nil || s.Identify.Token == "" || s.Token == "" {
if s.MFA {
err = ErrMFA
} else {
err = fmt.Errorf("Unable to fetch discord authentication token. %v", err)
}
return
}
}
return
}

@ -1,153 +0,0 @@
// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo
// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains variables for all known Discord end points. All functions
// throughout the Discordgo package use these variables for all connections
// to Discord. These are all exported and you may modify them if needed.
package discordgo
import "strconv"
// APIVersion is the Discord API version used for the REST and Websocket API.
var APIVersion = "8"
// Known Discord API Endpoints.
var (
EndpointStatus = "https://status.discord.com/api/v2/"
EndpointSm = EndpointStatus + "scheduled-maintenances/"
EndpointSmActive = EndpointSm + "active.json"
EndpointSmUpcoming = EndpointSm + "upcoming.json"
EndpointDiscord = "https://discord.com/"
EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/"
EndpointGuilds = EndpointAPI + "guilds/"
EndpointChannels = EndpointAPI + "channels/"
EndpointUsers = EndpointAPI + "users/"
EndpointGateway = EndpointAPI + "gateway"
EndpointGatewayBot = EndpointGateway + "/bot"
EndpointWebhooks = EndpointAPI + "webhooks/"
EndpointCDN = "https://cdn.discordapp.com/"
EndpointCDNAttachments = EndpointCDN + "attachments/"
EndpointCDNAvatars = EndpointCDN + "avatars/"
EndpointCDNIcons = EndpointCDN + "icons/"
EndpointCDNSplashes = EndpointCDN + "splashes/"
EndpointCDNChannelIcons = EndpointCDN + "channel-icons/"
EndpointCDNBanners = EndpointCDN + "banners/"
EndpointAuth = EndpointAPI + "auth/"
EndpointLogin = EndpointAuth + "login"
EndpointLogout = EndpointAuth + "logout"
EndpointVerify = EndpointAuth + "verify"
EndpointVerifyResend = EndpointAuth + "verify/resend"
EndpointForgotPassword = EndpointAuth + "forgot"
EndpointResetPassword = EndpointAuth + "reset"
EndpointRegister = EndpointAuth + "register"
EndpointVoice = EndpointAPI + "/voice/"
EndpointVoiceRegions = EndpointVoice + "regions"
EndpointVoiceIce = EndpointVoice + "ice"
EndpointTutorial = EndpointAPI + "tutorial/"
EndpointTutorialIndicators = EndpointTutorial + "indicators"
EndpointTrack = EndpointAPI + "track"
EndpointSso = EndpointAPI + "sso"
EndpointReport = EndpointAPI + "report"
EndpointIntegrations = EndpointAPI + "integrations"
EndpointUser = func(uID string) string { return EndpointUsers + uID }
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
EndpointDefaultUserAvatar = func(uDiscriminator string) string {
uDiscriminatorInt, _ := strconv.Atoi(uDiscriminator)
return EndpointCDN + "embed/avatars/" + strconv.Itoa(uDiscriminatorInt%5) + ".png"
}
EndpointUserSettings = func(uID string) string { return EndpointUsers + uID + "/settings" }
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" }
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
EndpointUserDevices = func(uID string) string { return EndpointUsers + uID + "/devices" }
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
EndpointUserNotes = func(uID string) string { return EndpointUsers + "@me/notes/" + uID }
EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
EndpointGuildChannels = func(gID string) string { return EndpointGuilds + gID + "/channels" }
EndpointGuildMembers = func(gID string) string { return EndpointGuilds + gID + "/members" }
EndpointGuildMember = func(gID, uID string) string { return EndpointGuilds + gID + "/members/" + uID }
EndpointGuildMemberRole = func(gID, uID, rID string) string { return EndpointGuilds + gID + "/members/" + uID + "/roles/" + rID }
EndpointGuildBans = func(gID string) string { return EndpointGuilds + gID + "/bans" }
EndpointGuildBan = func(gID, uID string) string { return EndpointGuilds + gID + "/bans/" + uID }
EndpointGuildIntegrations = func(gID string) string { return EndpointGuilds + gID + "/integrations" }
EndpointGuildIntegration = func(gID, iID string) string { return EndpointGuilds + gID + "/integrations/" + iID }
EndpointGuildIntegrationSync = func(gID, iID string) string { return EndpointGuilds + gID + "/integrations/" + iID + "/sync" }
EndpointGuildRoles = func(gID string) string { return EndpointGuilds + gID + "/roles" }
EndpointGuildRole = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID }
EndpointGuildInvites = func(gID string) string { return EndpointGuilds + gID + "/invites" }
EndpointGuildWidget = func(gID string) string { return EndpointGuilds + gID + "/widget" }
EndpointGuildEmbed = EndpointGuildWidget
EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" }
EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
EndpointGuildSplash = func(gID, hash string) string { return EndpointCDNSplashes + gID + "/" + hash + ".png" }
EndpointGuildWebhooks = func(gID string) string { return EndpointGuilds + gID + "/webhooks" }
EndpointGuildAuditLogs = func(gID string) string { return EndpointGuilds + gID + "/audit-logs" }
EndpointGuildEmojis = func(gID string) string { return EndpointGuilds + gID + "/emojis" }
EndpointGuildEmoji = func(gID, eID string) string { return EndpointGuilds + gID + "/emojis/" + eID }
EndpointGuildBanner = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" }
EndpointChannel = func(cID string) string { return EndpointChannels + cID }
EndpointChannelPermissions = func(cID string) string { return EndpointChannels + cID + "/permissions" }
EndpointChannelPermission = func(cID, tID string) string { return EndpointChannels + cID + "/permissions/" + tID }
EndpointChannelInvites = func(cID string) string { return EndpointChannels + cID + "/invites" }
EndpointChannelTyping = func(cID string) string { return EndpointChannels + cID + "/typing" }
EndpointChannelMessages = func(cID string) string { return EndpointChannels + cID + "/messages" }
EndpointChannelMessage = func(cID, mID string) string { return EndpointChannels + cID + "/messages/" + mID }
EndpointChannelMessageAck = func(cID, mID string) string { return EndpointChannels + cID + "/messages/" + mID + "/ack" }
EndpointChannelMessagesBulkDelete = func(cID string) string { return EndpointChannel(cID) + "/messages/bulk-delete" }
EndpointChannelMessagesPins = func(cID string) string { return EndpointChannel(cID) + "/pins" }
EndpointChannelMessagePin = func(cID, mID string) string { return EndpointChannel(cID) + "/pins/" + mID }
EndpointChannelMessageCrosspost = func(cID, mID string) string { return EndpointChannel(cID) + "/messages/" + mID + "/crosspost" }
EndpointChannelFollow = func(cID string) string { return EndpointChannel(cID) + "/followers" }
EndpointGroupIcon = func(cID, hash string) string { return EndpointCDNChannelIcons + cID + "/" + hash + ".png" }
EndpointChannelWebhooks = func(cID string) string { return EndpointChannel(cID) + "/webhooks" }
EndpointWebhook = func(wID string) string { return EndpointWebhooks + wID }
EndpointWebhookToken = func(wID, token string) string { return EndpointWebhooks + wID + "/" + token }
EndpointMessageReactionsAll = func(cID, mID string) string {
return EndpointChannelMessage(cID, mID) + "/reactions"
}
EndpointMessageReactions = func(cID, mID, eID string) string {
return EndpointChannelMessage(cID, mID) + "/reactions/" + eID
}
EndpointMessageReaction = func(cID, mID, eID, uID string) string {
return EndpointMessageReactions(cID, mID, eID) + "/" + uID
}
EndpointRelationships = func() string { return EndpointUsers + "@me" + "/relationships" }
EndpointRelationship = func(uID string) string { return EndpointRelationships() + "/" + uID }
EndpointRelationshipsMutual = func(uID string) string { return EndpointUsers + uID + "/relationships" }
EndpointGuildCreate = EndpointAPI + "guilds"
EndpointInvite = func(iID string) string { return EndpointAPI + "invite/" + iID }
EndpointIntegrationsJoin = func(iID string) string { return EndpointAPI + "integrations/" + iID + "/join" }
EndpointEmoji = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".png" }
EndpointEmojiAnimated = func(eID string) string { return EndpointCDN + "emojis/" + eID + ".gif" }
EndpointOauth2 = EndpointAPI + "oauth2/"
EndpointApplications = EndpointOauth2 + "applications"
EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID }
EndpointApplicationsBot = func(aID string) string { return EndpointApplications + "/" + aID + "/bot" }
EndpointApplicationAssets = func(aID string) string { return EndpointApplications + "/" + aID + "/assets" }
)

@ -1,54 +0,0 @@
package discordgo
import (
"bytes"
"crypto/ed25519"
"encoding/hex"
"io"
"io/ioutil"
"net/http"
)
// VerifyInteraction implements message verification of the discord interactions api
// signing algorithm, as documented here:
// https://discord.com/developers/docs/interactions/slash-commands#security-and-authorization
func VerifyInteraction(r *http.Request, key ed25519.PublicKey) bool {
var msg bytes.Buffer
signature := r.Header.Get("X-Signature-Ed25519")
if signature == "" {
return false
}
sig, err := hex.DecodeString(signature)
if err != nil {
return false
}
if len(sig) != ed25519.SignatureSize {
return false
}
timestamp := r.Header.Get("X-Signature-Timestamp")
if timestamp == "" {
return false
}
msg.WriteString(timestamp)
defer r.Body.Close()
var body bytes.Buffer
// at the end of the function, copy the original body back into the request
defer func() {
r.Body = ioutil.NopCloser(&body)
}()
// copy body into buffers
_, err = io.Copy(&msg, io.TeeReader(r.Body, &body))
if err != nil {
return false
}
return ed25519.Verify(key, msg.Bytes(), sig)
}

File diff suppressed because it is too large Load Diff

@ -1,17 +0,0 @@
package discordgo
import (
"strconv"
"time"
)
// SnowflakeTimestamp returns the creation time of a Snowflake ID relative to the creation of Discord.
func SnowflakeTimestamp(ID string) (t time.Time, err error) {
i, err := strconv.ParseInt(ID, 10, 64)
if err != nil {
return
}
timestamp := (i >> 22) + 1420070400000
t = time.Unix(0, timestamp*1000000)
return
}

@ -51,6 +51,9 @@ github.com/av-elier/go-decimal-to-rational
# github.com/blang/semver v3.5.1+incompatible
## explicit
github.com/blang/semver
# github.com/bwmarrin/discordgo v0.24.0
## explicit; go 1.13
github.com/bwmarrin/discordgo
# github.com/d5/tengo/v2 v2.10.0
## explicit; go 1.13
github.com/d5/tengo/v2
@ -194,9 +197,6 @@ github.com/matrix-org/gomatrix
github.com/matterbridge/Rocket.Chat.Go.SDK/models
github.com/matterbridge/Rocket.Chat.Go.SDK/realtime
github.com/matterbridge/Rocket.Chat.Go.SDK/rest
# github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7
## explicit; go 1.10
github.com/matterbridge/discordgo
# github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be
## explicit
github.com/matterbridge/go-xmpp

Loading…
Cancel
Save