Follow the leader with help from a server
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

250 lines
7.1KB

  1. // NGnius 2020-01-30
  2. package main
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "net/http"
  8. "net/url"
  9. "strconv"
  10. "strings"
  11. )
  12. func boardHandler(w http.ResponseWriter, r *http.Request) {
  13. w.Header().Add("Content-Type", "application/json")
  14. w.Header().Add("Access-Control-Allow-Origin", "*")
  15. if r.Method != "GET" {
  16. //w.WriteHeader(405)
  17. errorResponse(405, "Non-GET method not allowed at this endpoint", w, r)
  18. return
  19. }
  20. args := r.URL.Query()
  21. // check args pre-conditions
  22. if !checkArgExists(args, "board", w) {
  23. errorResponse(400, "Missing required 'boards' URL parameter", w, r)
  24. return
  25. }
  26. board := args.Get("board")
  27. if !checkArgExists(args, "count", w) || !checkArgInt(args, "count", w, 0) {
  28. //w.WriteHeader(400)
  29. errorResponse(400, "Missing required 'count' integer URL parameter", w, r)
  30. return
  31. }
  32. count, _ := strconv.Atoi(args.Get("count"))
  33. if !checkArgExists(args, "start", w) || !checkArgInt(args, "start", w, 0) {
  34. //w.WriteHeader(400)
  35. errorResponse(400, "Missing required 'start' integer URL parameter", w, r)
  36. return
  37. }
  38. start, _ := strconv.Atoi(args.Get("start"))
  39. // execute query
  40. result := NewResult("", r.URL.String())
  41. b, err := boardByName(board)
  42. //b, ok := boards[board]
  43. if err != nil {
  44. fmt.Println(err)
  45. //w.WriteHeader(404)
  46. errorResponse(404, "Board could not be retrieved: "+err.Error(), w, r)
  47. return
  48. }
  49. bEntries, loadErr := b.SomeEntries(int64(start), int64(start+count))
  50. if loadErr != nil {
  51. fmt.Println(loadErr)
  52. //w.WriteHeader(404)
  53. errorResponse(404, "Board entries could not be retrieved: "+loadErr.Error(), w, r)
  54. return
  55. }
  56. for _, entry := range bEntries {
  57. item, entryErr := entry.JsonObject()
  58. if entryErr != nil {
  59. fmt.Println(entryErr)
  60. }
  61. result.Items = append(result.Items, &item)
  62. }
  63. result.Query = fmt.Sprintf("load board[name: %s] from %d to %d", board, start, count+start)
  64. result.Complete()
  65. data, err := json.Marshal(result)
  66. if err != nil {
  67. //w.WriteHeader(500)
  68. errorResponse(500, "Unable to convert result into JSON: "+err.Error(), w, r)
  69. return
  70. }
  71. w.Write(data)
  72. }
  73. func playerHandler(w http.ResponseWriter, r *http.Request) {
  74. w.Header().Add("Content-Type", "application/json")
  75. w.Header().Add("Access-Control-Allow-Origin", "*")
  76. if r.Method != "GET" {
  77. //w.WriteHeader(405)
  78. errorResponse(405, "Non-GET method not allowed at this endpoint", w, r)
  79. return
  80. }
  81. args := r.URL.Query()
  82. // check args
  83. if !checkArgExists(args, "id", w) || !checkArgInt(args, "id", w, 1) {
  84. errorResponse(400, "Missing required 'id' integer URL parameter", w, r)
  85. return
  86. }
  87. id, _ := strconv.Atoi(args.Get("id"))
  88. entry_count := 0
  89. if checkArgExists(args, "entries", w) && checkArgInt(args, "entries", w, 0) {
  90. entry_count, _ = strconv.Atoi(args.Get("entries"))
  91. }
  92. // retrieve player
  93. result := NewResult("", r.URL.String())
  94. player := &Player{ID: int64(id)}
  95. loadErr := player.Load()
  96. if loadErr != nil {
  97. fmt.Println(loadErr)
  98. //w.WriteHeader(404)
  99. errorResponse(404, "Player could not be retrieved: "+loadErr.Error(), w, r)
  100. return
  101. }
  102. tempJsonObj, _ := player.JsonObject()
  103. pJsonObj := tempJsonObj.(PlayerJSON)
  104. if entry_count > 0 {
  105. entries, loadErr := player.SomeEntries(int64(entry_count))
  106. if loadErr == nil {
  107. for _, e := range entries {
  108. eJsonObj, entryErr := e.JsonObject()
  109. if entryErr != nil {
  110. fmt.Println(entryErr)
  111. }
  112. pJsonObj.Entries = append(pJsonObj.Entries, eJsonObj.(EntryJSON))
  113. }
  114. }
  115. }
  116. result.Items = []interface{}{pJsonObj}
  117. result.Query = fmt.Sprintf("load player[id: %d]", player.ID)
  118. result.Complete()
  119. data, err := json.Marshal(result)
  120. if err != nil {
  121. //w.WriteHeader(500)
  122. errorResponse(500, "Unable convert result to JSON: "+err.Error(), w, r)
  123. return
  124. }
  125. w.Write(data)
  126. }
  127. func newEntryHandler(w http.ResponseWriter, r *http.Request) {
  128. w.Header().Add("Content-Type", "application/json")
  129. w.Header().Add("Access-Control-Allow-Origin", "*")
  130. if r.Method != "POST" {
  131. //w.WriteHeader(405)
  132. errorResponse(405, "Non-POST method not allowed at this endpoint", w, r)
  133. return
  134. }
  135. // check for API token
  136. tokenHeader := r.Header.Get("Authorization")
  137. tokenSplit := strings.Split(tokenHeader, " ")
  138. if tokenHeader == "" || len(tokenSplit) != 2 || tokenSplit[1] == "" {
  139. errorResponse(401, "Missing or invalid authorization header", w, r)
  140. return
  141. }
  142. key, keyErr := keyByToken(tokenSplit[1])
  143. if keyErr != nil || key.ID == 0 {
  144. errorResponse(401, "Invalid token", w, r)
  145. return
  146. }
  147. if !key.IsEnabled() {
  148. errorResponse(403, "Invalid token", w, r)
  149. return
  150. }
  151. data, readErr := ioutil.ReadAll(r.Body)
  152. if readErr != nil {
  153. fmt.Println(readErr)
  154. //w.WriteHeader(500)
  155. errorResponse(500, "Unable to read HTTP request body: "+readErr.Error(), w, r)
  156. return
  157. }
  158. newEntry, jsonErr := UnmarshalNewEntryJSON(data)
  159. if jsonErr != nil {
  160. //w.WriteHeader(400)
  161. errorResponse(400, "Unable to convert request to JSON: "+jsonErr.Error(), w, r)
  162. return
  163. }
  164. if newEntry.PlayerID != key.Player && !key.IsMultiuser() {
  165. errorResponse(403, "Invalid authorization for player", w, r)
  166. return
  167. }
  168. sqlErr := newEntrySql(newEntry.Score, newEntry.PlayerID, newEntry.BoardID)
  169. if sqlErr != nil {
  170. fmt.Println(sqlErr)
  171. //w.WriteHeader(500)
  172. errorResponse(500, "Entry could not be created: "+sqlErr.Error(), w, r)
  173. return
  174. }
  175. //w.WriteHeader(204)
  176. errorResponse(200, "New entry created", w, r)
  177. }
  178. func newKeyHandler(w http.ResponseWriter, r *http.Request) {
  179. w.Header().Add("Content-Type", "application/json")
  180. w.Header().Add("Access-Control-Allow-Origin", "*")
  181. if r.Method != "POST" {
  182. errorResponse(405, "Non-POST method not allowed at this endpoint", w, r)
  183. return
  184. }
  185. data, readErr := ioutil.ReadAll(r.Body)
  186. if readErr != nil {
  187. fmt.Println(readErr)
  188. errorResponse(500, "Unable to read HTTP request body: "+readErr.Error(), w, r)
  189. return
  190. }
  191. result := NewResult("", r.URL.String())
  192. newKey, jsonErr := UnmarshalNewKeyJSON(data)
  193. if jsonErr != nil {
  194. errorResponse(400, "Unable to convert request to JSON: "+jsonErr.Error(), w, r)
  195. return
  196. }
  197. key, sqlErr := newKeySql(newKey.PlayerID)
  198. if sqlErr != nil {
  199. fmt.Println(sqlErr)
  200. errorResponse(500, "Key could not be created: "+sqlErr.Error(), w, r)
  201. return
  202. }
  203. jsonObj, _ := key.JsonObject()
  204. result.Items = []interface{}{jsonObj}
  205. result.Query = fmt.Sprintf("new key[player id: %d]", newKey.PlayerID)
  206. result.Complete()
  207. data, err := json.Marshal(result)
  208. if err != nil {
  209. errorResponse(500, "Unable convert result to JSON: "+err.Error(), w, r)
  210. return
  211. }
  212. w.Write(data)
  213. }
  214. func exampleHandler(w http.ResponseWriter, r *http.Request) {
  215. // useless function please ignore
  216. }
  217. // utility functions
  218. func checkArgExists(values url.Values, key string, w http.ResponseWriter) (ok bool) {
  219. ok = values.Get(key) != ""
  220. return
  221. }
  222. func checkArgInt(values url.Values, key string, w http.ResponseWriter, min int) (ok bool) {
  223. intVal, err := strconv.Atoi(values.Get(key))
  224. ok = err == nil && intVal >= min
  225. return
  226. }
  227. func errorResponse(statusCode int, reason string, w http.ResponseWriter, r *http.Request) {
  228. w.WriteHeader(statusCode)
  229. query := "error"
  230. if statusCode == 200 {
  231. query = "success"
  232. }
  233. errorRes := NewResult(query, r.URL.String())
  234. errorRes.Items = append(errorRes.Items, ErrorJSON{Reason: reason, StatusCode: statusCode})
  235. errorRes.StatusCode = statusCode
  236. data, _ := json.Marshal(errorRes)
  237. w.Write(data)
  238. }