prep code for reuse
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
package botclient
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"bitbucket.org/hackerbots/botserv"
|
||||
"code.google.com/p/go.net/websocket"
|
||||
)
|
||||
|
||||
func connect(server string, port int) (*websocket.Conn, error) {
|
||||
origin := "http://localhost/"
|
||||
url := fmt.Sprintf("ws://%s:%d/ws/", server, port)
|
||||
return websocket.Dial(url, "", origin)
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
ForceJSON bool
|
||||
GameId string
|
||||
Name string
|
||||
Port int
|
||||
Server string
|
||||
StatsReq botserv.StatsRequest
|
||||
Verbose bool
|
||||
Player Player
|
||||
Game botserv.GameParam
|
||||
|
||||
boardstate botserv.Boardstate
|
||||
ws *websocket.Conn
|
||||
}
|
||||
|
||||
type encoder interface {
|
||||
Encode(v interface{}) error
|
||||
}
|
||||
|
||||
type decoder interface {
|
||||
Decode(v interface{}) error
|
||||
}
|
||||
|
||||
func (c *Client) Negociate() (err error) {
|
||||
if c.Verbose {
|
||||
log.Printf("%s: trying to connect to game '%s'", c.Name, c.GameId)
|
||||
}
|
||||
c.ws, err = connect(c.Server, c.Port)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("connection failure: %s", err))
|
||||
}
|
||||
|
||||
err = websocket.JSON.Send(c.ws, struct {
|
||||
Id string `json:"id"`
|
||||
}{
|
||||
c.GameId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var idreq struct {
|
||||
Type string `json:"type"`
|
||||
PlayerId string `json:"id"`
|
||||
}
|
||||
err = websocket.JSON.Receive(c.ws, &idreq)
|
||||
if err != nil || idreq.Type == "failure" {
|
||||
return errors.New(fmt.Sprintf("failure: %+v", idreq))
|
||||
}
|
||||
if c.Verbose {
|
||||
log.Printf("%s: idreq: %+v", c.Name, idreq)
|
||||
}
|
||||
|
||||
err = websocket.JSON.Send(c.ws, struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Useragent string `json:"useragent"`
|
||||
}{
|
||||
Name: c.Name,
|
||||
Useragent: "gobot",
|
||||
Type: "robot",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
supportedEncs := []string{"bson", "json", "gob"}
|
||||
if c.ForceJSON {
|
||||
supportedEncs = []string{"json"}
|
||||
}
|
||||
err = websocket.JSON.Send(c.ws, supportedEncs)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("failure: %+v", err))
|
||||
}
|
||||
|
||||
err = websocket.JSON.Receive(c.ws, &c.Game)
|
||||
if c.Game.Type != "gameparam" {
|
||||
return errors.New("didn't receive a good gameparam")
|
||||
}
|
||||
if c.Verbose {
|
||||
log.Printf("%s: game parameters: %+v", c.Name, c.Game)
|
||||
}
|
||||
|
||||
conf := botserv.ClientConfig{
|
||||
ID: c.GameId,
|
||||
Stats: map[string]botserv.StatsRequest{
|
||||
c.Name: c.StatsReq,
|
||||
},
|
||||
}
|
||||
|
||||
err = websocket.JSON.Send(c.ws, conf)
|
||||
|
||||
var handshake struct {
|
||||
Id string `json:"id"`
|
||||
Success bool `json:"success"`
|
||||
Type string `json:"type"`
|
||||
botserv.Failure
|
||||
}
|
||||
websocket.JSON.Receive(c.ws, &handshake)
|
||||
if !handshake.Success {
|
||||
return errors.New(handshake.Reason)
|
||||
}
|
||||
if c.Verbose {
|
||||
log.Printf("%s: handshake: %+v", c.Name, handshake)
|
||||
}
|
||||
|
||||
// we don't do anything useful with dstats, but could be interesting to
|
||||
// pass along to the player?
|
||||
dstats := struct {
|
||||
Stats map[string]botserv.Stats `json:"stats"`
|
||||
Type string `json:"type"`
|
||||
}{}
|
||||
err = websocket.JSON.Receive(c.ws, &dstats)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Play() error {
|
||||
log.Printf("%s: starting loop", c.Name)
|
||||
|
||||
var enc encoder
|
||||
var dec decoder
|
||||
|
||||
if c.Game.Encoding == "json" {
|
||||
enc = json.NewEncoder(c.ws)
|
||||
dec = json.NewDecoder(c.ws)
|
||||
} else {
|
||||
enc = gob.NewEncoder(c.ws)
|
||||
dec = gob.NewDecoder(c.ws)
|
||||
}
|
||||
|
||||
var err error
|
||||
for {
|
||||
err = dec.Decode(&c.boardstate)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("%s: Connection likely lost: %s", c.Name, err))
|
||||
}
|
||||
c.Player.Recv(&c.boardstate)
|
||||
|
||||
instruction := c.Player.Instruction()
|
||||
err = enc.Encode(instruction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user