package main import ( "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, bw *bandwidth.Bandwidth) *protoTalker { return &protoTalker{ send: make(chan Message, 16), ws: ws, bw: bw, Id: id, buff: make([]byte, maxMessageSize), } } func (pt *protoTalker) sender() { log.Printf("%s: client launched", pt.Id) for things := range pt.send { b, err := json.Marshal(things) if err != nil { break } n, err := pt.ws.Write(b) pt.bw.AddTx <- n if err != nil { break } } pt.ws.Close() log.Printf("%s: spectator sender close", pt.Id) } func (pt *protoTalker) readJSON(buff []byte) (map[string]Instruction, error) { msg := map[string]Instruction{} n, err := pt.ws.Read(buff) if err != nil { log.Printf("%s: problem reading from player: %s", pt.Id, err) return nil, err } pt.bw.AddRx <- n if n == len(buff) { errMsg := fmt.Sprintf("%s: read buffer overfull: %s", pt.Id, string(buff)) log.Printf(errMsg) return msg, errors.New(errMsg) } err = json.Unmarshal(buff[:n], &msg) if err != nil { log.Printf("%s: problem reading from player: %s", pt.Id, err) return nil, err } return msg, nil } type player struct { Robots []*Robot Instruction Instruction protoTalker } func NewPlayer(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *player { return &player{ Robots: []*Robot{}, protoTalker: *NewProtoTalker(id, ws, bw), } } func (p *player) recv() { for { msgs, err := p.readJSON(p.buff) if err != nil { log.Printf("%s: %s", p.Id, err) break } for _, r := range p.Robots { msg, ok := msgs[r.Id] if !ok { continue } if msg.Repair != nil && *msg.Repair == true { r.ActiveScan = false r.TargetSpeed = 0 r.FireAt = nil r.MoveTo = nil if r.RepairCounter <= 0 { r.RepairCounter = 3.0 } } else if msg.Scan != nil && *msg.Scan == true { r.RepairCounter = 0 r.TargetSpeed = 0 r.FireAt = nil r.MoveTo = nil r.ActiveScan = true } else { r.RepairCounter = 0 r.ActiveScan = false // Reapiring halts all other activity if msg.MoveTo != nil { r.MoveTo = msg.MoveTo } if msg.Heading != nil { r.DesiredHeading = msg.Heading } if msg.FireAt != nil { r.FireAt = msg.FireAt } else { r.FireAt = nil } if msg.TargetSpeed != nil { r.TargetSpeed = float32(*msg.TargetSpeed) } else { r.TargetSpeed = r.Stats.Speed } } if msg.Probe != nil { r.Probe = msg.Probe r.ProbeResult = nil } else { r.Probe = nil } if msg.Message != nil { r.Message = *msg.Message } } } log.Printf("%s: recv close", p.Id) p.ws.Close() } type Spectator struct { protoTalker } func NewSpectator(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *Spectator { return &Spectator{ protoTalker: *NewProtoTalker(id, ws, bw), } } func (s *Spectator) recv() { for { _, err := s.readJSON(s.buff) if err != nil { log.Printf("%s: %s", s.Id, err) break } // After the first bit of handshaking, the rest of the messages should // only be "{}" for spectators, and the following could hold true: // // if string(buff[:n]) != "{}" { // log.Printf("protocol breach!!") // break // } } log.Printf("%s: recv close", s.Id) s.ws.Close() }