cards/src/server/server.go

157 lines
3.6 KiB
Go

package main
import (
"encoding/json"
"fmt"
"local/router"
"local/storage"
"log"
"net/http"
"strings"
)
type Server struct {
config Config
gm *GameMaster
*router.Router
}
func NewServer(config Config, gm *GameMaster) *Server {
return &Server{
config: config,
gm: gm,
Router: router.New(),
}
}
func (server *Server) Routes() error {
cases := map[string]map[string]http.HandlerFunc{
fmt.Sprintf("%s/%s%s", server.config.Server.File.Prefix, router.Wildcard, router.Wildcard): map[string]http.HandlerFunc{
http.MethodGet: server.File,
},
fmt.Sprintf("%s/games", server.config.Server.API.Prefix): map[string]http.HandlerFunc{
http.MethodGet: server.GameList,
},
fmt.Sprintf("%s/games/%s", server.config.Server.API.Prefix, router.Wildcard): map[string]http.HandlerFunc{
http.MethodGet: server.GameGet,
http.MethodPost: server.GameInsert,
http.MethodPut: server.GameReplace,
},
}
for path, spec := range cases {
log.Println("listening for:", path)
handler := server.ByMethod(spec)
if err := server.Add(path, handler); err != nil {
return err
}
}
return nil
}
func (server *Server) ByMethod(m map[string]http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
foo, ok := m[r.Method]
if ok {
foo(w, r)
} else {
http.NotFound(w, r)
}
})
}
func (server *Server) File(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.NotFound(w, r)
return
}
s := http.FileServer(http.Dir(server.config.Server.File.Root))
r.URL.Path = strings.TrimPrefix(r.URL.Path, server.config.Server.File.Prefix)
s.ServeHTTP(w, r)
}
func (server *Server) GameList(w http.ResponseWriter, r *http.Request) {
resp, err := server.gm.ListGames()
if err != nil {
internalError(w, err.Error())
return
}
json.NewEncoder(w).Encode(resp)
}
func (server *Server) GameGet(w http.ResponseWriter, r *http.Request) {
var gameID string
err := router.Params(r, &gameID)
if err != nil {
badRequest(w, err.Error())
return
}
resp, err := server.gm.GetGame(gameID)
if err != nil {
internalError(w, err.Error())
return
}
json.NewEncoder(w).Encode(resp)
}
func (server *Server) GameReplace(w http.ResponseWriter, r *http.Request) {
var gameID string
err := router.Params(r, &gameID)
if err != nil {
badRequest(w, err.Error())
return
}
var game Game
err = json.NewDecoder(r.Body).Decode(&game)
if err != nil {
badRequest(w, err.Error())
return
}
err = server.gm.ReplaceGame(gameID, game)
if err != nil {
internalError(w, err.Error())
return
}
json.NewEncoder(w).Encode(game)
}
func (server *Server) GameInsert(w http.ResponseWriter, r *http.Request) {
var gameID string
err := router.Params(r, &gameID)
if err != nil {
badRequest(w, err.Error())
return
}
err = server.gm.CreateGame(gameID)
if err != nil {
internalError(w, err.Error())
return
}
json.NewEncoder(w).Encode(Game{})
}
func notImpl(w http.ResponseWriter) {
errHandler(w, http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func internalError(w http.ResponseWriter, message string) {
errHandler(w, http.StatusInternalServerError, message)
}
func badRequest(w http.ResponseWriter, message string) {
errHandler(w, http.StatusBadRequest, message)
}
func errHandler(w http.ResponseWriter, status int, message string) {
if message == storage.ErrNotFound.Error() {
status = http.StatusNotFound
}
w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]interface{}{
"status": http.StatusText(status),
"statusCode": status,
"error": message,
})
}