From 6fd4138740f80e42f8120f847a259dfcfa4d9b6a Mon Sep 17 00:00:00 2001 From: Stephen McQuay Date: Mon, 3 Mar 2014 21:57:39 -0800 Subject: [PATCH] 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. --- control.go | 35 ++++++++++++++++++++++++++++++++++- game.go | 18 ++++++++++++++++-- main.go | 1 + player.go | 22 +++++++++++++--------- protocol.go | 12 +++++++++--- 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/control.go b/control.go index 316e7bd..2557650 100644 --- a/control.go +++ b/control.go @@ -57,7 +57,13 @@ func startGame(w http.ResponseWriter, req *http.Request) { g := games.get(requested_game_name) if g == nil { log.Printf("Game '%s' non-existant; making it now", requested_game_name) - g = NewGame(requested_game_name, width, height, obstacles, conf.Tick, maxPoints, mode) + 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 { @@ -136,6 +142,33 @@ func gameStats(w http.ResponseWriter, req *http.Request) { } } +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 { diff --git a/game.go b/game.go index 3457914..96d040d 100644 --- a/game.go +++ b/game.go @@ -7,6 +7,8 @@ import ( "sort" "sync" "time" + + "bitbucket.org/smcquay/bandwidth" ) const maxPlayer = 128 @@ -84,6 +86,7 @@ type game struct { tick_duration int stats GameStats mode GameMode + bw *bandwidth.Bandwidth } type GameMode interface { @@ -92,7 +95,16 @@ type GameMode interface { gameOver(gg *game) (bool, *GameOver) } -func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, mode string) *game { +func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, mode string) (*game, error) { + bw, err := bandwidth.NewBandwidth( + []int{1, 10, 60}, + time.Duration(500)*time.Millisecond, + ) + if err != nil { + log.Fatal("seriously, what the fuck") + return nil, err + } + go bw.Run() g := &game{ id: id, register: make(chan *player, maxPlayer), @@ -115,6 +127,7 @@ func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, m tick_duration: tick, players_remaining: 2, stats: GameStats{PlayerStats: make(map[string]*PlayerStats)}, + bw: bw, } if mode == "melee" { @@ -125,7 +138,7 @@ func NewGame(id string, width, height float32, obstacles, tick, maxPoints int, m g.mode.setup(g) - return g + return g, nil } func (g *game) tick(payload *Boardstate) { @@ -286,6 +299,7 @@ func (g *game) run() { select { case <-g.kill: log.Printf("game %s: received kill signal, dying gracefully", g.id) + close(g.bw.Quit) games.Lock() for player := range g.players { close(player.send) diff --git a/main.go b/main.go index 1a5ce9c..ac2b931 100644 --- a/main.go +++ b/main.go @@ -64,6 +64,7 @@ func main() { sm.Handle("/game/start/", JsonHandler(startGame)) sm.Handle("/game/list/", JsonHandler(listGames)) sm.Handle("/game/stats/", JsonHandler(gameStats)) + sm.Handle("/game/bw/", JsonHandler(bw)) sm.Handle("/game/stop/", JsonHandler(stopGame)) sm.HandleFunc("/fuck/shit/up/", killServer) diff --git a/player.go b/player.go index 13f86de..ac6e211 100644 --- a/player.go +++ b/player.go @@ -1,26 +1,30 @@ package main import ( - "code.google.com/p/go.net/websocket" "encoding/json" "errors" "fmt" "log" + + "bitbucket.org/smcquay/bandwidth" + "code.google.com/p/go.net/websocket" ) const maxMessageSize = 1024 type protoTalker struct { ws *websocket.Conn + bw *bandwidth.Bandwidth send chan Message buff []byte Id string } -func NewProtoTalker(id string, ws *websocket.Conn) *protoTalker { +func NewProtoTalker(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *protoTalker { return &protoTalker{ send: make(chan Message, 16), ws: ws, + bw: bw, Id: id, buff: make([]byte, maxMessageSize), } @@ -33,8 +37,8 @@ func (pt *protoTalker) sender() { if err != nil { break } - // XXX: send the count to our bandwidth analyzer ... - _, err = pt.ws.Write(b) + n, err := pt.ws.Write(b) + pt.bw.AddTx <- n if err != nil { break } @@ -50,7 +54,7 @@ func (pt *protoTalker) readJSON(buff []byte) (map[string]Instruction, error) { log.Printf("%s: problem reading from player: %s", pt.Id, err) return nil, err } - // XXX: send n to our bandwidth analyzer ... + pt.bw.AddRx <- n if n == len(buff) { errMsg := fmt.Sprintf("%s: read buffer overfull: %s", pt.Id, string(buff)) log.Printf(errMsg) @@ -70,10 +74,10 @@ type player struct { protoTalker } -func NewPlayer(id string, ws *websocket.Conn) *player { +func NewPlayer(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *player { return &player{ Robots: []*Robot{}, - protoTalker: *NewProtoTalker(id, ws), + protoTalker: *NewProtoTalker(id, ws, bw), } } @@ -152,9 +156,9 @@ type Spectator struct { protoTalker } -func NewSpectator(id string, ws *websocket.Conn) *Spectator { +func NewSpectator(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *Spectator { return &Spectator{ - protoTalker: *NewProtoTalker(id, ws), + protoTalker: *NewProtoTalker(id, ws, bw), } } diff --git a/protocol.go b/protocol.go index 1124145..4ef49e9 100644 --- a/protocol.go +++ b/protocol.go @@ -153,7 +153,8 @@ func addPlayer(ws *websocket.Conn) { game := games.get(gid.Id) if game == nil { - game = NewGame( + var err error + game, err = NewGame( gid.Id, float32(conf.Width), float32(conf.Height), @@ -162,6 +163,11 @@ func addPlayer(ws *websocket.Conn) { conf.MaxPoints, "", ) + if err != nil { + log.Printf("problem creating game: %s", gid.Id) + websocket.JSON.Send(ws, NewFailure("game creation error")) + return + } go game.run() games.add(game) } @@ -230,7 +236,7 @@ func addPlayer(ws *websocket.Conn) { } } - p := NewPlayer(player_id, ws) + p := NewPlayer(player_id, ws, game.bw) log.Printf("%s: made a player: %s", gid.Id, p.Id) convertedStats := map[string]Stats{} @@ -285,7 +291,7 @@ func addPlayer(ws *websocket.Conn) { gid.Id, ) case "spectator": - s := NewSpectator(player_id, ws) + s := NewSpectator(player_id, ws, game.bw) log.Printf("%s, %s: about to register this spectator", gid.Id, s.Id) game.sregister <- s log.Printf("%s, %s: registered spectator", gid.Id, s.Id)