This commit is contained in:
Bruce Marriner 2016-01-28 08:36:09 -06:00
parent 53db54ea8c
commit edc09778a7
6 changed files with 132 additions and 54 deletions

View file

@ -12,13 +12,13 @@ import (
var ( var (
dg *Session // Stores global discordgo session dg *Session // Stores global discordgo session
envToken string = os.Getenv("DG_TOKEN") // Token to use when authenticating envToken = os.Getenv("DG_TOKEN") // Token to use when authenticating
envEmail string = os.Getenv("DG_EMAIL") // Email to use when authenticating envEmail = os.Getenv("DG_EMAIL") // Email to use when authenticating
envPassword string = os.Getenv("DG_PASSWORD") // Password to use when authenticating envPassword = os.Getenv("DG_PASSWORD") // Password to use when authenticating
envGuild string = os.Getenv("DG_GUILD") // Guild ID to use for tests envGuild = os.Getenv("DG_GUILD") // Guild ID to use for tests
envChannel string = os.Getenv("DG_CHANNEL") // Channel ID to use for tests envChannel = os.Getenv("DG_CHANNEL") // Channel ID to use for tests
envUser string = os.Getenv("DG_USER") // User ID to use for tests envUser = os.Getenv("DG_USER") // User ID to use for tests
envAdmin string = os.Getenv("DG_ADMIN") // User ID of admin user to use for tests envAdmin = os.Getenv("DG_ADMIN") // User ID of admin user to use for tests
) )
func init() { func init() {

View file

@ -25,7 +25,7 @@ import (
"time" "time"
) )
// Error returned for unmarshal errors. // ErrJSONUnmarshal is returned for JSON Unmarshall errors.
var ErrJSONUnmarshal = errors.New("json unmarshal") var ErrJSONUnmarshal = errors.New("json unmarshal")
// Request makes a (GET/POST/...) Requests to Discord REST API. // Request makes a (GET/POST/...) Requests to Discord REST API.
@ -69,10 +69,15 @@ func (s *Session) Request(method, urlStr string, data interface{}) (response []b
client := &http.Client{Timeout: (20 * time.Second)} client := &http.Client{Timeout: (20 * time.Second)}
resp, err := client.Do(req) resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil { if err != nil {
return return
} }
defer func() {
err := resp.Body.Close()
if err != nil {
fmt.Println("error closing resp body")
}
}()
response, err = ioutil.ReadAll(resp.Body) response, err = ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {

View file

@ -12,9 +12,13 @@
package discordgo package discordgo
import "errors" import (
"errors"
"fmt"
)
var nilError error = errors.New("State not instantiated, please use discordgo.New() or assign Session.State.") // ErrNilState is returned when the state is nil.
var ErrNilState = errors.New("State not instantiated, please use discordgo.New() or assign Session.State.")
// NewState creates an empty state. // NewState creates an empty state.
func NewState() *State { func NewState() *State {
@ -29,7 +33,7 @@ func NewState() *State {
// OnReady takes a Ready event and updates all internal state. // OnReady takes a Ready event and updates all internal state.
func (s *State) OnReady(r *Ready) error { func (s *State) OnReady(r *Ready) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
@ -42,7 +46,7 @@ func (s *State) OnReady(r *Ready) error {
// updates it if it already exists. // updates it if it already exists.
func (s *State) GuildAdd(guild *Guild) error { func (s *State) GuildAdd(guild *Guild) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
@ -67,7 +71,7 @@ func (s *State) GuildAdd(guild *Guild) error {
// GuildRemove removes a guild from current world state. // GuildRemove removes a guild from current world state.
func (s *State) GuildRemove(guild *Guild) error { func (s *State) GuildRemove(guild *Guild) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
@ -88,7 +92,7 @@ func (s *State) GuildRemove(guild *Guild) error {
// isInGuild := err == nil // isInGuild := err == nil
func (s *State) Guild(guildID string) (*Guild, error) { func (s *State) Guild(guildID string) (*Guild, error) {
if s == nil { if s == nil {
return nil, nilError return nil, ErrNilState
} }
s.RLock() s.RLock()
defer s.RUnlock() defer s.RUnlock()
@ -108,7 +112,7 @@ func (s *State) Guild(guildID string) (*Guild, error) {
// updates it if it already exists. // updates it if it already exists.
func (s *State) MemberAdd(member *Member) error { func (s *State) MemberAdd(member *Member) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
guild, err := s.Guild(member.GuildID) guild, err := s.Guild(member.GuildID)
@ -133,7 +137,7 @@ func (s *State) MemberAdd(member *Member) error {
// MemberRemove removes a member from current world state. // MemberRemove removes a member from current world state.
func (s *State) MemberRemove(member *Member) error { func (s *State) MemberRemove(member *Member) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
guild, err := s.Guild(member.GuildID) guild, err := s.Guild(member.GuildID)
@ -157,7 +161,7 @@ func (s *State) MemberRemove(member *Member) error {
// Member gets a member by ID from a guild. // Member gets a member by ID from a guild.
func (s *State) Member(guildID, userID string) (*Member, error) { func (s *State) Member(guildID, userID string) (*Member, error) {
if s == nil { if s == nil {
return nil, nilError return nil, ErrNilState
} }
guild, err := s.Guild(guildID) guild, err := s.Guild(guildID)
@ -183,7 +187,7 @@ func (s *State) Member(guildID, userID string) (*Member, error) {
// a guild. // a guild.
func (s *State) ChannelAdd(channel *Channel) error { func (s *State) ChannelAdd(channel *Channel) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
if channel.IsPrivate { if channel.IsPrivate {
@ -229,7 +233,7 @@ func (s *State) ChannelAdd(channel *Channel) error {
// ChannelRemove removes a channel from current world state. // ChannelRemove removes a channel from current world state.
func (s *State) ChannelRemove(channel *Channel) error { func (s *State) ChannelRemove(channel *Channel) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
if channel.IsPrivate { if channel.IsPrivate {
@ -265,7 +269,7 @@ func (s *State) ChannelRemove(channel *Channel) error {
// GuildChannel gets a channel by ID from a guild. // GuildChannel gets a channel by ID from a guild.
func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) { func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) {
if s == nil { if s == nil {
return nil, nilError return nil, ErrNilState
} }
guild, err := s.Guild(guildID) guild, err := s.Guild(guildID)
@ -288,7 +292,7 @@ func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) {
// PrivateChannel gets a private channel by ID. // PrivateChannel gets a private channel by ID.
func (s *State) PrivateChannel(channelID string) (*Channel, error) { func (s *State) PrivateChannel(channelID string) (*Channel, error) {
if s == nil { if s == nil {
return nil, nilError return nil, ErrNilState
} }
s.RLock() s.RLock()
defer s.RUnlock() defer s.RUnlock()
@ -305,7 +309,7 @@ func (s *State) PrivateChannel(channelID string) (*Channel, error) {
// Channel gets a channel by ID, it will look in all guilds an private channels. // Channel gets a channel by ID, it will look in all guilds an private channels.
func (s *State) Channel(channelID string) (*Channel, error) { func (s *State) Channel(channelID string) (*Channel, error) {
if s == nil { if s == nil {
return nil, nilError return nil, ErrNilState
} }
c, err := s.PrivateChannel(channelID) c, err := s.PrivateChannel(channelID)
@ -326,7 +330,7 @@ func (s *State) Channel(channelID string) (*Channel, error) {
// Emoji returns an emoji for a guild and emoji id. // Emoji returns an emoji for a guild and emoji id.
func (s *State) Emoji(guildID, emojiID string) (*Emoji, error) { func (s *State) Emoji(guildID, emojiID string) (*Emoji, error) {
if s == nil { if s == nil {
return nil, nilError return nil, ErrNilState
} }
guild, err := s.Guild(guildID) guild, err := s.Guild(guildID)
@ -349,7 +353,7 @@ func (s *State) Emoji(guildID, emojiID string) (*Emoji, error) {
// EmojiAdd adds an emoji to the current world state. // EmojiAdd adds an emoji to the current world state.
func (s *State) EmojiAdd(guildID string, emoji *Emoji) error { func (s *State) EmojiAdd(guildID string, emoji *Emoji) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
guild, err := s.Guild(guildID) guild, err := s.Guild(guildID)
@ -386,7 +390,7 @@ func (s *State) EmojisAdd(guildID string, emojis []*Emoji) error {
// Messages are kept in state up to s.MaxMessageCount // Messages are kept in state up to s.MaxMessageCount
func (s *State) MessageAdd(message *Message) error { func (s *State) MessageAdd(message *Message) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
c, err := s.Channel(message.ChannelID) c, err := s.Channel(message.ChannelID)
@ -410,7 +414,10 @@ func (s *State) MessageAdd(message *Message) error {
if len(c.Messages) > s.MaxMessageCount { if len(c.Messages) > s.MaxMessageCount {
s.Unlock() s.Unlock()
for len(c.Messages) > s.MaxMessageCount { for len(c.Messages) > s.MaxMessageCount {
s.MessageRemove(c.Messages[0]) err := s.MessageRemove(c.Messages[0])
if err != nil {
fmt.Println("message remove error: ", err)
}
} }
s.Lock() s.Lock()
} }
@ -420,7 +427,7 @@ func (s *State) MessageAdd(message *Message) error {
// MessageRemove removes a message from the world state. // MessageRemove removes a message from the world state.
func (s *State) MessageRemove(message *Message) error { func (s *State) MessageRemove(message *Message) error {
if s == nil { if s == nil {
return nilError return ErrNilState
} }
c, err := s.Channel(message.ChannelID) c, err := s.Channel(message.ChannelID)
if err != nil { if err != nil {
@ -443,7 +450,7 @@ func (s *State) MessageRemove(message *Message) error {
// Message gets a message by channel and message ID. // Message gets a message by channel and message ID.
func (s *State) Message(channelID, messageID string) (*Message, error) { func (s *State) Message(channelID, messageID string) (*Message, error) {
if s == nil { if s == nil {
return nil, nilError return nil, ErrNilState
} }
c, err := s.Channel(channelID) c, err := s.Channel(channelID)
if err != nil { if err != nil {

View file

@ -151,6 +151,7 @@ type PermissionOverwrite struct {
Allow int `json:"allow"` Allow int `json:"allow"`
} }
// Emoji struct holds data related to Emoji's
type Emoji struct { type Emoji struct {
Roles []string `json:"roles"` Roles []string `json:"roles"`
RequireColons bool `json:"require_colons"` RequireColons bool `json:"require_colons"`
@ -212,6 +213,7 @@ type Presence struct {
Game *Game `json:"game"` Game *Game `json:"game"`
} }
// A Game struct holds the name of the "playing .." game for a user
type Game struct { type Game struct {
Name string `json:"name"` Name string `json:"name"`
} }
@ -277,6 +279,8 @@ type Ready struct {
PrivateChannels []*Channel `json:"private_channels"` PrivateChannels []*Channel `json:"private_channels"`
Guilds []*Guild `json:"guilds"` Guilds []*Guild `json:"guilds"`
} }
// A RateLimit struct holds information related to a specific rate limit.
type RateLimit struct { type RateLimit struct {
Bucket string `json:"bucket"` Bucket string `json:"bucket"`
Message string `json:"message"` Message string `json:"message"`

View file

@ -112,11 +112,17 @@ func (v *Voice) Open() (err error) {
func (v *Voice) Close() { func (v *Voice) Close() {
if v.UDPConn != nil { if v.UDPConn != nil {
v.UDPConn.Close() err := v.UDPConn.Close()
if err != nil {
fmt.Println("error closing udp connection: ", err)
}
} }
if v.wsConn != nil { if v.wsConn != nil {
v.wsConn.Close() err := v.wsConn.Close()
if err != nil {
fmt.Println("error closing websocket connection: ", err)
}
} }
} }
@ -363,7 +369,7 @@ func (v *Voice) udpOpen() (err error) {
func (v *Voice) udpKeepAlive(i time.Duration) { func (v *Voice) udpKeepAlive(i time.Duration) {
var err error var err error
var sequence uint64 = 0 var sequence uint64
packet := make([]byte, 8) packet := make([]byte, 8)
@ -403,8 +409,8 @@ func (v *Voice) opusSender(opus <-chan []byte, rate, size int) {
v.Ready = true v.Ready = true
defer func() { v.Ready = false }() defer func() { v.Ready = false }()
var sequence uint16 = 0 var sequence uint16
var timestamp uint32 = 0 var timestamp uint32
udpHeader := make([]byte, 12) udpHeader := make([]byte, 12)
// build the parts that don't change in the udpHeader // build the parts that don't change in the udpHeader
@ -432,12 +438,16 @@ func (v *Voice) opusSender(opus <-chan []byte, rate, size int) {
// block here until we're exactly at the right time :) // block here until we're exactly at the right time :)
// Then send rtp audio packet to Discord over UDP // Then send rtp audio packet to Discord over UDP
<-ticker.C <-ticker.C
v.UDPConn.Write(sendbuf) _, err := v.UDPConn.Write(sendbuf)
if err != nil {
fmt.Println("error writing to udp connection: ", err)
}
if (sequence) == 0xFFFF { if (sequence) == 0xFFFF {
sequence = 0 sequence = 0
} else { } else {
sequence += 1 sequence++
} }
if (timestamp + uint32(size)) >= 0xFFFFFFFF { if (timestamp + uint32(size)) >= 0xFFFFFFFF {

View file

@ -134,7 +134,10 @@ func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
if sameConnection { if sameConnection {
// There has been an error reading, Close() the websocket so that // There has been an error reading, Close() the websocket so that
// OnDisconnect is fired. // OnDisconnect is fired.
s.Close() err := s.Close()
if err != nil {
fmt.Println("error closing session connection: ", err)
}
// Attempt to reconnect, with expenonential backoff up to 10 minutes. // Attempt to reconnect, with expenonential backoff up to 10 minutes.
if s.ShouldReconnectOnError { if s.ShouldReconnectOnError {
@ -262,7 +265,8 @@ func unmarshalEvent(event *Event, i interface{}) (err error) {
// broken up into smaller functions to be more idiomatic Go. // broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session. // Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent. // All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) (err error) { func (s *Session) event(messageType int, message []byte) {
var err error
var reader io.Reader var reader io.Reader
reader = bytes.NewBuffer(message) reader = bytes.NewBuffer(message)
@ -270,9 +274,14 @@ func (s *Session) event(messageType int, message []byte) (err error) {
z, err1 := zlib.NewReader(reader) z, err1 := zlib.NewReader(reader)
if err1 != nil { if err1 != nil {
fmt.Println(err1) fmt.Println(err1)
return err1 return
} }
defer z.Close() defer func() {
err := z.Close()
if err != nil {
fmt.Println("error closing zlib:", err)
}
}()
reader = z reader = z
} }
@ -293,7 +302,11 @@ func (s *Session) event(messageType int, message []byte) (err error) {
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
go s.heartbeat(s.wsConn, s.listening, st.HeartbeatInterval) go s.heartbeat(s.wsConn, s.listening, st.HeartbeatInterval)
if s.StateEnabled { if s.StateEnabled {
s.State.OnReady(st) err := s.State.OnReady(st)
if err != nil {
fmt.Println("error: ", err)
}
} }
if s.OnReady != nil { if s.OnReady != nil {
s.OnReady(s, st) s.OnReady(s, st)
@ -353,7 +366,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Message var st *Message
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if stateEnabled { if stateEnabled {
s.State.MessageAdd(st) err := s.State.MessageAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnMessageCreate != nil { if s.OnMessageCreate != nil {
s.OnMessageCreate(s, st) s.OnMessageCreate(s, st)
@ -370,7 +386,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Message var st *Message
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if stateEnabled { if stateEnabled {
s.State.MessageAdd(st) err := s.State.MessageAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnMessageUpdate != nil { if s.OnMessageUpdate != nil {
s.OnMessageUpdate(s, st) s.OnMessageUpdate(s, st)
@ -385,7 +404,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Message var st *Message
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if stateEnabled { if stateEnabled {
s.State.MessageRemove(st) err := s.State.MessageRemove(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnMessageDelete != nil { if s.OnMessageDelete != nil {
s.OnMessageDelete(s, st) s.OnMessageDelete(s, st)
@ -407,7 +429,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Channel var st *Channel
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.ChannelAdd(st) err := s.State.ChannelAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnChannelCreate != nil { if s.OnChannelCreate != nil {
s.OnChannelCreate(s, st) s.OnChannelCreate(s, st)
@ -423,7 +448,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Channel var st *Channel
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.ChannelAdd(st) err := s.State.ChannelAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnChannelUpdate != nil { if s.OnChannelUpdate != nil {
s.OnChannelUpdate(s, st) s.OnChannelUpdate(s, st)
@ -439,7 +467,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Channel var st *Channel
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.ChannelRemove(st) err := s.State.ChannelRemove(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnChannelDelete != nil { if s.OnChannelDelete != nil {
s.OnChannelDelete(s, st) s.OnChannelDelete(s, st)
@ -455,7 +486,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Guild var st *Guild
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.GuildAdd(st) err := s.State.GuildAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnGuildCreate != nil { if s.OnGuildCreate != nil {
s.OnGuildCreate(s, st) s.OnGuildCreate(s, st)
@ -471,7 +505,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Guild var st *Guild
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.GuildAdd(st) err := s.State.GuildAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnGuildCreate != nil { if s.OnGuildCreate != nil {
s.OnGuildUpdate(s, st) s.OnGuildUpdate(s, st)
@ -487,7 +524,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Guild var st *Guild
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.GuildRemove(st) err := s.State.GuildRemove(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnGuildDelete != nil { if s.OnGuildDelete != nil {
s.OnGuildDelete(s, st) s.OnGuildDelete(s, st)
@ -503,7 +543,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Member var st *Member
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.MemberAdd(st) err := s.State.MemberAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnGuildMemberAdd != nil { if s.OnGuildMemberAdd != nil {
s.OnGuildMemberAdd(s, st) s.OnGuildMemberAdd(s, st)
@ -519,7 +562,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Member var st *Member
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.MemberRemove(st) err := s.State.MemberRemove(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnGuildMemberRemove != nil { if s.OnGuildMemberRemove != nil {
s.OnGuildMemberRemove(s, st) s.OnGuildMemberRemove(s, st)
@ -535,7 +581,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *Member var st *Member
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.MemberAdd(st) err := s.State.MemberAdd(st)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnGuildMemberUpdate != nil { if s.OnGuildMemberUpdate != nil {
s.OnGuildMemberUpdate(s, st) s.OnGuildMemberUpdate(s, st)
@ -599,7 +648,10 @@ func (s *Session) event(messageType int, message []byte) (err error) {
var st *GuildEmojisUpdate var st *GuildEmojisUpdate
if err = unmarshalEvent(e, &st); err == nil { if err = unmarshalEvent(e, &st); err == nil {
if s.StateEnabled { if s.StateEnabled {
s.State.EmojisAdd(st.GuildID, st.Emojis) err := s.State.EmojisAdd(st.GuildID, st.Emojis)
if err != nil {
fmt.Println("error :", err)
}
} }
if s.OnGuildEmojisUpdate != nil { if s.OnGuildEmojisUpdate != nil {
s.OnGuildEmojisUpdate(s, st) s.OnGuildEmojisUpdate(s, st)