diff --git a/restapi.go b/restapi.go index 886dd00..d17209c 100644 --- a/restapi.go +++ b/restapi.go @@ -79,9 +79,9 @@ const ( // Request makes a (GET/POST/?) Requests to Discord REST API. // All the other functions in this file use this function. -func Request(session *Session, method, urlStr, body string) (response []byte, err error) { +func (s *Session) Request(method, urlStr, body string) (response []byte, err error) { - if session.Debug { + if s.Debug { fmt.Println("REQUEST :: " + method + " " + urlStr + "\n" + body) } @@ -91,8 +91,8 @@ func Request(session *Session, method, urlStr, body string) (response []byte, er } // Not used on initial login.. - if session.Token != "" { - req.Header.Set("authorization", session.Token) + if s.Token != "" { + req.Header.Set("authorization", s.Token) } req.Header.Set("Content-Type", "application/json") @@ -114,7 +114,7 @@ func Request(session *Session, method, urlStr, body string) (response []byte, er return } - if session.Debug { + if s.Debug { var prettyJSON bytes.Buffer error := json.Indent(&prettyJSON, response, "", "\t") if error != nil { @@ -127,9 +127,9 @@ func Request(session *Session, method, urlStr, body string) (response []byte, er } // Login asks the Discord server for an authentication token -func Login(session *Session, email string, password string) (token string, err error) { +func (s *Session) Login(email string, password string) (token string, err error) { - response, err := Request(session, "POST", LOGIN, fmt.Sprintf(`{"email":"%s", "password":"%s"}`, email, password)) + response, err := s.Request("POST", LOGIN, fmt.Sprintf(`{"email":"%s", "password":"%s"}`, email, password)) var temp map[string]interface{} err = json.Unmarshal(response, &temp) @@ -141,9 +141,9 @@ func Login(session *Session, email string, password string) (token string, err e // Returns the user details of the given userId // session : An active session connection to Discord // user : A user Id or name -func Users(session *Session, userId string) (user User, err error) { +func (s *Session) Users(userId string) (user User, err error) { - body, err := Request(session, "GET", fmt.Sprintf("%s/%s", USERS, userId), ``) + body, err := s.Request("GET", fmt.Sprintf("%s/%s", USERS, userId), ``) err = json.Unmarshal(body, &user) return } @@ -154,18 +154,18 @@ func Users(session *Session, userId string) (user User, err error) { // PrivateChannels returns an array of Channel structures for all private // channels for a user -func PrivateChannels(session *Session, userId string) (channels []Channel, err error) { +func (s *Session) PrivateChannels(userId string) (channels []Channel, err error) { - body, err := Request(session, "GET", fmt.Sprintf("%s/%s/channels", USERS, userId), ``) + body, err := s.Request("GET", fmt.Sprintf("%s/%s/channels", USERS, userId), ``) err = json.Unmarshal(body, &channels) return } // Guilds returns an array of Guild structures for all servers for a user -func Guilds(session *Session, userId string) (servers []Guild, err error) { +func (s *Session) Guilds(userId string) (servers []Guild, err error) { - body, err := Request(session, "GET", fmt.Sprintf("%s/%s/guilds", USERS, userId), ``) + body, err := s.Request("GET", fmt.Sprintf("%s/%s/guilds", USERS, userId), ``) err = json.Unmarshal(body, &servers) return @@ -176,9 +176,9 @@ func Guilds(session *Session, userId string) (servers []Guild, err error) { // Members returns an array of Member structures for all members of a given // server. -func Members(session *Session, serverId int) (members []Member, err error) { +func (s *Session) Members(serverId int) (members []Member, err error) { - body, err := Request(session, "GET", fmt.Sprintf("%s/%d/members", SERVERS, serverId), ``) + body, err := s.Request("GET", fmt.Sprintf("%s/%d/members", SERVERS, serverId), ``) err = json.Unmarshal(body, &members) return @@ -186,9 +186,9 @@ func Members(session *Session, serverId int) (members []Member, err error) { // Channels returns an array of Channel structures for all channels of a given // server. -func Channels(session *Session, serverId int) (channels []Channel, err error) { +func (s *Session) Channels(serverId int) (channels []Channel, err error) { - body, err := Request(session, "GET", fmt.Sprintf("%s/%d/channels", SERVERS, serverId), ``) + body, err := s.Request("GET", fmt.Sprintf("%s/%d/channels", SERVERS, serverId), ``) err = json.Unmarshal(body, &channels) return @@ -201,7 +201,7 @@ func Channels(session *Session, serverId int) (channels []Channel, err error) { // Messages returns an array of Message structures for messaages within a given // channel. limit, beforeId, and afterId can be used to control what messages // are returned. -func Messages(session *Session, channelId int, limit int, beforeId int, afterId int) (messages []Message, err error) { +func (s *Session) Messages(channelId int, limit int, beforeId int, afterId int) (messages []Message, err error) { var urlStr string @@ -229,17 +229,17 @@ func Messages(session *Session, channelId int, limit int, beforeId int, afterId urlStr = fmt.Sprintf("%s/%d/messages", CHANNELS, channelId) } - body, err := Request(session, "GET", urlStr, ``) + body, err := s.Request("GET", urlStr, ``) err = json.Unmarshal(body, &messages) return } // SendMessage sends a message to the given channel. -func SendMessage(session *Session, channelId int, content string) (message Message, err error) { +func (s *Session) SendMessage(channelId int, content string) (message Message, err error) { var urlStr string = fmt.Sprintf("%s/%d/messages", CHANNELS, channelId) - response, err := Request(session, "POST", urlStr, fmt.Sprintf(`{"content":"%s"}`, content)) + response, err := s.Request("POST", urlStr, fmt.Sprintf(`{"content":"%s"}`, content)) err = json.Unmarshal(response, &message) return @@ -247,9 +247,9 @@ func SendMessage(session *Session, channelId int, content string) (message Messa // Returns the a websocket Gateway address // session : An active session connection to Discord -func Gateway(session *Session) (gateway string, err error) { +func (s *Session) Gateway() (gateway string, err error) { - response, err := Request(session, "GET", GATEWAY, ``) + response, err := s.Request("GET", GATEWAY, ``) var temp map[string]interface{} err = json.Unmarshal(response, &temp) @@ -261,9 +261,9 @@ func Gateway(session *Session) (gateway string, err error) { // This does not seem to actually invalidate the token. So you can still // make API calls even after a Logout. So, it seems almost pointless to // even use. -func Logout(session *Session) (err error) { +func (s *Session) Logout() (err error) { - _, err = Request(session, "POST", LOGOUT, fmt.Sprintf(`{"token": "%s"}`, session.Token)) + _, err = s.Request("POST", LOGOUT, fmt.Sprintf(`{"token": "%s"}`, s.Token)) return } diff --git a/session.go b/session.go index e52380f..d3ea66d 100644 --- a/session.go +++ b/session.go @@ -1,5 +1,13 @@ /****************************************************************************** * A Discord API for Golang. + * + * This file has structs and functions specific to a session. + * + * A session is a single connection to Discord for a given + * user and all REST and Websock API functions exist within + * a session. + * + * See the restapi.go and wsapi.go for more information. */ package discordgo @@ -10,10 +18,9 @@ import "github.com/gorilla/websocket" // token : The authentication token returned from Discord // Debug : If set to ture debug logging will be displayed. type Session struct { - Token string // Authentication token for this session - Gateway string // Websocket Gateway for this session - Debug bool // Debug for printing JSON request/responses - Cache int // number in X to cache some responses + Token string // Authentication token for this session + Debug bool // Debug for printing JSON request/responses + Cache int // number in X to cache some responses // Settable Callback functions for Websocket Events OnEvent func(*Session, Event) // should Event be *Event? @@ -36,6 +43,7 @@ type Session struct { OnGuildMemberDelete func(*Session, Member) // which is it? OnGuildMemberUpdate func(*Session, Member) OnGuildRoleCreate func(*Session, Role) + OnGuildRoleUpdate func(*Session, GuildRoleUpdate) OnGuildRoleDelete func(*Session, Role) OnGuildIntegrationsUpdate func(*Session, GuildIntegrationsUpdate) @@ -56,28 +64,17 @@ type Session struct { * The below functions are "shortcut" methods for functions in restapi.go * Reference the client.go file for more documentation. */ -func (session *Session) Login(email string, password string) (token string, err error) { - token, err = Login(session, email, password) +func (s *Session) Self() (user User, err error) { + user, err = s.Users("@me") return } -func (session *Session) Self() (user User, err error) { - user, err = Users(session, "@me") +func (s *Session) MyPrivateChannels() (channels []Channel, err error) { + channels, err = s.PrivateChannels("@me") return } -func (session *Session) PrivateChannels() (channels []Channel, err error) { - channels, err = PrivateChannels(session, "@me") - return -} - -func (session *Session) Guilds() (servers []Guild, err error) { - servers, err = Guilds(session, "@me") - return -} - -// Logout ends a session and logs out from the Discord REST API. -func (session *Session) Logout() (err error) { - err = Logout(session) +func (s *Session) MyGuilds() (servers []Guild, err error) { + servers, err = s.Guilds("@me") return } diff --git a/wsapi.go b/wsapi.go index 8e00c62..22fd859 100644 --- a/wsapi.go +++ b/wsapi.go @@ -26,7 +26,7 @@ type Event struct { //Direction of command, 0-received, 1-sent -- thanks Xackery/discord RawData json.RawMessage `json:"d"` - Session Session + Session *Session } // The Ready Event given after initial connection @@ -88,19 +88,27 @@ type GuildIntegrationsUpdate struct { GuildId int `json:"guild_id,string"` } +type GuildRoleUpdate struct { + Role Role `json:"role"` + GuildId int `json:"guild_id,int"` +} + // Open a websocket connection to Discord -func Open(s *Session) (err error) { +func (s *Session) Open() (err error) { + + // Get the gateway to use for the Websocket connection + g, err := s.Gateway() // TODO: See if there's a use for the http response. // conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil) - s.wsConn, _, err = websocket.DefaultDialer.Dial(s.Gateway, nil) + s.wsConn, _, err = websocket.DefaultDialer.Dial(g, nil) return } // maybe this is SendOrigin? not sure the right name here // also bson.M vs string interface map? Read about // how to send JSON the right way. -func Handshake(s *Session) (err error) { +func (s *Session) Handshake() (err error) { err = s.wsConn.WriteJSON(map[string]interface{}{ "op": 2, @@ -120,7 +128,7 @@ func Handshake(s *Session) (err error) { return } -func UpdateStatus(s *Session, idleSince, gameId string) (err error) { +func (s *Session) UpdateStatus(idleSince, gameId string) (err error) { err = s.wsConn.WriteJSON(map[string]interface{}{ "op": 2, @@ -135,7 +143,7 @@ func UpdateStatus(s *Session, idleSince, gameId string) (err error) { // TODO: need a channel or something to communicate // to this so I can tell it to stop listening -func Listen(s *Session) (err error) { +func (s *Session) Listen() (err error) { if s.wsConn == nil { fmt.Println("No websocket connection exists.") @@ -148,7 +156,7 @@ func Listen(s *Session) (err error) { fmt.Println(err) break } - go event(s, messageType, message) + go s.event(messageType, message) } return @@ -156,13 +164,13 @@ func Listen(s *Session) (err error) { // Not sure how needed this is and where it would be best to call it. // somewhere. -func Close(s *Session) { +func (s *Session) Close() { s.wsConn.Close() } // Front line handler for all Websocket Events. Determines the // event type and passes the message along to the next handler. -func event(s *Session, messageType int, message []byte) (err error) { +func (s *Session) event(messageType int, message []byte) (err error) { if s.Debug { printJSON(message) @@ -362,10 +370,18 @@ func event(s *Session, messageType int, message []byte) (err error) { s.OnGuildMemberUpdate(s, st) return } + case "GUILD_ROLE_CREATE": + if s.OnGuildRoleUpdate != nil { + var st GuildRoleUpdate + if err := json.Unmarshal(e.RawData, &st); err != nil { + fmt.Println(e.Type, err) + printJSON(e.RawData) // TODO: Better error logginEventg + return err + } + s.OnGuildRoleUpdate(s, st) + return + } /* - case "GUILD_ROLE_CREATE": - if s.OnGuildRoleCreate != nil { - } case "GUILD_ROLE_DELETE": if s.OnGuildRoleDelete != nil { } @@ -398,7 +414,7 @@ func event(s *Session, messageType int, message []byte) (err error) { // This heartbeat is sent to keep the Websocket conenction // to Discord alive. If not sent, Discord will close the // connection. -func Heartbeat(s *Session, i time.Duration) { +func (s *Session) Heartbeat(i time.Duration) { if s.wsConn == nil { fmt.Println("No websocket connection exists.")