to packages
parent
ebbf21d23d
commit
cb42bdc8d0
|
|
@ -1,14 +1,18 @@
|
||||||
package main
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"local/args"
|
"local/args"
|
||||||
"local/storage"
|
"local/storage"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Game struct {
|
Game struct {
|
||||||
db storage.DB
|
DB storage.DB
|
||||||
}
|
}
|
||||||
Server struct {
|
Server struct {
|
||||||
Port int
|
Port int
|
||||||
|
|
@ -42,7 +46,7 @@ func NewConfig() Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
config := Config{}
|
config := Config{}
|
||||||
config.Game.db = db
|
config.Game.DB = db
|
||||||
config.Server.Port = as.GetInt("p")
|
config.Server.Port = as.GetInt("p")
|
||||||
config.Server.File.Root = as.GetString("root")
|
config.Server.File.Root = as.GetString("root")
|
||||||
config.Server.File.Prefix = "/" + strings.TrimPrefix(as.GetString("root-http-prefix"), "/")
|
config.Server.File.Prefix = "/" + strings.TrimPrefix(as.GetString("root-http-prefix"), "/")
|
||||||
|
|
@ -50,3 +54,21 @@ func NewConfig() Config {
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewTestConfig(t *testing.T) Config {
|
||||||
|
d := t.TempDir()
|
||||||
|
|
||||||
|
config := Config{}
|
||||||
|
config.Game.DB = storage.NewMap()
|
||||||
|
config.Server.Port = 9999
|
||||||
|
config.Server.File.Root = d
|
||||||
|
config.Server.File.Prefix = "/file"
|
||||||
|
config.Server.API.Prefix = "/api"
|
||||||
|
|
||||||
|
err := ioutil.WriteFile(path.Join(d, "index.html"), []byte("Hello, world"), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"local/storage"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func mockConfig(t *testing.T) Config {
|
|
||||||
d := t.TempDir()
|
|
||||||
|
|
||||||
config := Config{}
|
|
||||||
config.Game.db = storage.NewMap()
|
|
||||||
config.Server.Port = 9999
|
|
||||||
config.Server.File.Root = d
|
|
||||||
config.Server.File.Prefix = "/file"
|
|
||||||
config.Server.API.Prefix = "/api"
|
|
||||||
|
|
||||||
err := ioutil.WriteFile(path.Join(d, "index.html"), []byte("Hello, world"), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package consts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrGameExists = NewCodeError("game exists", http.StatusConflict)
|
||||||
|
)
|
||||||
|
|
||||||
|
type CodeError struct {
|
||||||
|
Err string
|
||||||
|
Status int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCodeError(err string, status int) CodeError {
|
||||||
|
return CodeError{
|
||||||
|
Err: err,
|
||||||
|
Status: status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ce CodeError) Error() string {
|
||||||
|
if ce.Err == "" {
|
||||||
|
return "unspecified error occurred"
|
||||||
|
}
|
||||||
|
return ce.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ce CodeError) Code() int {
|
||||||
|
if ce.Status == 0 {
|
||||||
|
return http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
return ce.Status
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
type Card struct {
|
||||||
|
Suit int
|
||||||
|
Value int
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
type Currency int
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
Pot Currency
|
||||||
|
Turn int
|
||||||
|
Players Players
|
||||||
|
Log string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (game Game) Equals(gameB Game) bool {
|
||||||
|
return fmt.Sprint(game) != fmt.Sprint(gameB)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
type Player struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Card Card
|
||||||
|
Balance Currency
|
||||||
|
Active bool
|
||||||
|
Participating bool
|
||||||
|
Checked bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Player) Empty() bool {
|
||||||
|
return p == (Player{})
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package entity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
type Players []Player
|
||||||
|
|
||||||
|
func (players *Players) Add(player Player) {
|
||||||
|
*players = append(*players, player)
|
||||||
|
}
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
var (
|
|
||||||
errGameExists = errors.New("cannot create game: already exists")
|
|
||||||
)
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type Players []Player
|
|
||||||
|
|
||||||
type Game struct {
|
|
||||||
Pot Currency
|
|
||||||
Turn int
|
|
||||||
Players Players
|
|
||||||
Log string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Player struct {
|
|
||||||
ID string
|
|
||||||
Name string
|
|
||||||
Card Card
|
|
||||||
Balance Currency
|
|
||||||
Active bool
|
|
||||||
Participating bool
|
|
||||||
Checked bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Currency int
|
|
||||||
|
|
||||||
type Card struct {
|
|
||||||
Suit int
|
|
||||||
Value int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (game Game) Equals(gameB Game) bool {
|
|
||||||
return fmt.Sprint(game) != fmt.Sprint(gameB)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Player) Empty() bool {
|
|
||||||
return p == (Player{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (players *Players) Add(player Player) {
|
|
||||||
*players = append(*players, player)
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/config"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/consts"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/entity"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/storage"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Master struct {
|
||||||
|
config config.Config
|
||||||
|
storage *storage.Storage
|
||||||
|
locks *storage.RWLockMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMaster(config config.Config, s *storage.Storage) *Master {
|
||||||
|
return &Master{
|
||||||
|
config: config,
|
||||||
|
storage: s,
|
||||||
|
locks: storage.NewRWLockMap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gm *Master) ListGames() ([]string, error) {
|
||||||
|
return gm.storage.ListGames()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gm *Master) GetGame(id string) (entity.Game, error) {
|
||||||
|
gm.locks.RLock(id)
|
||||||
|
defer gm.locks.RUnlock(id)
|
||||||
|
|
||||||
|
game, err := gm.storage.GetGame(id)
|
||||||
|
if game.Players == nil {
|
||||||
|
game.Players = make(entity.Players, 0)
|
||||||
|
}
|
||||||
|
return game, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gm *Master) CreateGame(id string) error {
|
||||||
|
gm.locks.Lock(id)
|
||||||
|
defer gm.locks.Unlock(id)
|
||||||
|
|
||||||
|
if _, err := gm.storage.GetGame(id); err == nil {
|
||||||
|
return consts.ErrGameExists
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm.storage.CreateGame(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gm *Master) ReplaceGame(id string, game entity.Game) error {
|
||||||
|
gm.locks.Lock(id)
|
||||||
|
defer gm.locks.Unlock(id)
|
||||||
|
|
||||||
|
if _, err := gm.storage.GetGame(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gm.storage.ReplaceGame(id, game)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTestMaster(t *testing.T) *Master {
|
||||||
|
config := config.NewTestConfig(t)
|
||||||
|
storage := storage.NewStorage(config)
|
||||||
|
return NewMaster(config, storage)
|
||||||
|
}
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
package main
|
package game
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/entity"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func mockGameMaster(t *testing.T) *GameMaster {
|
func TestMasterGetCreateGetList(t *testing.T) {
|
||||||
config := mockConfig(t)
|
gm := NewTestMaster(t)
|
||||||
storage := NewStorage(config)
|
|
||||||
return NewGameMaster(config, storage)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGameMasterGetCreateGetList(t *testing.T) {
|
|
||||||
gm := mockGameMaster(t)
|
|
||||||
id := "game"
|
id := "game"
|
||||||
|
|
||||||
if games, err := gm.ListGames(); err != nil {
|
if games, err := gm.ListGames(); err != nil {
|
||||||
|
|
@ -33,8 +30,8 @@ func TestGameMasterGetCreateGetList(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGameMasterUpdate(t *testing.T) {
|
func TestMasterUpdate(t *testing.T) {
|
||||||
gm := mockGameMaster(t)
|
gm := NewTestMaster(t)
|
||||||
id := "game"
|
id := "game"
|
||||||
|
|
||||||
err := gm.CreateGame(id)
|
err := gm.CreateGame(id)
|
||||||
|
|
@ -47,7 +44,7 @@ func TestGameMasterUpdate(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
game.Players.Add(Player{
|
game.Players.Add(entity.Player{
|
||||||
ID: "hi",
|
ID: "hi",
|
||||||
})
|
})
|
||||||
game.Pot = 123
|
game.Pot = 123
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
type GameMaster struct {
|
|
||||||
config Config
|
|
||||||
storage *Storage
|
|
||||||
locks *RWLockMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGameMaster(config Config, storage *Storage) *GameMaster {
|
|
||||||
return &GameMaster{
|
|
||||||
config: config,
|
|
||||||
storage: storage,
|
|
||||||
locks: NewRWLockMap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gm *GameMaster) ListGames() ([]string, error) {
|
|
||||||
return gm.storage.ListGames()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gm *GameMaster) GetGame(id string) (Game, error) {
|
|
||||||
gm.locks.RLock(id)
|
|
||||||
defer gm.locks.RUnlock(id)
|
|
||||||
|
|
||||||
game, err := gm.storage.GetGame(id)
|
|
||||||
if game.Players == nil {
|
|
||||||
game.Players = make(Players, 0)
|
|
||||||
}
|
|
||||||
return game, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gm *GameMaster) CreateGame(id string) error {
|
|
||||||
gm.locks.Lock(id)
|
|
||||||
defer gm.locks.Unlock(id)
|
|
||||||
|
|
||||||
if _, err := gm.storage.GetGame(id); err == nil {
|
|
||||||
return errGameExists
|
|
||||||
}
|
|
||||||
|
|
||||||
return gm.storage.CreateGame(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gm *GameMaster) ReplaceGame(id string, game Game) error {
|
|
||||||
gm.locks.Lock(id)
|
|
||||||
defer gm.locks.Unlock(id)
|
|
||||||
|
|
||||||
if _, err := gm.storage.GetGame(id); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return gm.storage.ReplaceGame(id, game)
|
|
||||||
}
|
|
||||||
|
|
@ -2,15 +2,19 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/config"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/game"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/server"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/storage"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config := NewConfig()
|
config := config.NewConfig()
|
||||||
storage := NewStorage(config)
|
storage := storage.NewStorage(config)
|
||||||
gm := NewGameMaster(config, storage)
|
gm := game.NewMaster(config, storage)
|
||||||
server := NewServer(config, gm)
|
server := server.NewServer(config, gm)
|
||||||
if err := server.Routes(); err != nil {
|
if err := server.Routes(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,156 +0,0 @@
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestServerRouter(t *testing.T) {
|
|
||||||
gm := mockGameMaster(t)
|
|
||||||
server := NewServer(gm.config, gm)
|
|
||||||
if err := server.Routes(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cases := map[string]struct {
|
|
||||||
method string
|
|
||||||
path string
|
|
||||||
}{
|
|
||||||
"file server root": {
|
|
||||||
method: http.MethodGet,
|
|
||||||
path: path.Join(server.config.Server.File.Prefix),
|
|
||||||
},
|
|
||||||
"api: games: get": {
|
|
||||||
method: http.MethodGet,
|
|
||||||
path: path.Join(server.config.Server.API.Prefix, "games"),
|
|
||||||
},
|
|
||||||
"api: games: id: get": {
|
|
||||||
method: http.MethodGet,
|
|
||||||
path: path.Join(server.config.Server.API.Prefix, "games", "my-game-id"),
|
|
||||||
},
|
|
||||||
"api: games: id: post": {
|
|
||||||
method: http.MethodPost,
|
|
||||||
path: path.Join(server.config.Server.API.Prefix, "games", "my-game-id"),
|
|
||||||
},
|
|
||||||
"api: games: id: put": {
|
|
||||||
method: http.MethodPut,
|
|
||||||
path: path.Join(server.config.Server.API.Prefix, "games", "my-game-id"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, d := range cases {
|
|
||||||
c := d
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
r := httptest.NewRequest(c.method, c.path, strings.NewReader("{}"))
|
|
||||||
server.ServeHTTP(w, r)
|
|
||||||
if w.Code == http.StatusNotFound && string(w.Body.Bytes()) == "404 page not found" {
|
|
||||||
t.Fatalf("not found: (%s) %s: (%v) %s", c.method, c.path, w.Code, w.Body.Bytes())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServerByMethod(t *testing.T) {
|
|
||||||
server := NewServer(Config{}, nil)
|
|
||||||
|
|
||||||
gotGet := false
|
|
||||||
get := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotGet = true })
|
|
||||||
gotPost := false
|
|
||||||
post := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotPost = true })
|
|
||||||
|
|
||||||
handler := server.ByMethod(map[string]http.HandlerFunc{
|
|
||||||
http.MethodGet: get,
|
|
||||||
http.MethodPost: post,
|
|
||||||
})
|
|
||||||
|
|
||||||
handler(nil, &http.Request{Method: http.MethodGet})
|
|
||||||
if !gotGet || gotPost {
|
|
||||||
t.Fatal(gotGet, gotPost)
|
|
||||||
}
|
|
||||||
gotGet = false
|
|
||||||
gotPost = false
|
|
||||||
|
|
||||||
handler(nil, &http.Request{Method: http.MethodPost})
|
|
||||||
if gotGet || !gotPost {
|
|
||||||
t.Fatal(gotGet, gotPost)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package storage
|
||||||
|
|
||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package storage
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package main
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/config"
|
||||||
|
"local/sandbox/blind-mans-poker/src/server/entity"
|
||||||
"local/storage"
|
"local/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -10,18 +12,18 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
config Config
|
config config.Config
|
||||||
db storage.DB
|
db storage.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorage(config Config) *Storage {
|
func NewStorage(config config.Config) *Storage {
|
||||||
return &Storage{
|
return &Storage{
|
||||||
config: config,
|
config: config,
|
||||||
db: config.Game.db,
|
db: config.Game.DB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage Storage) ReplaceGame(id string, game Game) error {
|
func (storage Storage) ReplaceGame(id string, game entity.Game) error {
|
||||||
b, err := json.Marshal(game)
|
b, err := json.Marshal(game)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -29,8 +31,8 @@ func (storage Storage) ReplaceGame(id string, game Game) error {
|
||||||
return storage.db.Set(id, b, nsGames)
|
return storage.db.Set(id, b, nsGames)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage Storage) GetGame(id string) (Game, error) {
|
func (storage Storage) GetGame(id string) (entity.Game, error) {
|
||||||
var game Game
|
var game entity.Game
|
||||||
|
|
||||||
b, err := storage.db.Get(id, nsGames)
|
b, err := storage.db.Get(id, nsGames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -42,7 +44,7 @@ func (storage Storage) GetGame(id string) (Game, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage Storage) CreateGame(id string) error {
|
func (storage Storage) CreateGame(id string) error {
|
||||||
b, err := json.Marshal(Game{})
|
b, err := json.Marshal(entity.Game{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue