restapi.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /******************************************************************************
  2. * A Discord API for Golang.
  3. * See discord.go for more information.
  4. *
  5. * This file contains functions for interacting with the Discord HTTP REST API
  6. * at the lowest level.
  7. */
  8. package discordgo
  9. import (
  10. "bytes"
  11. "encoding/json"
  12. "errors"
  13. "fmt"
  14. "io/ioutil"
  15. "net/http"
  16. "time"
  17. )
  18. // Constants of all known Discord API Endpoints
  19. // Please let me know if you know of any others.
  20. const (
  21. STATUS = "https://status.discordapp.com/api/v2/"
  22. SM = STATUS + "scheduled-maintenances/"
  23. SM_ACTIVE = SM + "active.json"
  24. SM_UPCOMING = SM + "upcoming.json"
  25. DISCORD = "http://discordapp.com" // TODO consider removing
  26. API = DISCORD + "/api/"
  27. GUILDS = API + "guilds/"
  28. CHANNELS = API + "channels/"
  29. USERS = API + "users/"
  30. GATEWAY = API + "gateway"
  31. AUTH = API + "auth/"
  32. LOGIN = AUTH + "login"
  33. LOGOUT = AUTH + "logout"
  34. VERIFY = AUTH + "verify"
  35. VERIFY_RESEND = AUTH + "verify/resend"
  36. FORGOT_PASSWORD = AUTH + "forgot"
  37. RESET_PASSWORD = AUTH + "reset"
  38. REGISTER = AUTH + "register"
  39. VOICE = API + "/voice/"
  40. VOICE_REGIONS = VOICE + "regions"
  41. VOICE_ICE = VOICE + "ice"
  42. TUTORIAL = API + "tutorial/"
  43. TUTORIAL_INDICATORS = TUTORIAL + "indicators"
  44. TRACK = API + "track"
  45. SSO = API + "sso"
  46. REPORT = API + "report"
  47. INTEGRATIONS = API + "integrations"
  48. )
  49. // Almost like the constants above :) Except can't be constants
  50. var (
  51. USER = func(uId string) string { return USERS + uId }
  52. USER_AVATAR = func(uId, aId string) string { return USERS + uId + "/avatars/" + aId + ".jpg" }
  53. USER_SETTINGS = func(uId string) string { return USERS + uId + "/settings" }
  54. USER_GUILDS = func(uId string) string { return USERS + uId + "/guilds" }
  55. USER_CHANNELS = func(uId string) string { return USERS + uId + "/channels" }
  56. USER_DEVICES = func(uId string) string { return USERS + uId + "/devices" }
  57. USER_CONNECTIONS = func(uId string) string { return USERS + uId + "/connections" }
  58. GUILD = func(gId string) string { return GUILDS + gId }
  59. GUILD_INIVTES = func(gId string) string { return GUILDS + gId + "/invites" }
  60. GUILD_CHANNELS = func(gId string) string { return GUILDS + gId + "/channels" }
  61. GUILD_MEMBERS = func(gId string) string { return GUILDS + gId + "/members" }
  62. GUILD_MEMBER_DEL = func(gId, uId string) string { return GUILDS + gId + "/members/" + uId }
  63. GUILD_BANS = func(gId string) string { return GUILDS + gId + "/bans" }
  64. GUILD_BAN = func(gId, uId string) string { return GUILDS + gId + "/bans/" + uId }
  65. GUILD_INTEGRATIONS = func(gId string) string { return GUILDS + gId + "/integrations" }
  66. GUILD_ROLES = func(gId string) string { return GUILDS + gId + "/roles" }
  67. GUILD_INVITES = func(gId string) string { return GUILDS + gId + "/invites" }
  68. GUILD_EMBED = func(gId string) string { return GUILDS + gId + "/embed" }
  69. GUILD_PRUNE = func(gId string) string { return GUILDS + gId + "/prune" }
  70. GUILD_ICON = func(gId, hash string) string { return GUILDS + gId + "/icons/" + hash + ".jpg" }
  71. CHANNEL = func(cId string) string { return CHANNELS + cId }
  72. CHANNEL_PERMISSIONS = func(cId string) string { return CHANNELS + cId + "/permissions" }
  73. CHANNEL_INVITES = func(cId string) string { return CHANNELS + cId + "/invites" }
  74. CHANNEL_TYPING = func(cId string) string { return CHANNELS + cId + "/typing" }
  75. CHANNEL_MESSAGES = func(cId string) string { return CHANNELS + cId + "/messages" }
  76. CHANNEL_MESSAGE = func(cId, mId string) string { return CHANNELS + cId + "/messages/" + mId }
  77. CHANNEL_MESSAGE_ACK = func(cId, mId string) string { return CHANNELS + cId + "/messages/" + mId + "/ack" }
  78. INVITE = func(iId string) string { return API + "invite/" + iId }
  79. INTEGRATIONS_JOIN = func(iId string) string { return API + "integrations/" + iId + "/join" }
  80. )
  81. // Request makes a (GET/POST/?) Requests to Discord REST API.
  82. // All the other Discord REST Calls in this file use this function.
  83. func (s *Session) Request(method, urlStr, body string) (response []byte, err error) {
  84. if s.Debug {
  85. fmt.Println("REQUEST :: " + method + " " + urlStr + "\n" + body)
  86. }
  87. req, err := http.NewRequest(method, urlStr, bytes.NewBuffer([]byte(body)))
  88. if err != nil {
  89. return
  90. }
  91. // Not used on initial login..
  92. if s.Token != "" {
  93. req.Header.Set("authorization", s.Token)
  94. }
  95. req.Header.Set("Content-Type", "application/json")
  96. client := &http.Client{Timeout: (20 * time.Second)}
  97. resp, err := client.Do(req)
  98. if err != nil {
  99. return
  100. }
  101. response, err = ioutil.ReadAll(resp.Body)
  102. if err != nil {
  103. return
  104. }
  105. resp.Body.Close()
  106. if resp.StatusCode != 204 && resp.StatusCode != 200 {
  107. err = errors.New(fmt.Sprintf("StatusCode: %d, %s", resp.StatusCode, string(response)))
  108. return
  109. }
  110. if s.Debug {
  111. printJSON(response)
  112. }
  113. return
  114. }
  115. /***************************************************************************************************
  116. * Functions specific to this session.
  117. */
  118. // Login asks the Discord server for an authentication token
  119. func (s *Session) Login(email string, password string) (token string, err error) {
  120. response, err := s.Request("POST", LOGIN, fmt.Sprintf(`{"email":"%s", "password":"%s"}`, email, password))
  121. var temp map[string]interface{}
  122. err = json.Unmarshal(response, &temp)
  123. token = temp["token"].(string)
  124. return
  125. }
  126. // Logout sends a logout request to Discord.
  127. // This does not seem to actually invalidate the token. So you can still
  128. // make API calls even after a Logout. So, it seems almost pointless to
  129. // even use.
  130. func (s *Session) Logout() (err error) {
  131. _, err = s.Request("POST", LOGOUT, fmt.Sprintf(`{"token": "%s"}`, s.Token))
  132. return
  133. }
  134. /***************************************************************************************************
  135. * Functions related to a specific user
  136. */
  137. // User returns the user details of the given userId
  138. // userId : A user Id or "@me" which is a shortcut of current user ID
  139. func (s *Session) User(userId string) (st User, err error) {
  140. body, err := s.Request("GET", USER(userId), ``)
  141. err = json.Unmarshal(body, &st)
  142. return
  143. }
  144. // UserAvatar returns a ?? of a users Avatar
  145. // userId : A user Id or "@me" which is a shortcut of current user ID
  146. func (s *Session) UserAvatar(userId string) (st User, err error) {
  147. u, err := s.User(userId)
  148. _, err = s.Request("GET", USER_AVATAR(userId, u.Avatar), ``)
  149. // TODO need to figure out how to handle returning a file
  150. return
  151. }
  152. // UserSettings returns the settings for a given user
  153. // userId : A user Id or "@me" which is a shortcut of current user ID
  154. // This seems to only return a result for "@me"
  155. func (s *Session) UserSettings(userId string) (st Settings, err error) {
  156. body, err := s.Request("GET", USER_SETTINGS(userId), ``)
  157. err = json.Unmarshal(body, &st)
  158. return
  159. }
  160. // UserChannels returns an array of Channel structures for all private
  161. // channels for a user
  162. // userId : A user Id or "@me" which is a shortcut of current user ID
  163. func (s *Session) UserChannels(userId string) (st []Channel, err error) {
  164. body, err := s.Request("GET", USER_CHANNELS(userId), ``)
  165. err = json.Unmarshal(body, &st)
  166. return
  167. }
  168. // UserChannelCreate creates a new User (Private) Channel with another User
  169. // userId : A user Id or "@me" which is a shortcut of current user ID
  170. // recipientId : A user Id for the user to which this channel is opened with.
  171. func (s *Session) UserChannelCreate(userId, recipientId string) (st []Channel, err error) {
  172. body, err := s.Request(
  173. "POST",
  174. USER_CHANNELS(userId),
  175. fmt.Sprintf(`{"recipient_id": "%s"}`, recipientId))
  176. err = json.Unmarshal(body, &st)
  177. return
  178. }
  179. // UserGuilds returns an array of Guild structures for all guilds for a given user
  180. // userId : A user Id or "@me" which is a shortcut of current user ID
  181. func (s *Session) UserGuilds(userId string) (st []Guild, err error) {
  182. body, err := s.Request("GET", USER_GUILDS(userId), ``)
  183. err = json.Unmarshal(body, &st)
  184. return
  185. }
  186. /***************************************************************************************************
  187. * Functions related to a specific guild
  188. */
  189. // Guild returns a Guild structure of a specific Guild.
  190. // guildId : The ID of a Guild
  191. func (s *Session) Guild(guildId string) (st []Guild, err error) {
  192. body, err := s.Request("GET", GUILD(guildId), ``)
  193. err = json.Unmarshal(body, &st)
  194. return
  195. }
  196. // GuildCreate creates a new Guild
  197. // name : A name for the Guild (2-100 characters)
  198. func (s *Session) GuildCreate(name string) (st []Guild, err error) {
  199. body, err := s.Request("POST", GUILDS, fmt.Sprintf(`{"name":"%s"}`, name))
  200. err = json.Unmarshal(body, &st)
  201. return
  202. }
  203. // GuildEdit edits a new Guild
  204. // guildId : The ID of a Guild
  205. // name : A name for the Guild (2-100 characters)
  206. func (s *Session) GuildEdit(guildId, name string) (st []Guild, err error) {
  207. body, err := s.Request("POST", GUILD(guildId), fmt.Sprintf(`{"name":"%s"}`, name))
  208. err = json.Unmarshal(body, &st)
  209. return
  210. }
  211. // GuildDelete deletes or leaves a Guild.
  212. // guildId : The ID of a Guild
  213. func (s *Session) GuildDelete(guildId string) (st []Guild, err error) {
  214. body, err := s.Request("DELETE", GUILD(guildId), ``)
  215. err = json.Unmarshal(body, &st)
  216. return
  217. }
  218. // GuildBans returns an array of User structures for all bans of a
  219. // given guild.
  220. // guildId : The ID of a Guild.
  221. func (s *Session) GuildBans(guildId string) (st []User, err error) {
  222. body, err := s.Request("GET", GUILD_BANS(guildId), ``)
  223. err = json.Unmarshal(body, &st)
  224. return
  225. }
  226. // GuildBanAdd bans the given user from the given guild.
  227. // guildId : The ID of a Guild.
  228. // userId : The ID of a User
  229. func (s *Session) GuildBanAdd(guildId, userId string) (err error) {
  230. _, err = s.Request("PUT", GUILD_BAN(guildId, userId), ``)
  231. return
  232. }
  233. // GuildBanDelete removes the given user from the guild bans
  234. // guildId : The ID of a Guild.
  235. // userId : The ID of a User
  236. func (s *Session) GuildBanDelete(guildId, userId string) (err error) {
  237. _, err = s.Request("DELETE", GUILD_BAN(guildId, userId), ``)
  238. return
  239. }
  240. // GuildMembers returns an array of Member structures for all members of a
  241. // given guild.
  242. // guildId : The ID of a Guild.
  243. func (s *Session) GuildMembers(guildId string) (st []Member, err error) {
  244. body, err := s.Request("GET", GUILD_MEMBERS(guildId), ``)
  245. err = json.Unmarshal(body, &st)
  246. return
  247. }
  248. // GuildMemberDelete removes the given user from the given guild.
  249. // guildId : The ID of a Guild.
  250. // userId : The ID of a User
  251. func (s *Session) GuildMemberDelete(guildId, userId string) (err error) {
  252. _, err = s.Request("DELETE", GUILD_MEMBER_DEL(guildId, userId), ``)
  253. return
  254. }
  255. // GuildChannels returns an array of Channel structures for all channels of a
  256. // given guild.
  257. // guildId : The ID of a Guild.
  258. func (s *Session) GuildChannels(guildId string) (st []Channel, err error) {
  259. body, err := s.Request("GET", GUILD_CHANNELS(guildId), ``)
  260. err = json.Unmarshal(body, &st)
  261. return
  262. }
  263. // GuildChannelCreate creates a new channel in the given guild
  264. // guildId : The ID of a Guild.
  265. // name : Name of the channel (2-100 chars length)
  266. // ctype : Tpye of the channel (voice or text)
  267. func (s *Session) GuildChannelCreate(guildId, name, ctype string) (st []Channel, err error) {
  268. body, err := s.Request("POST", GUILD_CHANNELS(guildId), fmt.Sprintf(`{"name":"%s", "type":"%s"}`, name, ctype))
  269. err = json.Unmarshal(body, &st)
  270. return
  271. }
  272. // GuildInvites returns an array of Invite structures for the given guild
  273. // guildId : The ID of a Guild.
  274. func (s *Session) GuildInvites(guildId string) (st []Invite, err error) {
  275. body, err := s.Request("GET", GUILD_INVITES(guildId), ``)
  276. err = json.Unmarshal(body, &st)
  277. return
  278. }
  279. // GuildInviteCreate creates a new invite for the given guild.
  280. // guildId : The ID of a Guild.
  281. // i : An Invite struct with the values MaxAge, MaxUses, Temporary,
  282. // and XkcdPass defined.
  283. func (s *Session) GuildInviteCreate(guildId string, i Invite) (st Invite, err error) {
  284. payload := fmt.Sprintf(
  285. `{"max_age":%d, "max_uses":%d, "temporary":%t, "xkcdpass":%t}`,
  286. i.MaxAge, i.MaxUses, i.Temporary, i.XkcdPass)
  287. body, err := s.Request("POST", GUILD_INVITES(guildId), payload)
  288. err = json.Unmarshal(body, &st)
  289. return
  290. }
  291. /***************************************************************************************************
  292. * Functions related to a specific channel
  293. */
  294. // Channel returns a Channel strucutre of a specific Channel.
  295. // channelId : The ID of the Channel you want returend.
  296. func (s *Session) Channel(channelId string) (st Channel, err error) {
  297. body, err := s.Request("GET", CHANNEL(channelId), ``)
  298. err = json.Unmarshal(body, &st)
  299. return
  300. }
  301. // ChannelEdit edits the given channel
  302. // channelId : The ID of a Channel
  303. // name : The new name to assign the channel.
  304. func (s *Session) ChannelEdit(channelId, name string) (st []Channel, err error) {
  305. body, err := s.Request("PATCH", CHANNEL(channelId), fmt.Sprintf(`{"name":"%s"}`, name))
  306. err = json.Unmarshal(body, &st)
  307. return
  308. }
  309. // ChannelDelete deletes the given channel
  310. // channelId : The ID of a Channel
  311. func (s *Session) ChannelDelete(channelId string) (st []Channel, err error) {
  312. body, err := s.Request("DELETE", CHANNEL(channelId), ``)
  313. err = json.Unmarshal(body, &st)
  314. return
  315. }
  316. // ChannelTyping broadcasts to all members that authenticated user is typing in
  317. // the given channel.
  318. // channelId : The ID of a Channel
  319. func (s *Session) ChannelTyping(channelId string) (err error) {
  320. _, err = s.Request("POST", CHANNEL_TYPING(channelId), ``)
  321. return
  322. }
  323. // ChannelMessages returns an array of Message structures for messaages within
  324. // a given channel.
  325. // channelId : The ID of a Channel.
  326. // limit : The number messages that can be returned.
  327. // beforeId : If provided all messages returned will be before given ID.
  328. // afterId : If provided all messages returned will be after given ID.
  329. func (s *Session) ChannelMessages(channelId string, limit int, beforeId int, afterId int) (st []Message, err error) {
  330. var urlStr string = ""
  331. if limit > 0 {
  332. urlStr = fmt.Sprintf("?limit=%d", limit)
  333. }
  334. if afterId > 0 {
  335. if urlStr != "" {
  336. urlStr = urlStr + fmt.Sprintf("&after=%d", afterId)
  337. } else {
  338. urlStr = fmt.Sprintf("?after=%d", afterId)
  339. }
  340. }
  341. if beforeId > 0 {
  342. if urlStr != "" {
  343. urlStr = urlStr + fmt.Sprintf("&before=%d", beforeId)
  344. } else {
  345. urlStr = fmt.Sprintf("?before=%d", beforeId)
  346. }
  347. }
  348. body, err := s.Request("GET", CHANNEL_MESSAGES(channelId)+urlStr, ``)
  349. err = json.Unmarshal(body, &st)
  350. return
  351. }
  352. // ChannelMessageAck acknowledges and marks the given message as read
  353. // channeld : The ID of a Channel
  354. // messageId : the ID of a Message
  355. func (s *Session) ChannelMessageAck(channelId, messageId string) (err error) {
  356. _, err = s.Request("POST", CHANNEL_MESSAGE_ACK(channelId, messageId), ``)
  357. return
  358. }
  359. // ChannelMessageSend sends a message to the given channel.
  360. // channelId : The ID of a Channel.
  361. // content : The message to send.
  362. func (s *Session) ChannelMessageSend(channelId string, content string) (st Message, err error) {
  363. response, err := s.Request("POST", CHANNEL_MESSAGES(channelId), fmt.Sprintf(`{"content":"%s"}`, content))
  364. err = json.Unmarshal(response, &st)
  365. return
  366. }
  367. // ChannelMessageEdit edits an existing message, replacing it entirely with
  368. // the given content.
  369. // channeld : The ID of a Channel
  370. // messageId : the ID of a Message
  371. func (s *Session) ChannelMessageEdit(channelId, messageId, content string) (st Message, err error) {
  372. response, err := s.Request("PATCH", CHANNEL_MESSAGE(channelId, messageId), fmt.Sprintf(`{"content":"%s"}`, content))
  373. err = json.Unmarshal(response, &st)
  374. return
  375. }
  376. // ChannelMessageDelete deletes a message from the Channel.
  377. func (s *Session) ChannelMessageDelete(channelId, messageId string) (err error) {
  378. _, err = s.Request("DELETE", CHANNEL_MESSAGE(channelId, messageId), ``)
  379. return
  380. }
  381. // ChannelInvites returns an array of Invite structures for the given channel
  382. // channelId : The ID of a Channel
  383. func (s *Session) ChannelInvites(channelId string) (st []Invite, err error) {
  384. body, err := s.Request("GET", CHANNEL_INVITES(channelId), ``)
  385. err = json.Unmarshal(body, &st)
  386. return
  387. }
  388. // ChannelInviteCreate creates a new invite for the given channel.
  389. // channelId : The ID of a Channel
  390. // i : An Invite struct with the values MaxAge, MaxUses, Temporary,
  391. // and XkcdPass defined.
  392. func (s *Session) ChannelInviteCreate(channelId string, i Invite) (st Invite, err error) {
  393. payload := fmt.Sprintf(
  394. `{"max_age":%d, "max_uses":%d, "temporary":%t, "xkcdpass":%t}`,
  395. i.MaxAge, i.MaxUses, i.Temporary, i.XkcdPass)
  396. body, err := s.Request("POST", CHANNEL_INVITES(channelId), payload)
  397. err = json.Unmarshal(body, &st)
  398. return
  399. }
  400. /***************************************************************************************************
  401. * Functions related to an invite
  402. */
  403. // Inivte returns an Invite structure of the given invite
  404. // inviteId : The invite code (or maybe xkcdpass?)
  405. func (s *Session) Invite(inviteId string) (st Invite, err error) {
  406. body, err := s.Request("GET", INVITE(inviteId), ``)
  407. err = json.Unmarshal(body, &st)
  408. return
  409. }
  410. // InviteDelete deletes an existing invite
  411. // inviteId : the code (or maybe xkcdpass?) of an invite
  412. func (s *Session) InviteDelete(inviteId string) (st Invite, err error) {
  413. body, err := s.Request("DELETE", INVITE(inviteId), ``)
  414. err = json.Unmarshal(body, &st)
  415. return
  416. }
  417. // InivteAccept accepts an Invite to a Guild or Channel
  418. // inviteId : The invite code (or maybe xkcdpass?)
  419. func (s *Session) InviteAccept(inviteId string) (st Invite, err error) {
  420. body, err := s.Request("POST", INVITE(inviteId), ``)
  421. err = json.Unmarshal(body, &st)
  422. return
  423. }
  424. // https://discordapi.readthedocs.org/en/latest/reference/guilds/invites.html#get-and-accept-invite
  425. func (s *Session) InviteValidate(validateId string) (i Invite, err error) {
  426. return
  427. }
  428. /***************************************************************************************************
  429. * Functions related to Voice/Audio
  430. */
  431. // VoiceRegions returns the voice server regions
  432. func (s *Session) VoiceRegions() (st []VoiceRegion, err error) {
  433. body, err := s.Request("GET", VOICE_REGIONS, ``)
  434. err = json.Unmarshal(body, &st)
  435. return
  436. }
  437. // VoiceIce returns the voice server ICE information
  438. func (s *Session) VoiceIce() (st VoiceIce, err error) {
  439. body, err := s.Request("GET", VOICE_ICE, ``)
  440. err = json.Unmarshal(body, &st)
  441. return
  442. }
  443. /***************************************************************************************************
  444. * Functions related to Websockets
  445. */
  446. // Gateway returns the a websocket Gateway address
  447. func (s *Session) Gateway() (gateway string, err error) {
  448. response, err := s.Request("GET", GATEWAY, ``)
  449. var temp map[string]interface{}
  450. err = json.Unmarshal(response, &temp)
  451. gateway = temp["url"].(string)
  452. return
  453. }