Refactor and implement the api functions
This commit is contained in:
parent
3474e6ca8c
commit
f82565bf22
5 changed files with 139 additions and 108 deletions
128
pkg/rove/api.go
Normal file
128
pkg/rove/api.go
Normal file
|
@ -0,0 +1,128 @@
|
|||
package rove
|
||||
|
||||
import (
|
||||
"github.com/mdiluz/rove/pkg/game"
|
||||
)
|
||||
|
||||
// ==============================
|
||||
// API: /status method: GET
|
||||
|
||||
// Status queries the status of the server
|
||||
func (s Server) Status() (r StatusResponse, err error) {
|
||||
s.GET("status", &r)
|
||||
return
|
||||
}
|
||||
|
||||
// StatusResponse is a struct that contains information on the status of the server
|
||||
type StatusResponse struct {
|
||||
Ready bool `json:"ready"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// API: /register method: POST
|
||||
|
||||
// Register registers a user account by name
|
||||
// Responds with a unique ID for that account to be used in future requests
|
||||
func (s Server) Register(d RegisterData) (r RegisterResponse, err error) {
|
||||
err = s.POST("register", d, &r)
|
||||
return
|
||||
}
|
||||
|
||||
// RegisterData describes the data to send when registering
|
||||
type RegisterData struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// RegisterResponse describes the response to a register request
|
||||
type RegisterResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// API: /spawn method: POST
|
||||
|
||||
// Spawn spawns the rover for an account
|
||||
// Responds with the position of said rover
|
||||
func (s Server) Spawn(d SpawnData) (r SpawnResponse, err error) {
|
||||
err = s.POST("spawn", d, &r)
|
||||
return
|
||||
}
|
||||
|
||||
// SpawnData is the data to be sent for the spawn command
|
||||
type SpawnData struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// SpawnResponse is the data to respond with on a spawn command
|
||||
type SpawnResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
|
||||
// The location of the spawned entity
|
||||
Position game.Vector `json:"position"`
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// API: /commands method: POST
|
||||
|
||||
// Commands issues a set of commands from the user
|
||||
func (s Server) Commands(d CommandsData) (r CommandsResponse, err error) {
|
||||
err = s.POST("commands", d, &r)
|
||||
return
|
||||
}
|
||||
|
||||
// CommandsData is a set of commands to execute in order
|
||||
type CommandsData struct {
|
||||
Id string `json:"id"`
|
||||
Commands []Command `json:"commands"`
|
||||
}
|
||||
|
||||
// CommandsResponse is the response to be sent back
|
||||
type CommandsResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
// CommandMove describes a single move command
|
||||
CommandMove = "move"
|
||||
)
|
||||
|
||||
// Command describes a single command to execute
|
||||
// it contains the type, and then any members used for each command type
|
||||
type Command struct {
|
||||
// Command is the main command string
|
||||
Command string `json:"command"`
|
||||
|
||||
// Used for CommandMove
|
||||
Bearing string `json:"bearing"` // The direction to move on a compass in short (NW) or long (NorthWest) form
|
||||
Duration int `json:"duration"` // The duration of the move in ticks
|
||||
}
|
||||
|
||||
// ================
|
||||
// API: /radar POST
|
||||
|
||||
// Radar queries the current radar for the user
|
||||
// Commands issues a set of commands from the user
|
||||
func (s Server) Radar(d RadarData) (r RadarResponse, err error) {
|
||||
err = s.POST("radar", d, &r)
|
||||
return
|
||||
}
|
||||
|
||||
// RadarData describes the input data to request an accounts current radar
|
||||
type RadarData struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// RadarResponse describes the response to a /radar call
|
||||
type RadarResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Error string `json:"error,omitempty"`
|
||||
|
||||
// The set of positions for nearby rovers
|
||||
Rovers []game.Vector `json:"rovers"`
|
||||
}
|
64
pkg/rove/http.go
Normal file
64
pkg/rove/http.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package rove
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Server is a simple wrapper to a server path
|
||||
type Server string
|
||||
|
||||
// GET performs a GET request
|
||||
func (s Server) GET(path string, out interface{}) error {
|
||||
url := url.URL{
|
||||
Scheme: "http",
|
||||
Host: string(s),
|
||||
Path: path,
|
||||
}
|
||||
if resp, err := http.Get(url.String()); err != nil {
|
||||
return err
|
||||
|
||||
} else if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("http.Get returned status %d: %s", resp.StatusCode, resp.Status)
|
||||
|
||||
} else {
|
||||
return json.NewDecoder(resp.Body).Decode(out)
|
||||
}
|
||||
}
|
||||
|
||||
// POST performs a POST request
|
||||
func (s Server) POST(path string, in interface{}, out interface{}) error {
|
||||
url := url.URL{
|
||||
Scheme: "http",
|
||||
Host: string(s),
|
||||
Path: path,
|
||||
}
|
||||
client := &http.Client{}
|
||||
|
||||
// Marshal the input
|
||||
marshalled, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set up the request
|
||||
req, err := http.NewRequest("POST", url.String(), bytes.NewReader(marshalled))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Do the POST
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
if resp, err := client.Do(req); err != nil {
|
||||
return err
|
||||
|
||||
} else if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("http returned status %d", resp.StatusCode)
|
||||
|
||||
} else {
|
||||
return json.NewDecoder(resp.Body).Decode(out)
|
||||
}
|
||||
}
|
39
pkg/rove/integration_test.go
Normal file
39
pkg/rove/integration_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package rove
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var server Server = "localhost:80"
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
status, err := server.Status()
|
||||
assert.NoError(t, err, "Status must not return error")
|
||||
assert.True(t, status.Ready, "Server must return ready")
|
||||
assert.NotZero(t, len(status.Version), "Version must not be empty")
|
||||
}
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
d1 := RegisterData{
|
||||
Name: uuid.New().String(),
|
||||
}
|
||||
r1, err := server.Register(d1)
|
||||
assert.NoError(t, err, "Register must not return error")
|
||||
assert.True(t, r1.Success, "Register must return success")
|
||||
assert.NotZero(t, len(r1.Id), "Register must return registration ID")
|
||||
|
||||
d2 := RegisterData{
|
||||
Name: uuid.New().String(),
|
||||
}
|
||||
r2, err := server.Register(d2)
|
||||
assert.NoError(t, err, "Register must not return error")
|
||||
assert.True(t, r2.Success, "Register must return success")
|
||||
assert.NotZero(t, len(r2.Id), "Register must return registration ID")
|
||||
|
||||
r3, err := server.Register(d1)
|
||||
assert.NoError(t, err, "Register must not return error")
|
||||
assert.False(t, r3.Success, "Register must return fail for duplicate registration")
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue