server/control.go
Stephen McQuay 6fd4138740 added bw calcs
unfortunately there is an issue with how these are calculated, and they don't
decrease as things quiet down. Well, the bad numbers are their for your
consumption, and should Just Work TM when appropriate changes in
bitbucket.org/smcquay/bandwith land. And they will. But I'm tired now.
2014-03-03 22:56:26 -08:00

232 lines
5.7 KiB
Go

package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"runtime/pprof"
"strings"
)
type JsonHandler func(http.ResponseWriter, *http.Request)
func (h JsonHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
h(w, req)
}
func startGame(w http.ResponseWriter, req *http.Request) {
log.Println("asked to create a game")
requested_game_name := idg.Hash()
width, height := float32(conf.Width), float32(conf.Height)
obstacles := 0
maxPoints := conf.MaxPoints
mode := "deathmatch"
// here we determine if we are going to run with defaults or pick them off
// a posted json blob
if req.Method == "POST" {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
log.Printf("unable to read request body:", err)
}
req.Body.Close()
cfg := struct {
Name string `json:"name"`
Config
}{}
err = json.Unmarshal(body, &cfg)
if err != nil {
if err := json.NewEncoder(w).Encode(NewFailure(err.Error())); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
requested_game_name = cfg.Name
width = float32(cfg.Width)
height = float32(cfg.Height)
obstacles = cfg.Obstacles
maxPoints = cfg.MaxPoints
mode = cfg.Mode
}
g := games.get(requested_game_name)
if g == nil {
log.Printf("Game '%s' non-existant; making it now", requested_game_name)
g, err := NewGame(requested_game_name, width, height, obstacles, conf.Tick, maxPoints, mode)
if err != nil {
log.Printf("problem creating game: %s: %s", requested_game_name, err)
b, _ := json.Marshal(NewFailure("game creation failure"))
http.Error(w, string(b), http.StatusConflict)
return
}
go g.run()
games.add(g)
} else {
log.Printf("Game '%s' already exists: %p", requested_game_name, g)
b, _ := json.Marshal(NewFailure("game already exists"))
http.Error(w, string(b), http.StatusConflict)
return
}
game_json := struct {
Id string `json:"id"`
}{
Id: g.id,
}
if err := json.NewEncoder(w).Encode(game_json); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func listGames(w http.ResponseWriter, req *http.Request) {
log.Println("games list requested")
games.RLock()
defer games.RUnlock()
type pout struct {
Name string `json:"name"`
Id string `json:"id"`
}
type gl struct {
Id string `json:"id"`
Players []pout `json:"players"`
}
ids := make([]gl, 0)
for id, g := range games.m {
players := make([]pout, 0)
// TODO - players instead of robots?
for p := range g.players {
for _, r := range p.Robots {
players = append(players, pout{
Name: r.Name,
Id: r.Id,
})
}
}
ids = append(ids, gl{
Id: id,
Players: players,
})
}
if err := json.NewEncoder(w).Encode(ids); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func gameStats(w http.ResponseWriter, req *http.Request) {
// TODO: wrap this up in something similar to the JsonHandler to verify the
// url? Look at gorilla routing?
key, err := getGameId(req.URL.Path)
if err != nil {
b, _ := json.Marshal(NewFailure(err.Error()))
http.Error(w, string(b), http.StatusBadRequest)
return
}
log.Printf("requested stats for game: %s", key)
games.RLock()
g, ok := games.m[key]
games.RUnlock()
if !ok {
b, _ := json.Marshal(NewFailure("game not found"))
http.Error(w, string(b), http.StatusNotFound)
return
}
g.stats.RLock()
defer g.stats.RUnlock()
if err := json.NewEncoder(w).Encode(g.stats.PlayerStats); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func bw(w http.ResponseWriter, req *http.Request) {
// TODO: wrap this up in something similar to the JsonHandler to verify the
// url? Look at gorilla routing?
key, err := getGameId(req.URL.Path)
if err != nil {
b, _ := json.Marshal(NewFailure(err.Error()))
http.Error(w, string(b), http.StatusBadRequest)
return
}
log.Printf("requested bandwidth for game: %s", key)
games.RLock()
g, ok := games.m[key]
games.RUnlock()
if !ok {
b, _ := json.Marshal(NewFailure("game not found"))
http.Error(w, string(b), http.StatusNotFound)
return
}
s := map[string][]float64{
"tx": <-g.bw.Tx,
"rx": <-g.bw.Rx,
}
if err := json.NewEncoder(w).Encode(s); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func stopGame(w http.ResponseWriter, req *http.Request) {
key, err := getGameId(req.URL.Path)
if err != nil {
b, _ := json.Marshal(NewFailure(err.Error()))
http.Error(w, string(b), http.StatusBadRequest)
return
}
games.Lock()
g, ok := games.m[key]
defer games.Unlock()
if !ok {
http.NotFound(w, req)
return
}
g.kill <- true
message := struct {
Ok bool `json:"ok"`
Message string `json:"message"`
}{
Ok: true,
Message: fmt.Sprintf("Successfully stopped game: %s", key),
}
if err := json.NewEncoder(w).Encode(message); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func killServer(w http.ResponseWriter, req *http.Request) {
if *profile != "" {
log.Print("trying to stop cpu profile")
pprof.StopCPUProfile()
log.Print("stopped cpu profile")
}
log.Fatal("shit got fucked up")
}
func index(w http.ResponseWriter, req *http.Request) {
log.Println("version requested")
version := struct {
Version string `json:"version"`
Name string `json:"name"`
}{
Version: "0.1.2",
Name: "Hackerbots",
}
if err := json.NewEncoder(w).Encode(version); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func getGameId(path string) (string, error) {
var err error
trimmed := strings.Trim(path, "/")
fullPath := strings.Split(trimmed, "/")
if len(fullPath) != 3 {
return "", errors.New("improperly formed url")
}
key := fullPath[2]
return key, err
}