Follow the leader with help from a server
You can not select more than 25 topics 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.

258 lines
7.2KB

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