diff --git a/endpoints.go b/endpoints.go index 95f6fd9..b961908 100644 --- a/endpoints.go +++ b/endpoints.go @@ -136,7 +136,8 @@ var ( EndpointIntegrationsJoin = func(iID string) string { return EndpointAPI + "integrations/" + iID + "/join" } - EndpointEmoji = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".png" } + EndpointEmoji = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".png" } + EndpointEmojiAnimated = func(eID string) string { return EndpointAPI + "emojis/" + eID + ".gif" } EndpointOauth2 = EndpointAPI + "oauth2/" EndpointApplications = EndpointOauth2 + "applications" diff --git a/eventhandlers.go b/eventhandlers.go index 5cc157d..d2b9a98 100644 --- a/eventhandlers.go +++ b/eventhandlers.go @@ -50,6 +50,7 @@ const ( userUpdateEventType = "USER_UPDATE" voiceServerUpdateEventType = "VOICE_SERVER_UPDATE" voiceStateUpdateEventType = "VOICE_STATE_UPDATE" + webhooksUpdateEventType = "WEBHOOKS_UPDATE" ) // channelCreateEventHandler is an event handler for ChannelCreate events. @@ -892,6 +893,26 @@ func (eh voiceStateUpdateEventHandler) Handle(s *Session, i interface{}) { } } +// webhooksUpdateEventHandler is an event handler for WebhooksUpdate events. +type webhooksUpdateEventHandler func(*Session, *WebhooksUpdate) + +// Type returns the event type for WebhooksUpdate events. +func (eh webhooksUpdateEventHandler) Type() string { + return webhooksUpdateEventType +} + +// New returns a new instance of WebhooksUpdate. +func (eh webhooksUpdateEventHandler) New() interface{} { + return &WebhooksUpdate{} +} + +// Handle is the handler for WebhooksUpdate events. +func (eh webhooksUpdateEventHandler) Handle(s *Session, i interface{}) { + if t, ok := i.(*WebhooksUpdate); ok { + eh(s, t) + } +} + func handlerForInterface(handler interface{}) EventHandler { switch v := handler.(type) { case func(*Session, interface{}): @@ -982,6 +1003,8 @@ func handlerForInterface(handler interface{}) EventHandler { return voiceServerUpdateEventHandler(v) case func(*Session, *VoiceStateUpdate): return voiceStateUpdateEventHandler(v) + case func(*Session, *WebhooksUpdate): + return webhooksUpdateEventHandler(v) } return nil @@ -1027,4 +1050,5 @@ func init() { registerInterfaceProvider(userUpdateEventHandler(nil)) registerInterfaceProvider(voiceServerUpdateEventHandler(nil)) registerInterfaceProvider(voiceStateUpdateEventHandler(nil)) + registerInterfaceProvider(webhooksUpdateEventHandler(nil)) } diff --git a/events.go b/events.go index e784cac..c4fb520 100644 --- a/events.go +++ b/events.go @@ -254,3 +254,9 @@ type MessageDeleteBulk struct { ChannelID string `json:"channel_id"` GuildID string `json:"guild_id"` } + +// WebhooksUpdate is the data for a WebhooksUpdate event +type WebhooksUpdate struct { + GuildID string `json:"guild_id"` + ChannelID string `json:"channel_id"` +} diff --git a/message_test.go b/message_test.go index 8bff87b..792bfc4 100644 --- a/message_test.go +++ b/message_test.go @@ -12,7 +12,6 @@ func TestContentWithMoreMentionsReplaced(t *testing.T) { Username: "User Name", } - s.StateEnabled = true s.State.GuildAdd(&Guild{ID: "guild"}) s.State.RoleAdd("guild", &Role{ ID: "role", diff --git a/restapi.go b/restapi.go index 476f783..9d53065 100644 --- a/restapi.go +++ b/restapi.go @@ -90,7 +90,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b req.Header.Set("Content-Type", contentType) // TODO: Make a configurable static variable. - req.Header.Set("User-Agent", fmt.Sprintf("DiscordBot (https://github.com/bwmarrin/discordgo, v%s)", VERSION)) + req.Header.Set("User-Agent", "DiscordBot (https://github.com/bwmarrin/discordgo, v"+VERSION+")") if s.Debug { for k, v := range req.Header { @@ -250,7 +250,7 @@ func (s *Session) Register(username string) (token string, err error) { // even use. func (s *Session) Logout() (err error) { - // _, err = s.Request("POST", LOGOUT, fmt.Sprintf(`{"token": "%s"}`, s.Token)) + // _, err = s.Request("POST", LOGOUT, `{"token": "` + s.Token + `"}`) if s.Token == "" { return @@ -428,7 +428,7 @@ func (s *Session) UserGuilds(limit int, beforeID, afterID string) (st []*UserGui uri := EndpointUserGuilds("@me") if len(v) > 0 { - uri = fmt.Sprintf("%s?%s", uri, v.Encode()) + uri += "?" + v.Encode() } body, err := s.RequestWithBucketID("GET", uri, nil, EndpointUserGuilds("")) @@ -743,7 +743,7 @@ func (s *Session) GuildMembers(guildID string, after string, limit int) (st []*M } if len(v) > 0 { - uri = fmt.Sprintf("%s?%s", uri, v.Encode()) + uri += "?" + v.Encode() } body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildMembers(guildID)) @@ -1065,7 +1065,7 @@ func (s *Session) GuildPruneCount(guildID string, days uint32) (count uint32, er Pruned uint32 `json:"pruned"` }{} - uri := EndpointGuildPrune(guildID) + fmt.Sprintf("?days=%d", days) + uri := EndpointGuildPrune(guildID) + "?days=" + strconv.FormatUint(uint64(days), 10) body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildPrune(guildID)) if err != nil { return @@ -1423,7 +1423,7 @@ func (s *Session) ChannelMessages(channelID string, limit int, beforeID, afterID v.Set("around", aroundID) } if len(v) > 0 { - uri = fmt.Sprintf("%s?%s", uri, v.Encode()) + uri += "?" + v.Encode() } body, err := s.RequestWithBucketID("GET", uri, nil, EndpointChannelMessages(channelID)) @@ -2103,7 +2103,7 @@ func (s *Session) MessageReactions(channelID, messageID, emojiID string, limit i } if len(v) > 0 { - uri = fmt.Sprintf("%s?%s", uri, v.Encode()) + uri += "?" + v.Encode() } body, err := s.RequestWithBucketID("GET", uri, nil, EndpointMessageReaction(channelID, "", "", "")) diff --git a/structs.go b/structs.go index d089b5f..97f726c 100644 --- a/structs.go +++ b/structs.go @@ -597,7 +597,7 @@ type Member struct { GuildID string `json:"guild_id"` // The time at which the member joined the guild, in ISO8601. - JoinedAt string `json:"joined_at"` + JoinedAt Timestamp `json:"joined_at"` // The nickname of the member, if they have one. Nick string `json:"nick"` @@ -615,6 +615,11 @@ type Member struct { Roles []string `json:"roles"` } +// Mention creates a member mention +func (m *Member) Mention() string { + return "<@!" + m.User.ID + ">" +} + // A Settings stores data for a specific users Discord client settings. type Settings struct { RenderEmbeds bool `json:"render_embeds"` @@ -929,6 +934,7 @@ const ( ErrCodeUnknownToken = 10012 ErrCodeUnknownUser = 10013 ErrCodeUnknownEmoji = 10014 + ErrCodeUnknownWebhook = 10015 ErrCodeBotsCannotUseEndpoint = 20001 ErrCodeOnlyBotsCanUseEndpoint = 20002 diff --git a/types.go b/types.go index 780b6bb..c0ce013 100644 --- a/types.go +++ b/types.go @@ -11,7 +11,6 @@ package discordgo import ( "encoding/json" - "fmt" "net/http" "time" ) @@ -54,5 +53,5 @@ func newRestError(req *http.Request, resp *http.Response, body []byte) *RESTErro } func (r RESTError) Error() string { - return fmt.Sprintf("HTTP %s, %s", r.Response.Status, r.ResponseBody) + return "HTTP " + r.Response.Status + ", " + string(r.ResponseBody) } diff --git a/user.go b/user.go index 618a7d5..a9af31a 100644 --- a/user.go +++ b/user.go @@ -1,9 +1,6 @@ package discordgo -import ( - "fmt" - "strings" -) +import "strings" // A User stores all data for an individual Discord user. type User struct { @@ -43,12 +40,12 @@ type User struct { // String returns a unique identifier of the form username#discriminator func (u *User) String() string { - return fmt.Sprintf("%s#%s", u.Username, u.Discriminator) + return u.Username + "#" + u.Discriminator } // Mention return a string which mentions the user func (u *User) Mention() string { - return fmt.Sprintf("<@%s>", u.ID) + return "<@" + u.ID + ">" } // AvatarURL returns a URL to the user's avatar. diff --git a/voice.go b/voice.go index 85fb6b8..b904508 100644 --- a/voice.go +++ b/voice.go @@ -14,6 +14,7 @@ import ( "encoding/json" "fmt" "net" + "strconv" "strings" "sync" "time" @@ -135,7 +136,6 @@ func (v *VoiceConnection) ChangeChannel(channelID string, mute, deaf bool) (err // Disconnect disconnects from this voice channel and closes the websocket // and udp connections to Discord. -// !!! NOTE !!! this function may be removed in favour of ChannelVoiceLeave func (v *VoiceConnection) Disconnect() (err error) { // Send a OP4 with a nil channel to disconnect @@ -299,7 +299,7 @@ func (v *VoiceConnection) open() (err error) { } // Connect to VoiceConnection Websocket - vg := fmt.Sprintf("wss://%s", strings.TrimSuffix(v.endpoint, ":80")) + vg := "wss://" + strings.TrimSuffix(v.endpoint, ":80") v.log(LogInformational, "connecting to voice endpoint %s", vg) v.wsConn, _, err = websocket.DefaultDialer.Dial(vg, nil) if err != nil { @@ -542,7 +542,7 @@ func (v *VoiceConnection) udpOpen() (err error) { return fmt.Errorf("empty endpoint") } - host := fmt.Sprintf("%s:%d", strings.TrimSuffix(v.endpoint, ":80"), v.op2.Port) + host := strings.TrimSuffix(v.endpoint, ":80") + ":" + strconv.Itoa(v.op2.Port) addr, err := net.ResolveUDPAddr("udp", host) if err != nil { v.log(LogWarning, "error resolving udp host %s, %s", host, err) diff --git a/wsapi.go b/wsapi.go index 80e85ac..9b94b23 100644 --- a/wsapi.go +++ b/wsapi.go @@ -85,6 +85,10 @@ func (s *Session) Open() error { s.wsConn = nil // Just to be safe. return err } + + s.wsConn.SetCloseHandler(func(code int, text string) error { + return nil + }) defer func() { // because of this, all code below must set err to the error