Added io.Reader and io.Writer wrapper
This finalizes the work on getting the server to support multiple encodings for players and spectators.
This commit is contained in:
parent
e6c7abc969
commit
9a4b76f610
106
player.go
106
player.go
@ -1,9 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"bitbucket.org/smcquay/bandwidth"
|
"bitbucket.org/smcquay/bandwidth"
|
||||||
@ -12,78 +11,95 @@ import (
|
|||||||
|
|
||||||
const maxMessageSize = 1024
|
const maxMessageSize = 1024
|
||||||
|
|
||||||
type protoTalker struct {
|
type encoder interface {
|
||||||
|
Encode(v interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type decoder interface {
|
||||||
|
Decode(v interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type streamCounter struct {
|
||||||
ws *websocket.Conn
|
ws *websocket.Conn
|
||||||
bw *bandwidth.Bandwidth
|
bw *bandwidth.Bandwidth
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *streamCounter) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = sc.ws.Read(p)
|
||||||
|
sc.bw.AddRx <- n
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *streamCounter) Write(p []byte) (n int, err error) {
|
||||||
|
n, err = sc.ws.Write(p)
|
||||||
|
sc.bw.AddTx <- n
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *streamCounter) Close() error {
|
||||||
|
return sc.ws.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
type protoTalker struct {
|
||||||
|
enc encoder
|
||||||
|
dec decoder
|
||||||
|
counter *streamCounter
|
||||||
send chan Message
|
send chan Message
|
||||||
buff []byte
|
|
||||||
Id string
|
Id string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProtoTalker(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *protoTalker {
|
func NewProtoTalker(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth, encoding string) *protoTalker {
|
||||||
return &protoTalker{
|
var enc encoder
|
||||||
send: make(chan Message, 16),
|
var dec decoder
|
||||||
|
comptroller := &streamCounter{
|
||||||
ws: ws,
|
ws: ws,
|
||||||
bw: bw,
|
bw: bw,
|
||||||
|
}
|
||||||
|
if encoding == "json" {
|
||||||
|
enc = json.NewEncoder(comptroller)
|
||||||
|
dec = json.NewDecoder(comptroller)
|
||||||
|
} else {
|
||||||
|
enc = gob.NewEncoder(comptroller)
|
||||||
|
dec = gob.NewDecoder(comptroller)
|
||||||
|
}
|
||||||
|
return &protoTalker{
|
||||||
|
send: make(chan Message, 16),
|
||||||
|
enc: enc,
|
||||||
|
dec: dec,
|
||||||
|
counter: comptroller,
|
||||||
Id: id,
|
Id: id,
|
||||||
buff: make([]byte, maxMessageSize),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *protoTalker) sender() {
|
func (pt *protoTalker) sender() {
|
||||||
log.Printf("%s: client launched", pt.Id)
|
log.Printf("%s: client launched", pt.Id)
|
||||||
for things := range pt.send {
|
for things := range pt.send {
|
||||||
b, err := json.Marshal(things)
|
err := pt.enc.Encode(things)
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
n, err := pt.ws.Write(b)
|
|
||||||
pt.bw.AddTx <- n
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pt.ws.Close()
|
pt.counter.Close()
|
||||||
log.Printf("%s: spectator sender close", pt.Id)
|
log.Printf("%s: spectator sender close", pt.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *protoTalker) readJSON() (map[string]Instruction, error) {
|
|
||||||
msg := map[string]Instruction{}
|
|
||||||
n, err := pt.ws.Read(pt.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(pt.buff) {
|
|
||||||
errMsg := fmt.Sprintf("%s: read buffer overfull: %s", pt.Id, string(pt.buff))
|
|
||||||
log.Printf(errMsg)
|
|
||||||
return msg, errors.New(errMsg)
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(pt.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 {
|
type player struct {
|
||||||
Robots []*Robot
|
Robots []*Robot
|
||||||
Instruction Instruction
|
Instruction Instruction
|
||||||
protoTalker
|
protoTalker
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPlayer(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *player {
|
func NewPlayer(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth, encoding string) *player {
|
||||||
return &player{
|
return &player{
|
||||||
Robots: []*Robot{},
|
Robots: []*Robot{},
|
||||||
protoTalker: *NewProtoTalker(id, ws, bw),
|
protoTalker: *NewProtoTalker(id, ws, bw, encoding),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *player) recv() {
|
func (p *player) recv() {
|
||||||
for {
|
for {
|
||||||
msgs, err := p.readJSON()
|
var msgs map[string]Instruction
|
||||||
|
err := p.dec.Decode(&msgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s: %s", p.Id, err)
|
log.Printf("%s: %s", p.Id, err)
|
||||||
break
|
break
|
||||||
@ -149,26 +165,28 @@ func (p *player) recv() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("%s: recv close", p.Id)
|
log.Printf("%s: recv close", p.Id)
|
||||||
p.ws.Close()
|
p.counter.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type Spectator struct {
|
type Spectator struct {
|
||||||
protoTalker
|
protoTalker
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSpectator(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth) *Spectator {
|
func NewSpectator(id string, ws *websocket.Conn, bw *bandwidth.Bandwidth, encoding string) *Spectator {
|
||||||
return &Spectator{
|
return &Spectator{
|
||||||
protoTalker: *NewProtoTalker(id, ws, bw),
|
protoTalker: *NewProtoTalker(id, ws, bw, encoding),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Spectator) recv() {
|
func (s *Spectator) recv() {
|
||||||
for {
|
for {
|
||||||
_, err := s.readJSON()
|
var msgs interface{}
|
||||||
|
err := s.dec.Decode(&msgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s: %s", s.Id, err)
|
log.Printf("%s: %s", s.Id, err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// After the first bit of handshaking, the rest of the messages should
|
// After the first bit of handshaking, the rest of the messages should
|
||||||
// only be "{}" for spectators, and the following could hold true:
|
// only be "{}" for spectators, and the following could hold true:
|
||||||
//
|
//
|
||||||
@ -178,5 +196,5 @@ func (s *Spectator) recv() {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
log.Printf("%s: recv close", s.Id)
|
log.Printf("%s: recv close", s.Id)
|
||||||
s.ws.Close()
|
s.counter.Close()
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ encodingLoops:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p := NewPlayer(player_id, ws, game.bw)
|
p := NewPlayer(player_id, ws, game.bw, encoding)
|
||||||
log.Printf("%s: made a player: %s", gid.Id, p.Id)
|
log.Printf("%s: made a player: %s", gid.Id, p.Id)
|
||||||
|
|
||||||
convertedStats := map[string]Stats{}
|
convertedStats := map[string]Stats{}
|
||||||
@ -330,7 +330,7 @@ encodingLoops:
|
|||||||
gid.Id,
|
gid.Id,
|
||||||
)
|
)
|
||||||
case "spectator":
|
case "spectator":
|
||||||
s := NewSpectator(player_id, ws, game.bw)
|
s := NewSpectator(player_id, ws, game.bw, encoding)
|
||||||
log.Printf("%s, %s: about to register this spectator", gid.Id, s.Id)
|
log.Printf("%s, %s: about to register this spectator", gid.Id, s.Id)
|
||||||
game.sregister <- s
|
game.sregister <- s
|
||||||
log.Printf("%s, %s: registered spectator", gid.Id, s.Id)
|
log.Printf("%s, %s: registered spectator", gid.Id, s.Id)
|
||||||
|
Loading…
Reference in New Issue
Block a user