diff --git a/channel.go b/channel.go new file mode 100644 index 0000000..631b217 --- /dev/null +++ b/channel.go @@ -0,0 +1,19 @@ +package discordgo + +type Channel struct { + Server_id int `json:"guild_id,string,omitempty"` + Id int `json:"id,string"` + Name string `json:"name"` + Topic string `json:"topic"` + Position int `json:"position"` + Last_message_id int `json:"last_message_id,string"` + Type string `json:"type"` + Is_private bool `json:"is_private"` + Permission_overwrites string `json:"-"` // ignored for now + Session *Session +} + +/* +func (c *Channel) Messages() (messages []Message) { +} +*/ diff --git a/client.go b/client.go new file mode 100644 index 0000000..6864bc6 --- /dev/null +++ b/client.go @@ -0,0 +1,165 @@ +/****************************************************************************** + * Discordgo by Bruce Marriner + * A Discord API for Golang. + * See discord.go for more information. + * + * This file contains functions for interacting with the Discord API + * at the lowest level. See other files for easier methods of access. + */ + +package discordgo + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +// RequestToken asks the Discord server for an authentication token +func RequestToken(session *Session, email string, password string) (token string, err error) { + + var urlStr string = fmt.Sprintf("%s/%s", discordApi, "auth/login") + req, err := http.NewRequest("POST", urlStr, bytes.NewBuffer([]byte(fmt.Sprintf(`{"email":"%s", "password":"%s"}`, email, password)))) + if err != nil { + return + } + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{Timeout: (20 * time.Second)} + resp, err := client.Do(req) + if err != nil { + return + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode != 200 { + err = errors.New(fmt.Sprintf("StatusCode: %d, %s", resp.StatusCode, string(body))) + return + } + + if session.Debug { + var prettyJSON bytes.Buffer + error := json.Indent(&prettyJSON, body, "", "\t") + if error != nil { + fmt.Print("JSON parse error: ", error) + return + } + fmt.Println("requestToken Response:\n", string(prettyJSON.Bytes())) + } + + temp := &Session{} // TODO Must be a better way + err = json.Unmarshal(body, &temp) + token = temp.Token + return +} + +// Request makes a REST API GET Request with Discord. +func Request(session *Session, urlStr string) (body []byte, err error) { + + req, err := http.NewRequest("GET", urlStr, bytes.NewBuffer([]byte(fmt.Sprintf(``)))) + if err != nil { + return + } + + req.Header.Set("authorization", session.Token) + req.Header.Set("Content-Type", "application/json") + client := &http.Client{Timeout: (20 * time.Second)} + resp, err := client.Do(req) + if err != nil { + return + } + + body, err = ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + return + } + + if resp.StatusCode != 200 { + err = errors.New(fmt.Sprintf("StatusCode: %d, %s", resp.StatusCode, string(body))) + return + } + + if session.Debug { + var prettyJSON bytes.Buffer + error := json.Indent(&prettyJSON, body, "", "\t") + if error != nil { + fmt.Print("JSON parse error: ", error) + return + } + fmt.Println(urlStr+" Response:\n", string(prettyJSON.Bytes())) + } + return +} + +// 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) { + + body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, "users/%s", userId)) + err = json.Unmarshal(body, &user) + + return +} + +// PrivateChannels returns an array of Channel structures for all private +// channels for a user +func PrivateChannels(session *Session, userId string) (channels []Channel, err error) { + + body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("users/%s/channels", userId))) + err = json.Unmarshal(body, &channels) + + return +} + +// Servers returns an array of Server structures for all servers for a user +func Servers(session *Session, userId string) (servers []Server, err error) { + + body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("users/%s/guilds", userId))) + err = json.Unmarshal(body, &servers) + + return +} + +// Channels returns an array of Channel structures for all channels of a given +// server. +func Channels(session *Session, serverId int) (channels []Channel, err error) { + + body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("guilds/%d/channels", serverId))) + err = json.Unmarshal(body, &channels) + + return +} + +// Close ends a session and logs out from the Discord REST API. +func Close(session *Session) (err error) { + req, err := http.NewRequest("POST", fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("auth/logout")), bytes.NewBuffer([]byte(fmt.Sprintf(``)))) + if err != nil { + return + } + req.Header.Set("authorization", session.Token) + req.Header.Set("Content-Type", "application/json") + client := &http.Client{Timeout: (20 * time.Second)} + resp, err := client.Do(req) + if err != nil { + return + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return + } + resp.Body.Close() + + if resp.StatusCode != 204 && resp.StatusCode != 200 { + err = errors.New(fmt.Sprintf("StatusCode: %d, %s", resp.StatusCode, string(body))) + return + } + return +} diff --git a/discord.go b/discord.go index 09e9588..c149501 100644 --- a/discord.go +++ b/discord.go @@ -30,7 +30,7 @@ type Discord struct { // New creates a new connection to Discord and returns a Discord structure. // This provides an easy entry where most commonly needed information is // automatically fetched. -func New(email string, password string) (discord *Discord, err error) { +func New(email string, password string) (d *Discord, err error) { session := Session{} @@ -46,7 +46,7 @@ func New(email string, password string) (discord *Discord, err error) { servers, err := session.Servers() - discord = &Discord{session, user, servers} + d = &Discord{session, user, servers} return } @@ -55,10 +55,10 @@ func New(email string, password string) (discord *Discord, err error) { // This will update all the user, server, and channel information that was // fetched with the New command. This is not an efficient way of doing this // but if used infrequently it does provide convenience. -func (discord *Discord) Renew() (err error) { +func (d *Discord) Renew() (err error) { - discord.User, err = discord.Session.Self() - discord.Servers, err = discord.Session.Servers() + d.User, err = Users(&d.Session, "@me") + d.Servers, err = Servers(&d.Session, "@me") return } diff --git a/server.go b/server.go new file mode 100644 index 0000000..b5b2e78 --- /dev/null +++ b/server.go @@ -0,0 +1,23 @@ +package discordgo + +type Server struct { + Id int `json:"id,string"` + Name string `json:"name"` + Icon string `json:"icon"` + Region string `json:"region"` + Joined_at string `json:"joined_at"` + Afk_timeout int `json:"afk_timeout"` + Afk_channel_id int `json:"afk_channel_id"` + Embed_channel_id int `json:"embed_channel_id"` + Embed_enabled bool `json:"embed_enabled"` + Owner_id int `json:"owner_id,string"` + Roles []Role `json:"roles"` + Session *Session // I got to be doing it wrong here. +} + +// Channels returns an array of Channel structures for channels within +// this Server +func (s *Server) Channels() (c []Channel, err error) { + c, err = Channels(s.Session, s.Id) + return +} diff --git a/session.go b/session.go index d5ef638..9bbe983 100644 --- a/session.go +++ b/session.go @@ -5,16 +5,6 @@ package discordgo -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "net/http" - "time" -) - // A Session represents a connection to the Discord REST API. // Token : The authentication token returned from Discord // Debug : If set to ture debug logging will be displayed. @@ -23,146 +13,32 @@ type Session struct { Debug bool } -// RequestToken asks the Discord server for an authentication token +/****************************************************************************** + * The below functions are "shortcut" methods for functions in client.go + * Reference the client.go file for more documentation. + */ func (session *Session) RequestToken(email string, password string) (token string, err error) { - - var urlStr string = fmt.Sprintf("%s/%s", discordApi, "auth/login") - req, err := http.NewRequest("POST", urlStr, bytes.NewBuffer([]byte(fmt.Sprintf(`{"email":"%s", "password":"%s"}`, email, password)))) - if err != nil { - return - } - req.Header.Set("Content-Type", "application/json") - - client := &http.Client{Timeout: (20 * time.Second)} - resp, err := client.Do(req) - if err != nil { - return - } - defer resp.Body.Close() - - body, _ := ioutil.ReadAll(resp.Body) - if resp.StatusCode != 200 { - err = errors.New(fmt.Sprintf("StatusCode: %d, %s", resp.StatusCode, string(body))) - return - } - - if session.Debug { - var prettyJSON bytes.Buffer - error := json.Indent(&prettyJSON, body, "", "\t") - if error != nil { - fmt.Print("JSON parse error: ", error) - return - } - fmt.Println("requestToken Response:\n", string(prettyJSON.Bytes())) - } - - temp := &Session{} // TODO Must be a better way - err = json.Unmarshal(body, &temp) - token = temp.Token + token, err = RequestToken(session, email, password) return } -// Self returns a User structure of the session authenticated user. func (session *Session) Self() (user User, err error) { - - body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, "users/@me")) - err = json.Unmarshal(body, &user) - + user, err = Users(session, "@me") return } -// Request makes a REST API GET Request with Discord. -func Request(session *Session, urlStr string) (body []byte, err error) { - - req, err := http.NewRequest("GET", urlStr, bytes.NewBuffer([]byte(fmt.Sprintf(``)))) - if err != nil { - return - } - - req.Header.Set("authorization", session.Token) - req.Header.Set("Content-Type", "application/json") - client := &http.Client{Timeout: (20 * time.Second)} - resp, err := client.Do(req) - if err != nil { - return - } - - body, err = ioutil.ReadAll(resp.Body) - resp.Body.Close() - if err != nil { - return - } - - if resp.StatusCode != 200 { - err = errors.New(fmt.Sprintf("StatusCode: %d, %s", resp.StatusCode, string(body))) - return - } - - if session.Debug { - var prettyJSON bytes.Buffer - error := json.Indent(&prettyJSON, body, "", "\t") - if error != nil { - fmt.Print("JSON parse error: ", error) - return - } - fmt.Println(urlStr+" Response:\n", string(prettyJSON.Bytes())) - } - return -} - -// PrivateChannels returns an array of Channel structures for all private -// channels of the session authenticated user. func (session *Session) PrivateChannels() (channels []Channel, err error) { - - body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("users/@me/channels"))) - err = json.Unmarshal(body, &channels) - + channels, err = PrivateChannels(session, "@me") return } -// Servers returns an array of Server structures for all servers for the -// session authenticated user. func (session *Session) Servers() (servers []Server, err error) { - - body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("users/@me/guilds"))) - err = json.Unmarshal(body, &servers) - - return -} - -// Channels returns an array of Channel structures for all channels of a given -// server. -func (session *Session) Channels(serverId int) (channels []Channel, err error) { - - body, err := Request(session, fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("guilds/%d/channels", serverId))) - err = json.Unmarshal(body, &channels) - + servers, err = Servers(session, "@me") return } // Close ends a session and logs out from the Discord REST API. func (session *Session) Close() (err error) { - req, err := http.NewRequest("POST", fmt.Sprintf("%s/%s", discordApi, fmt.Sprintf("auth/logout")), bytes.NewBuffer([]byte(fmt.Sprintf(``)))) - if err != nil { - return - } - req.Header.Set("authorization", session.Token) - req.Header.Set("Content-Type", "application/json") - client := &http.Client{Timeout: (20 * time.Second)} - resp, err := client.Do(req) - if err != nil { - return - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return - } - resp.Body.Close() - - if resp.StatusCode != 204 && resp.StatusCode != 200 { - err = errors.New(fmt.Sprintf("StatusCode: %d, %s", resp.StatusCode, string(body))) - return - } + err = Close(session) return } diff --git a/structs.go b/structs.go index c78b329..49c3888 100644 --- a/structs.go +++ b/structs.go @@ -9,20 +9,6 @@ type User struct { Discriminator string `json:"discriminator"` } -type Server struct { - Id int `json:"id,string"` - Name string `json:"name"` - Icon string `json:"icon"` - Region string `json:"region"` - Joined_at string `json:"joined_at"` - Afk_timeout int `json:"afk_timeout"` - Afk_channel_id int `json:"afk_channel_id"` - Embed_channel_id int `json:"embed_channel_id"` - Embed_enabled bool `json:"embed_enabled"` - Owner_id int `json:"owner_id,string"` - Roles []Role `json:"roles"` -} - type Role struct { Id int `json:"id,string"` Name string `json:"name"` @@ -33,18 +19,6 @@ type Role struct { Permissions int `json:"permissions"` } -type Channel struct { - Server_id int `json:"guild_id,string,omitempty"` - Id int `json:"id,string"` - Name string `json:"name"` - Topic string `json:"topic"` - Position int `json:"position"` - Last_message_id int `json:"last_message_id,string"` - Type string `json:"type"` - Is_private bool `json:"is_private"` - Permission_overwrites string `json:"-"` // ignored for now -} - type Message struct { Attachments []Attachment Tts bool