From 7ababb79f69c6c5f84d92b5ee9e01969ab830b57 Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Fri, 12 Jun 2020 22:51:18 +0100 Subject: [PATCH] Migrate to gRPC rather than REST with swagger Will also be adding in a RESTful endpoint to the server as well so it can consume both types --- .github/workflows/docker-image.yml | 7 +- Dockerfile.docs | 8 - Makefile | 4 +- cmd/rove-accountant/main.go | 19 +- cmd/rove-server/internal/api_test.go | 91 --- cmd/rove-server/internal/routes.go | 203 ++---- cmd/rove-server/internal/routes_test.go | 202 ------ cmd/rove-server/internal/server.go | 91 +-- cmd/rove/main.go | 35 +- docker-compose.yml | 12 +- go.mod | 1 + pkg/accounts/accounts.pb.go | 136 ++-- pkg/accounts/accounts.proto | 20 +- pkg/atlas/atlas.go | 8 +- pkg/atlas/atlas_test.go | 16 +- pkg/atlas/tile.go | 11 +- pkg/game/command_test.go | 4 +- pkg/game/world.go | 6 +- pkg/rove/api.go | 94 --- pkg/rove/http.go | 73 --- pkg/rove/rove.pb.go | 821 ++++++++++++++++++++++++ pkg/rove/rove.proto | 103 +++ swagger.yml | 246 ------- 23 files changed, 1110 insertions(+), 1101 deletions(-) delete mode 100644 Dockerfile.docs delete mode 100644 cmd/rove-server/internal/api_test.go delete mode 100644 cmd/rove-server/internal/routes_test.go delete mode 100644 pkg/rove/api.go delete mode 100644 pkg/rove/http.go create mode 100644 pkg/rove/rove.pb.go create mode 100644 pkg/rove/rove.proto delete mode 100644 swagger.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 3f33b71..1d08aea 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -21,12 +21,7 @@ jobs: - name: Install dict run: sudo apt-get update && sudo apt-get install wamerican - - - name: Install swagger - run: | - sudo curl -o /usr/local/bin/swagger -L'#' https://github.com/go-swagger/go-swagger/releases/download/v0.23.0/swagger_linux_amd64 - sudo chmod +x /usr/local/bin/swagger - + - name: Check out repo uses: actions/checkout@v2 diff --git a/Dockerfile.docs b/Dockerfile.docs deleted file mode 100644 index e0f15fe..0000000 --- a/Dockerfile.docs +++ /dev/null @@ -1,8 +0,0 @@ -FROM quay.io/goswagger/swagger:latest -LABEL maintainer="Marc Di Luzio " - -WORKDIR /app -COPY . . - -CMD [ "serve", "swagger.yml", "--no-open" ] - diff --git a/Makefile b/Makefile index f20f144..9205bd6 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ install: gen: protoc --proto_path pkg/accounts --go_out=plugins=grpc:pkg/accounts/ --go_opt=paths=source_relative pkg/accounts/accounts.proto + protoc --proto_path pkg/rove --go_out=plugins=grpc:pkg/rove/ --go_opt=paths=source_relative pkg/rove/rove.proto test: @echo Unit tests @@ -18,9 +19,6 @@ test: @echo Integration tests docker-compose up --build --exit-code-from=rove-tests --abort-on-container-exit rove-tests go tool cover -html=/tmp/coverage-data/c.out -o /tmp/coverage.html - - @echo Validating swagger spec - swagger validate swagger.yml @echo Done, coverage data can be found in /tmp/coverage.html diff --git a/cmd/rove-accountant/main.go b/cmd/rove-accountant/main.go index be71cfc..3e8e0d2 100644 --- a/cmd/rove-accountant/main.go +++ b/cmd/rove-accountant/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "fmt" "log" "net" "os" @@ -34,20 +33,20 @@ func (a *accountantServer) Register(ctx context.Context, in *accounts.RegisterIn log.Printf("Registering account: %s\n", in.Name) if _, err := a.accountant.RegisterAccount(in.Name); err != nil { log.Printf("Error: %s\n", err) - return &accounts.RegisterResponse{Success: false, Error: fmt.Sprintf("error registering account: %s", err)}, nil + return nil, err } // Save out the accounts if err := persistence.Save("accounts", a.accountant); err != nil { log.Printf("Error: %s\n", err) - return &accounts.RegisterResponse{Success: false, Error: fmt.Sprintf("failed to save accounts: %s", err)}, nil + return nil, err } - return &accounts.RegisterResponse{Success: true}, nil + return &accounts.RegisterResponse{}, nil } // AssignData assigns a key value pair to an account -func (a *accountantServer) AssignValue(_ context.Context, in *accounts.DataKeyValue) (*accounts.Response, error) { +func (a *accountantServer) AssignValue(_ context.Context, in *accounts.DataKeyValue) (*accounts.DataKeyResponse, error) { a.sync.RLock() defer a.sync.RUnlock() @@ -56,10 +55,10 @@ func (a *accountantServer) AssignValue(_ context.Context, in *accounts.DataKeyVa err := a.accountant.AssignData(in.Account, in.Key, in.Value) if err != nil { log.Printf("Error: %s\n", err) - return &accounts.Response{Success: false, Error: err.Error()}, nil + return nil, err } - return &accounts.Response{Success: true}, nil + return &accounts.DataKeyResponse{}, nil } @@ -73,10 +72,10 @@ func (a *accountantServer) GetValue(_ context.Context, in *accounts.DataKey) (*a data, err := a.accountant.GetValue(in.Account, in.Key) if err != nil { log.Printf("Error: %s\n", err) - return &accounts.DataResponse{Success: false, Error: err.Error()}, nil + return nil, err } - return &accounts.DataResponse{Success: true, Value: data}, nil + return &accounts.DataResponse{Value: data}, nil } @@ -117,7 +116,7 @@ func main() { // Serve the RPC server log.Printf("Serving accountant on %s\n", address) if err := grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to server gRPC: %s", err) + log.Fatalf("failed to serve gRPC: %s", err) } // Save out the accountant data diff --git a/cmd/rove-server/internal/api_test.go b/cmd/rove-server/internal/api_test.go deleted file mode 100644 index 146d61b..0000000 --- a/cmd/rove-server/internal/api_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// +build integration - -package internal - -import ( - "os" - "testing" - - "github.com/google/uuid" - "github.com/mdiluz/rove/pkg/game" - "github.com/mdiluz/rove/pkg/rove" - "github.com/stretchr/testify/assert" -) - -const ( - defaultAddress = "localhost:8080" -) - -var serv = func() rove.Server { - var address = os.Getenv("ROVE_SERVER_ADDRESS") - if len(address) == 0 { - address = defaultAddress - } - return rove.Server(address) -}() - -func TestServer_Status(t *testing.T) { - status, err := serv.Status() - assert.NoError(t, err) - assert.True(t, status.Ready) - assert.NotZero(t, len(status.Version)) -} - -func TestServer_Register(t *testing.T) { - d1 := rove.RegisterData{ - Name: uuid.New().String(), - } - _, err := serv.Register(d1) - assert.NoError(t, err) - - d2 := rove.RegisterData{ - Name: uuid.New().String(), - } - _, err = serv.Register(d2) - assert.NoError(t, err) - - _, err = serv.Register(d1) - assert.Error(t, err) -} - -func TestServer_Command(t *testing.T) { - d1 := rove.RegisterData{ - Name: uuid.New().String(), - } - _, err := serv.Register(d1) - assert.NoError(t, err) - - c := rove.CommandData{ - Commands: []game.Command{ - { - Command: game.CommandMove, - Bearing: "N", - Duration: 1, - }, - }, - } - _, err = serv.Command(d1.Name, c) - assert.NoError(t, err) -} - -func TestServer_Radar(t *testing.T) { - d1 := rove.RegisterData{ - Name: uuid.New().String(), - } - _, err := serv.Register(d1) - assert.NoError(t, err) - - _, err = serv.Radar(d1.Name) - assert.NoError(t, err) -} - -func TestServer_Rover(t *testing.T) { - d1 := rove.RegisterData{ - Name: uuid.New().String(), - } - _, err := serv.Register(d1) - assert.NoError(t, err) - - _, err = serv.Rover(d1.Name) - assert.NoError(t, err) -} diff --git a/cmd/rove-server/internal/routes.go b/cmd/rove-server/internal/routes.go index 41258c0..eae2a1d 100644 --- a/cmd/rove-server/internal/routes.go +++ b/cmd/rove-server/internal/routes.go @@ -2,69 +2,26 @@ package internal import ( "context" - "encoding/json" "fmt" - "io" - "log" - "net/http" - "time" + "github.com/golang/protobuf/ptypes/empty" "github.com/google/uuid" "github.com/mdiluz/rove/pkg/accounts" + "github.com/mdiluz/rove/pkg/game" "github.com/mdiluz/rove/pkg/rove" "github.com/mdiluz/rove/pkg/version" "google.golang.org/grpc" ) -// Handler describes a function that handles any incoming request and can respond -type Handler func(*Server, map[string]string, io.ReadCloser) (interface{}, error) - -// Route defines the information for a single path->function route -type Route struct { - path string - method string - handler Handler -} - -// Routes is an array of all the Routes -var Routes = []Route{ - { - path: "/status", - method: http.MethodGet, - handler: HandleStatus, - }, - { - path: "/register", - method: http.MethodPost, - handler: HandleRegister, - }, - { - path: "/{account}/command", - method: http.MethodPost, - handler: HandleCommand, - }, - { - path: "/{account}/radar", - method: http.MethodGet, - handler: HandleRadar, - }, - { - path: "/{account}/rover", - method: http.MethodGet, - handler: HandleRover, - }, -} - -// HandleStatus handles the /status request -func HandleStatus(s *Server, vars map[string]string, b io.ReadCloser) (interface{}, error) { - - // Simply return the current server status - response := rove.StatusResponse{ +func (s *Server) Status(context.Context, *empty.Empty) (*rove.StatusResponse, error) { + response := &rove.StatusResponse{ Ready: true, Version: version.Version, - Tick: s.tick, + Tick: int32(s.tick), } + // TODO: Verify the accountant is up and ready too + // If there's a schedule, respond with it if len(s.schedule.Entries()) > 0 { response.NextTick = s.schedule.Entries()[0].Next.Format("15:04:05") @@ -73,31 +30,15 @@ func HandleStatus(s *Server, vars map[string]string, b io.ReadCloser) (interface return response, nil } -// HandleRegister handles /register endpoint -func HandleRegister(s *Server, vars map[string]string, b io.ReadCloser) (interface{}, error) { - var response = rove.RegisterResponse{} - - // Decode the registration info, verify it and register the account - var data rove.RegisterData - err := json.NewDecoder(b).Decode(&data) - if err != nil { - log.Printf("Failed to decode json: %s\n", err) - return BadRequestError{Error: err.Error()}, nil - - } else if len(data.Name) == 0 { - return BadRequestError{Error: "cannot register empty name"}, nil - +func (s *Server) Register(ctx context.Context, req *rove.RegisterRequest) (*empty.Empty, error) { + if len(req.Name) == 0 { + return nil, fmt.Errorf("empty account name") } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - reg := accounts.RegisterInfo{Name: data.Name} - if acc, err := s.accountant.Register(ctx, ®, grpc.WaitForReady(true)); err != nil { - return nil, fmt.Errorf("gRPC failed to contact accountant: %s", err) - } else if !acc.Success { - return BadRequestError{Error: acc.Error}, nil + if _, err := s.accountant.Register(ctx, &accounts.RegisterInfo{Name: req.Name}, grpc.WaitForReady(true)); err != nil { + return nil, err - } else if _, _, err := s.SpawnRoverForAccount(data.Name); err != nil { + } else if _, _, err := s.SpawnRoverForAccount(req.Name); err != nil { return nil, fmt.Errorf("failed to spawn rover for account: %s", err) } else if err := s.SaveWorld(); err != nil { @@ -105,66 +46,48 @@ func HandleRegister(s *Server, vars map[string]string, b io.ReadCloser) (interfa } - log.Printf("register response:%+v\n", response) - return response, nil + return &empty.Empty{}, nil } -// HandleSpawn will spawn the player entity for the associated account -func HandleCommand(s *Server, vars map[string]string, b io.ReadCloser) (interface{}, error) { - var response = rove.CommandResponse{} +func (s *Server) Rover(ctx context.Context, req *rove.RoverRequest) (*rove.RoverResponse, error) { + response := &rove.RoverResponse{} + if len(req.Account) == 0 { + return nil, fmt.Errorf("empty account name") - id := vars["account"] - - // Decode the commands, verify them and the account, and execute the commands - var data rove.CommandData - if err := json.NewDecoder(b).Decode(&data); err != nil { - log.Printf("Failed to decode json: %s\n", err) - return BadRequestError{Error: err.Error()}, nil - - } - - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - key := accounts.DataKey{Account: id, Key: "rover"} - if len(id) == 0 { - return BadRequestError{Error: "no account ID provided"}, nil - - } else if resp, err := s.accountant.GetValue(ctx, &key); err != nil { + } else if resp, err := s.accountant.GetValue(ctx, &accounts.DataKey{Account: req.Account, Key: "rover"}); err != nil { return nil, fmt.Errorf("gRPC failed to contact accountant: %s", err) - } else if !resp.Success { - return BadRequestError{Error: resp.Error}, nil - } else if id, err := uuid.Parse(resp.Value); err != nil { return nil, fmt.Errorf("account had invalid rover ID: %s", resp.Value) - } else if err := s.world.Enqueue(id, data.Commands...); err != nil { - return BadRequestError{Error: err.Error()}, nil + } else if attrib, err := s.world.RoverAttributes(id); err != nil { + return nil, fmt.Errorf("error getting rover attributes: %s", err) + } else { + response = &rove.RoverResponse{ + Name: attrib.Name, + Position: &rove.Vector{ + X: int32(attrib.Pos.X), + Y: int32(attrib.Pos.Y), + }, + } } - - log.Printf("command response \taccount:%s\tresponse:%+v\n", id, response) return response, nil } -// HandleRadar handles the radar request -func HandleRadar(s *Server, vars map[string]string, b io.ReadCloser) (interface{}, error) { - var response = rove.RadarResponse{} +func (s *Server) Radar(ctx context.Context, req *rove.RadarRequest) (*rove.RadarResponse, error) { + if len(req.Account) == 0 { + return nil, fmt.Errorf("empty account name") + } - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - id := vars["account"] - key := accounts.DataKey{Account: id, Key: "rover"} - if len(id) == 0 { - return BadRequestError{Error: "no account ID provided"}, nil + response := &rove.RadarResponse{} - } else if resp, err := s.accountant.GetValue(ctx, &key); err != nil { + resp, err := s.accountant.GetValue(ctx, &accounts.DataKey{Account: req.Account, Key: "rover"}) + if err != nil { return nil, fmt.Errorf("gRPC failed to contact accountant: %s", err) + } - } else if !resp.Success { - return BadRequestError{Error: resp.Error}, nil - - } else if id, err := uuid.Parse(resp.Value); err != nil { + if id, err := uuid.Parse(resp.Value); err != nil { return nil, fmt.Errorf("account had invalid rover ID: %s", resp.Value) } else if attrib, err := s.world.RoverAttributes(id); err != nil { @@ -175,40 +98,38 @@ func HandleRadar(s *Server, vars map[string]string, b io.ReadCloser) (interface{ } else { response.Tiles = radar - response.Range = attrib.Range + response.Range = int32(attrib.Range) } - log.Printf("radar response \taccount:%s\tresponse:%+v\n", id, response) return response, nil } -// HandleRover handles the rover request -func HandleRover(s *Server, vars map[string]string, b io.ReadCloser) (interface{}, error) { - var response = rove.RoverResponse{} +func (s *Server) Commands(ctx context.Context, req *rove.CommandsRequest) (*empty.Empty, error) { + if len(req.Account) == 0 { + return nil, fmt.Errorf("empty account") + } + resp, err := s.accountant.GetValue(ctx, &accounts.DataKey{Account: req.Account, Key: "rover"}) - ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - defer cancel() - id := vars["account"] - key := accounts.DataKey{Account: id, Key: "rover"} - if len(id) == 0 { - return BadRequestError{Error: "no account ID provided"}, nil + if err != nil { + return nil, err + } - } else if resp, err := s.accountant.GetValue(ctx, &key); err != nil { - return nil, fmt.Errorf("gRPC failed to contact accountant: %s", err) - - } else if !resp.Success { - return BadRequestError{Error: resp.Error}, nil - - } else if id, err := uuid.Parse(resp.Value); err != nil { + id, err := uuid.Parse(resp.Value) + if err != nil { return nil, fmt.Errorf("account had invalid rover ID: %s", resp.Value) - - } else if attrib, err := s.world.RoverAttributes(id); err != nil { - return nil, fmt.Errorf("error getting rover attributes: %s", err) - - } else { - response.Attributes = attrib } - log.Printf("rover response \taccount:%s\tresponse:%+v\n", id, response) - return response, nil + var cmds []game.Command + for _, c := range req.Commands { + cmds = append(cmds, game.Command{ + Bearing: c.Bearing, + Command: c.Command, + Duration: int(c.Duration)}) + } + + if err := s.world.Enqueue(id, cmds...); err != nil { + return nil, err + } + + return &empty.Empty{}, nil } diff --git a/cmd/rove-server/internal/routes_test.go b/cmd/rove-server/internal/routes_test.go deleted file mode 100644 index 04a1bac..0000000 --- a/cmd/rove-server/internal/routes_test.go +++ /dev/null @@ -1,202 +0,0 @@ -// +build integration - -package internal - -import ( - "bytes" - "context" - "encoding/json" - "net/http" - "net/http/httptest" - "path" - "testing" - - "github.com/google/uuid" - "github.com/mdiluz/rove/pkg/accounts" - "github.com/mdiluz/rove/pkg/atlas" - "github.com/mdiluz/rove/pkg/game" - "github.com/mdiluz/rove/pkg/rove" - "github.com/mdiluz/rove/pkg/vector" - "github.com/stretchr/testify/assert" -) - -func TestHandleStatus(t *testing.T) { - - request, _ := http.NewRequest(http.MethodGet, "/status", nil) - response := httptest.NewRecorder() - - s := NewServer() - s.Initialise(true) - s.router.ServeHTTP(response, request) - assert.Equal(t, http.StatusOK, response.Code) - - var status rove.StatusResponse - err := json.NewDecoder(response.Body).Decode(&status) - assert.NoError(t, err) - - if status.Ready != true { - t.Errorf("got false for /status") - } - - if len(status.Version) == 0 { - t.Errorf("got empty version info") - } -} - -func TestHandleRegister(t *testing.T) { - data := rove.RegisterData{Name: uuid.New().String()} - b, err := json.Marshal(data) - if err != nil { - t.Error(err) - } - - request, _ := http.NewRequest(http.MethodPost, "/register", bytes.NewReader(b)) - response := httptest.NewRecorder() - - s := NewServer() - s.Initialise(true) - s.router.ServeHTTP(response, request) - assert.Equal(t, http.StatusOK, response.Code) - - var status rove.RegisterResponse - err = json.NewDecoder(response.Body).Decode(&status) - assert.NoError(t, err) -} - -func TestHandleCommand(t *testing.T) { - name := uuid.New().String() - s := NewServer() - s.Initialise(false) // Leave the world empty with no obstacles - reg := accounts.RegisterInfo{Name: name} - acc, err := s.accountant.Register(context.Background(), ®) - assert.NoError(t, err) - assert.NotNil(t, acc) - assert.True(t, acc.Success, acc.Error) - - assert.NoError(t, err, "Error registering account") - - // Spawn the rover rover for the account - _, inst, err := s.SpawnRoverForAccount(name) - assert.NoError(t, s.world.WarpRover(inst, vector.Vector{})) - - attribs, err := s.world.RoverAttributes(inst) - assert.NoError(t, err, "Couldn't get rover position") - - data := rove.CommandData{ - Commands: []game.Command{ - { - Command: game.CommandMove, - Bearing: "N", - Duration: 1, - }, - }, - } - - b, err := json.Marshal(data) - assert.NoError(t, err, "Error marshalling data") - - request, _ := http.NewRequest(http.MethodPost, path.Join("/", name, "/command"), bytes.NewReader(b)) - response := httptest.NewRecorder() - - s.router.ServeHTTP(response, request) - assert.Equal(t, http.StatusOK, response.Code) - - var status rove.CommandResponse - err = json.NewDecoder(response.Body).Decode(&status) - assert.NoError(t, err) - - attrib, err := s.world.RoverAttributes(inst) - assert.NoError(t, err, "Couldn't get rover attribs") - - // Tick the command queues to progress the move command - s.world.EnqueueAllIncoming() - s.world.ExecuteCommandQueues() - - attribs2, err := s.world.RoverAttributes(inst) - assert.NoError(t, err, "Couldn't get rover position") - attribs.Pos.Add(vector.Vector{X: 0.0, Y: attrib.Speed * 1}) // Should have moved north by the speed and duration - assert.Equal(t, attribs.Pos, attribs2.Pos, "Rover should have moved by bearing") -} - -func TestHandleRadar(t *testing.T) { - name := uuid.New().String() - s := NewServer() - s.Initialise(false) // Spawn a clean world - reg := accounts.RegisterInfo{Name: name} - acc, err := s.accountant.Register(context.Background(), ®) - assert.NoError(t, err) - assert.True(t, acc.Success, acc.Error) - assert.NoError(t, err, "Error registering account") - - // Spawn the rover rover for the account - attrib, id, err := s.SpawnRoverForAccount(name) - assert.NoError(t, err) - - // Warp this rover to 0,0 - assert.NoError(t, s.world.WarpRover(id, vector.Vector{})) - - // Explicity set a few nearby tiles - wallPos1 := vector.Vector{X: 0, Y: -1} - wallPos2 := vector.Vector{X: 1, Y: 1} - rockPos := vector.Vector{X: 1, Y: 3} - emptyPos := vector.Vector{X: -2, Y: -3} - assert.NoError(t, s.world.Atlas.SetTile(wallPos1, atlas.TileWall)) - assert.NoError(t, s.world.Atlas.SetTile(wallPos2, atlas.TileWall)) - assert.NoError(t, s.world.Atlas.SetTile(rockPos, atlas.TileRock)) - assert.NoError(t, s.world.Atlas.SetTile(emptyPos, atlas.TileEmpty)) - - request, _ := http.NewRequest(http.MethodGet, path.Join("/", name, "/radar"), nil) - response := httptest.NewRecorder() - - s.router.ServeHTTP(response, request) - assert.Equal(t, http.StatusOK, response.Code) - - var status rove.RadarResponse - err = json.NewDecoder(response.Body).Decode(&status) - assert.NoError(t, err) - - scope := attrib.Range*2 + 1 - radarOrigin := vector.Vector{X: -attrib.Range, Y: -attrib.Range} - - // Make sure the rover tile is correct - assert.Equal(t, atlas.TileRover, status.Tiles[len(status.Tiles)/2]) - - // Check our other tiles - wallPos1.Add(radarOrigin.Negated()) - wallPos2.Add(radarOrigin.Negated()) - rockPos.Add(radarOrigin.Negated()) - emptyPos.Add(radarOrigin.Negated()) - assert.Equal(t, atlas.TileWall, status.Tiles[wallPos1.X+wallPos1.Y*scope]) - assert.Equal(t, atlas.TileWall, status.Tiles[wallPos2.X+wallPos2.Y*scope]) - assert.Equal(t, atlas.TileRock, status.Tiles[rockPos.X+rockPos.Y*scope]) - assert.Equal(t, atlas.TileEmpty, status.Tiles[emptyPos.X+emptyPos.Y*scope]) - -} - -func TestHandleRover(t *testing.T) { - name := uuid.New().String() - s := NewServer() - s.Initialise(true) - reg := accounts.RegisterInfo{Name: name} - acc, err := s.accountant.Register(context.Background(), ®) - assert.NoError(t, err) - assert.True(t, acc.Success, acc.Error) - - // Spawn one rover for the account - attribs, _, err := s.SpawnRoverForAccount(name) - assert.NoError(t, err) - - request, _ := http.NewRequest(http.MethodGet, path.Join("/", name, "/rover"), nil) - response := httptest.NewRecorder() - - s.router.ServeHTTP(response, request) - assert.Equal(t, http.StatusOK, response.Code) - - var status rove.RoverResponse - err = json.NewDecoder(response.Body).Decode(&status) - assert.NoError(t, err) - - if attribs != status.Attributes { - t.Errorf("Missmatched attributes: %+v, !=%+v", attribs, status.Attributes) - } -} diff --git a/cmd/rove-server/internal/server.go b/cmd/rove-server/internal/server.go index 00f696b..920cbf2 100644 --- a/cmd/rove-server/internal/server.go +++ b/cmd/rove-server/internal/server.go @@ -2,20 +2,17 @@ package internal import ( "context" - "encoding/json" "fmt" "log" "net" - "net/http" "os" "sync" - "time" "github.com/google/uuid" - "github.com/gorilla/mux" "github.com/mdiluz/rove/pkg/accounts" "github.com/mdiluz/rove/pkg/game" "github.com/mdiluz/rove/pkg/persistence" + "github.com/mdiluz/rove/pkg/rove" "github.com/robfig/cron" "google.golang.org/grpc" ) @@ -40,10 +37,9 @@ type Server struct { accountant accounts.AccountantClient clientConn *grpc.ClientConn - // HTTP server - listener net.Listener - server *http.Server - router *mux.Router + // gRPC server + netListener net.Listener + grpcServ *grpc.Server // Config settings address string @@ -85,13 +81,10 @@ func OptionTick(minutes int) ServerOption { // NewServer sets up a new server func NewServer(opts ...ServerOption) *Server { - router := mux.NewRouter().StrictSlash(true) - // Set up the default server s := &Server{ address: "", persistence: EphemeralData, - router: router, schedule: cron.New(), } @@ -100,9 +93,6 @@ func NewServer(opts ...ServerOption) *Server { o(s) } - // Set up the server object - s.server = &http.Server{Addr: s.address, Handler: s.router} - // Start small, we can grow the world later s.world = game.NewWorld(4, 8) @@ -133,18 +123,14 @@ func (s *Server) Initialise(fillWorld bool) (err error) { return err } - // Set up the handlers - for _, route := range Routes { - s.router.HandleFunc(route.path, s.wrapHandler(route.method, route.handler)) + // Set up the RPC server and register + s.netListener, err = net.Listen("tcp", s.address) + if err != nil { + log.Fatalf("failed to listen: %v", err) } + s.grpcServ = grpc.NewServer() + rove.RegisterRoverServerServer(s.grpcServ, s) - // Start the listen - log.Printf("Listening on %s\n", s.server.Addr) - if s.listener, err = net.Listen("tcp", s.server.Addr); err != nil { - return err - } - - s.address = s.listener.Addr().String() return nil } @@ -178,9 +164,10 @@ func (s *Server) Run() { log.Printf("First server tick scheduled for %s\n", s.schedule.Entries()[0].Next.Format("15:04:05")) } - // Serve the http requests - if err := s.server.Serve(s.listener); err != nil && err != http.ErrServerClosed { - log.Fatal(err) + // Serve the RPC server + log.Printf("Serving rove on %s\n", s.address) + if err := s.grpcServ.Serve(s.netListener); err != nil && err != grpc.ErrServerStopped { + log.Fatalf("failed to serve gRPC: %s", err) } } @@ -189,12 +176,8 @@ func (s *Server) Stop() error { // Stop the cron s.schedule.Stop() - // Try and shut down the http server - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - if err := s.server.Shutdown(ctx); err != nil { - return err - } + // Stop the gRPC + s.grpcServ.Stop() // Close the accountant connection if err := s.clientConn.Close(); err != nil { @@ -206,7 +189,7 @@ func (s *Server) Stop() error { // Close waits until the server is finished and closes up shop func (s *Server) Close() error { - // Wait until the server has shut down + // Wait until the world has shut down s.sync.Wait() // Save and return @@ -253,40 +236,6 @@ type BadRequestError struct { Error string `json:"error"` } -// wrapHandler wraps a request handler in http checks -func (s *Server) wrapHandler(method string, handler Handler) func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - // Log the request - log.Printf("%s\t%s\n", r.Method, r.RequestURI) - - vars := mux.Vars(r) - - // Verify the method, call the handler, and encode the return - if r.Method != method { - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - - val, err := handler(s, vars, r.Body) - if err != nil { - log.Printf("Failed to handle http request: %s", err) - w.WriteHeader(http.StatusInternalServerError) - return - - } else if _, ok := val.(BadRequestError); ok { - w.WriteHeader(http.StatusBadRequest) - } - - if err := json.NewEncoder(w).Encode(val); err != nil { - log.Printf("Failed to encode reply to json: %s", err) - w.WriteHeader(http.StatusInternalServerError) - - } else { - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - } - } -} - // SpawnRoverForAccount spawns the rover rover for an account func (s *Server) SpawnRoverForAccount(account string) (game.RoverAttributes, uuid.UUID, error) { if inst, err := s.world.SpawnRover(); err != nil { @@ -297,9 +246,9 @@ func (s *Server) SpawnRoverForAccount(account string) (game.RoverAttributes, uui } else { keyval := accounts.DataKeyValue{Account: account, Key: "rover", Value: inst.String()} - resp, err := s.accountant.AssignValue(context.Background(), &keyval) - if err != nil || !resp.Success { - log.Printf("Failed to assign rover to account, %s, %s", err, resp.Error) + _, err := s.accountant.AssignValue(context.Background(), &keyval) + if err != nil { + log.Printf("Failed to assign rover to account, %s", err) // Try and clear up the rover if err := s.world.DestroyRover(inst); err != nil { diff --git a/cmd/rove/main.go b/cmd/rove/main.go index 527faf9..7e7e418 100644 --- a/cmd/rove/main.go +++ b/cmd/rove/main.go @@ -7,10 +7,14 @@ import ( "io/ioutil" "os" "path" + "time" + "github.com/golang/protobuf/ptypes/empty" "github.com/mdiluz/rove/pkg/game" "github.com/mdiluz/rove/pkg/rove" "github.com/mdiluz/rove/pkg/version" + "golang.org/x/net/context" + "google.golang.org/grpc" ) var USAGE = "" @@ -90,7 +94,13 @@ func InnerMain(command string) error { } // Set up the server - var server = rove.Server(config.Host) + clientConn, err := grpc.Dial(config.Host, grpc.WithInsecure()) + if err != nil { + return err + } + var client = rove.NewRoverServerClient(clientConn) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() // Grab the account var account = config.Accounts[config.Host] @@ -98,7 +108,7 @@ func InnerMain(command string) error { // Handle all the commands switch command { case "status": - response, err := server.Status() + response, err := client.Status(ctx, &empty.Empty{}) switch { case err != nil: return err @@ -114,10 +124,10 @@ func InnerMain(command string) error { if len(*name) == 0 { return fmt.Errorf("must set name with -name") } - d := rove.RegisterData{ + d := rove.RegisterRequest{ Name: *name, } - _, err := server.Register(d) + _, err := client.Register(ctx, &d) switch { case err != nil: return err @@ -128,11 +138,12 @@ func InnerMain(command string) error { } case "move": - d := rove.CommandData{ - Commands: []game.Command{ + d := rove.CommandsRequest{ + Account: account, + Commands: []*rove.Command{ { Command: game.CommandMove, - Duration: *duration, + Duration: int32(*duration), Bearing: *bearing, }, }, @@ -142,7 +153,7 @@ func InnerMain(command string) error { return err } - _, err := server.Command(account, d) + _, err := client.Commands(ctx, &d) switch { case err != nil: return err @@ -152,11 +163,12 @@ func InnerMain(command string) error { } case "radar": + dat := rove.RadarRequest{Account: account} if err := verifyId(account); err != nil { return err } - response, err := server.Radar(account) + response, err := client.Radar(ctx, &dat) switch { case err != nil: return err @@ -167,17 +179,18 @@ func InnerMain(command string) error { } case "rover": + req := rove.RoverRequest{Account: account} if err := verifyId(account); err != nil { return err } - response, err := server.Rover(account) + response, err := client.Rover(ctx, &req) switch { case err != nil: return err default: - fmt.Printf("attributes: %+v\n", response.Attributes) + fmt.Printf("attributes: %+v\n", response) } case "config": fmt.Printf("host: %s\taccount: %s\n", config.Host, account) diff --git a/docker-compose.yml b/docker-compose.yml index e370c48..83b3396 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,18 +18,8 @@ services: - persistent-data:/mnt/rove-server:rw command: [ ./rove-accountant ] - rove-docs: - build: - context: . - dockerfile: Dockerfile.docs - image: rove-docs:latest - ports: - - "80:80" - environment: - - PORT=80 - rove-server: - depends_on: [ rove-accountant, rove-docs ] + depends_on: [ rove-accountant ] build: context: . dockerfile: Dockerfile diff --git a/go.mod b/go.mod index 973e0a5..c9465c4 100644 --- a/go.mod +++ b/go.mod @@ -10,5 +10,6 @@ require ( github.com/robfig/cron v1.2.0 github.com/stretchr/testify v1.6.0 github.com/tjarratt/babble v0.0.0-20191209142150-eecdf8c2339d + golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 google.golang.org/grpc v1.29.1 ) diff --git a/pkg/accounts/accounts.pb.go b/pkg/accounts/accounts.pb.go index f3f33b9..aa6fcd2 100644 --- a/pkg/accounts/accounts.pb.go +++ b/pkg/accounts/accounts.pb.go @@ -67,9 +67,6 @@ func (m *RegisterInfo) GetName() string { // RegisterResponse is the response information from registering an account type RegisterResponse struct { - // The error value should only be populated if success is false - Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -100,20 +97,6 @@ func (m *RegisterResponse) XXX_DiscardUnknown() { var xxx_messageInfo_RegisterResponse proto.InternalMessageInfo -func (m *RegisterResponse) GetSuccess() bool { - if m != nil { - return m.Success - } - return false -} - -func (m *RegisterResponse) GetError() string { - if m != nil { - return m.Error - } - return "" -} - // DataKeyValue represents a simple key value pair to assign to an account type DataKeyValue struct { // The account to assign the new key value pair to @@ -172,54 +155,37 @@ func (m *DataKeyValue) GetValue() string { return "" } -// Response is a simple response with success and error -type Response struct { - // error should only be populated if success is false - Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` +// DataKeyResponse is a simple response +type DataKeyResponse struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *Response) Reset() { *m = Response{} } -func (m *Response) String() string { return proto.CompactTextString(m) } -func (*Response) ProtoMessage() {} -func (*Response) Descriptor() ([]byte, []int) { +func (m *DataKeyResponse) Reset() { *m = DataKeyResponse{} } +func (m *DataKeyResponse) String() string { return proto.CompactTextString(m) } +func (*DataKeyResponse) ProtoMessage() {} +func (*DataKeyResponse) Descriptor() ([]byte, []int) { return fileDescriptor_e1e7723af4c007b7, []int{3} } -func (m *Response) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Response.Unmarshal(m, b) +func (m *DataKeyResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DataKeyResponse.Unmarshal(m, b) } -func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Response.Marshal(b, m, deterministic) +func (m *DataKeyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DataKeyResponse.Marshal(b, m, deterministic) } -func (m *Response) XXX_Merge(src proto.Message) { - xxx_messageInfo_Response.Merge(m, src) +func (m *DataKeyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_DataKeyResponse.Merge(m, src) } -func (m *Response) XXX_Size() int { - return xxx_messageInfo_Response.Size(m) +func (m *DataKeyResponse) XXX_Size() int { + return xxx_messageInfo_DataKeyResponse.Size(m) } -func (m *Response) XXX_DiscardUnknown() { - xxx_messageInfo_Response.DiscardUnknown(m) +func (m *DataKeyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_DataKeyResponse.DiscardUnknown(m) } -var xxx_messageInfo_Response proto.InternalMessageInfo - -func (m *Response) GetSuccess() bool { - if m != nil { - return m.Success - } - return false -} - -func (m *Response) GetError() string { - if m != nil { - return m.Error - } - return "" -} +var xxx_messageInfo_DataKeyResponse proto.InternalMessageInfo // DataKey describes a simple key value with an account, for fetching type DataKey struct { @@ -273,9 +239,6 @@ func (m *DataKey) GetKey() string { // DataResponse describes a data fetch response type DataResponse struct { - // error should only be populated if success is false - Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` - Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // The value of the key Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -308,20 +271,6 @@ func (m *DataResponse) XXX_DiscardUnknown() { var xxx_messageInfo_DataResponse proto.InternalMessageInfo -func (m *DataResponse) GetSuccess() bool { - if m != nil { - return m.Success - } - return false -} - -func (m *DataResponse) GetError() string { - if m != nil { - return m.Error - } - return "" -} - func (m *DataResponse) GetValue() string { if m != nil { return m.Value @@ -333,7 +282,7 @@ func init() { proto.RegisterType((*RegisterInfo)(nil), "accounts.RegisterInfo") proto.RegisterType((*RegisterResponse)(nil), "accounts.RegisterResponse") proto.RegisterType((*DataKeyValue)(nil), "accounts.DataKeyValue") - proto.RegisterType((*Response)(nil), "accounts.Response") + proto.RegisterType((*DataKeyResponse)(nil), "accounts.DataKeyResponse") proto.RegisterType((*DataKey)(nil), "accounts.DataKey") proto.RegisterType((*DataResponse)(nil), "accounts.DataResponse") } @@ -343,26 +292,25 @@ func init() { } var fileDescriptor_e1e7723af4c007b7 = []byte{ - // 298 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0x4f, 0x4b, 0xc3, 0x40, - 0x10, 0xc5, 0x8d, 0x55, 0x1b, 0xc7, 0x22, 0x75, 0x11, 0x09, 0x39, 0xc9, 0x8a, 0xe0, 0x29, 0x01, - 0x45, 0x04, 0xbd, 0xd8, 0x22, 0x88, 0x78, 0x91, 0x20, 0x1e, 0xbc, 0x6d, 0xe3, 0x18, 0x43, 0x9b, - 0xdd, 0xb0, 0x7f, 0x0a, 0xf5, 0xf3, 0xf9, 0xc1, 0x24, 0xbb, 0xd9, 0x1a, 0xac, 0x17, 0x7b, 0xdb, - 0x17, 0xe6, 0xf7, 0xe6, 0xcd, 0x4c, 0x60, 0x9f, 0xe5, 0xb9, 0x30, 0x5c, 0xab, 0xa4, 0x96, 0x42, - 0x0b, 0x12, 0x7a, 0x4d, 0x29, 0x0c, 0x32, 0x2c, 0x4a, 0xa5, 0x51, 0x3e, 0xf0, 0x77, 0x41, 0x08, - 0x6c, 0x71, 0x56, 0x61, 0x14, 0x1c, 0x07, 0x67, 0xbb, 0x99, 0x7d, 0xd3, 0x31, 0x0c, 0x7d, 0x4d, - 0x86, 0xaa, 0x16, 0x5c, 0x21, 0x89, 0xa0, 0xaf, 0x4c, 0x9e, 0xa3, 0x52, 0xb6, 0x34, 0xcc, 0xbc, - 0x24, 0x87, 0xb0, 0x8d, 0x52, 0x0a, 0x19, 0x6d, 0x5a, 0x0b, 0x27, 0xe8, 0x13, 0x0c, 0xee, 0x98, - 0x66, 0x8f, 0xb8, 0x78, 0x61, 0x33, 0x63, 0xf9, 0x36, 0x43, 0xdb, 0xca, 0x4b, 0x32, 0x84, 0xde, - 0x14, 0x17, 0x2d, 0xdd, 0x3c, 0x1b, 0xc7, 0x79, 0x03, 0x45, 0x3d, 0xe7, 0x68, 0x05, 0xbd, 0x86, - 0x70, 0xed, 0x34, 0x97, 0xd0, 0x6f, 0xd3, 0xfc, 0x27, 0x08, 0x7d, 0x76, 0x43, 0xac, 0xdb, 0xf6, - 0xef, 0x41, 0xce, 0xbf, 0x02, 0x80, 0x91, 0xeb, 0xc9, 0xb8, 0x26, 0xb7, 0xcd, 0x5c, 0x6e, 0xdb, - 0xe4, 0x28, 0x59, 0x1e, 0xae, 0x7b, 0xa5, 0x38, 0x5e, 0xfd, 0xee, 0x43, 0xd1, 0x0d, 0x72, 0x03, - 0x7b, 0x23, 0xa5, 0xca, 0x82, 0xbb, 0x55, 0x77, 0x4c, 0xba, 0x27, 0x88, 0x49, 0xd7, 0x64, 0x09, - 0x5f, 0x41, 0x78, 0x8f, 0xda, 0x91, 0x07, 0x2b, 0x64, 0xfc, 0xcb, 0xec, 0x07, 0x1c, 0x9f, 0xbe, - 0x9e, 0x14, 0xa5, 0xfe, 0x30, 0x93, 0x24, 0x17, 0x55, 0x5a, 0xbd, 0x95, 0x33, 0xf3, 0x99, 0x4a, - 0x31, 0xc7, 0xb4, 0x9e, 0x16, 0xa9, 0xa7, 0x26, 0x3b, 0xf6, 0x0f, 0xbc, 0xf8, 0x0e, 0x00, 0x00, - 0xff, 0xff, 0xef, 0x53, 0xc6, 0xba, 0x93, 0x02, 0x00, 0x00, + // 276 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0x41, 0x4b, 0xc3, 0x40, + 0x10, 0x85, 0x8d, 0x55, 0x1b, 0xc7, 0xa2, 0xed, 0x20, 0x12, 0x73, 0x92, 0x55, 0xc1, 0x53, 0x02, + 0x8a, 0x78, 0xb5, 0x45, 0x10, 0xf1, 0x22, 0x39, 0x78, 0xf0, 0xb6, 0x8d, 0x63, 0x0c, 0x6d, 0x76, + 0x43, 0x76, 0x53, 0xa8, 0x7f, 0xd1, 0x3f, 0x25, 0xc9, 0x66, 0x63, 0x30, 0x5e, 0x7a, 0x9b, 0x79, + 0xcc, 0xfb, 0x66, 0xf6, 0x2d, 0x1c, 0xf2, 0x38, 0x96, 0xa5, 0xd0, 0x2a, 0xc8, 0x0b, 0xa9, 0x25, + 0xba, 0xb6, 0x67, 0x0c, 0x46, 0x11, 0x25, 0xa9, 0xd2, 0x54, 0x3c, 0x89, 0x0f, 0x89, 0x08, 0x3b, + 0x82, 0x67, 0xe4, 0x39, 0x67, 0xce, 0xd5, 0x7e, 0x54, 0xd7, 0x0c, 0x61, 0x6c, 0x67, 0x22, 0x52, + 0xb9, 0x14, 0x8a, 0xd8, 0x0b, 0x8c, 0x1e, 0xb8, 0xe6, 0xcf, 0xb4, 0x7e, 0xe5, 0xcb, 0x92, 0xd0, + 0x83, 0x61, 0xc3, 0x6c, 0xac, 0xb6, 0xc5, 0x31, 0x0c, 0x16, 0xb4, 0xf6, 0xb6, 0x6b, 0xb5, 0x2a, + 0xf1, 0x18, 0x76, 0x57, 0x95, 0xc9, 0x1b, 0xd4, 0x9a, 0x69, 0xd8, 0x04, 0x8e, 0x1a, 0x62, 0xbb, + 0xe4, 0x16, 0x86, 0x8d, 0xb4, 0x09, 0x9f, 0x5d, 0x98, 0xdb, 0x2c, 0xe6, 0xff, 0x7d, 0xd7, 0xdf, + 0x0e, 0xc0, 0xd4, 0x30, 0xb8, 0xd0, 0x78, 0x0f, 0xae, 0x7d, 0x24, 0x9e, 0x04, 0x6d, 0x5e, 0xdd, + 0x70, 0x7c, 0xbf, 0xaf, 0xb7, 0xb7, 0x6e, 0xe1, 0x0c, 0x0e, 0xa6, 0x4a, 0xa5, 0x89, 0x30, 0x89, + 0x74, 0x20, 0xdd, 0xa4, 0xfc, 0xd3, 0x9e, 0xde, 0x61, 0xdc, 0x81, 0xfb, 0x48, 0xda, 0x00, 0x26, + 0xbd, 0x41, 0xff, 0x0f, 0xf3, 0xd7, 0x38, 0xbb, 0x7c, 0x3b, 0x4f, 0x52, 0xfd, 0x59, 0xce, 0x83, + 0x58, 0x66, 0x61, 0xf6, 0x9e, 0x2e, 0xcb, 0xaf, 0xb0, 0x90, 0x2b, 0x0a, 0xf3, 0x45, 0x12, 0x5a, + 0xd7, 0x7c, 0xaf, 0xfe, 0xff, 0x9b, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x22, 0x35, 0x31, 0x6f, + 0x11, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -381,7 +329,7 @@ type AccountantClient interface { // It will return an error if the account already exists Register(ctx context.Context, in *RegisterInfo, opts ...grpc.CallOption) (*RegisterResponse, error) // AssignValue assigns a key-value pair to an account, or overwrites an existing key - AssignValue(ctx context.Context, in *DataKeyValue, opts ...grpc.CallOption) (*Response, error) + AssignValue(ctx context.Context, in *DataKeyValue, opts ...grpc.CallOption) (*DataKeyResponse, error) // GetValue will get the value for a key for an account GetValue(ctx context.Context, in *DataKey, opts ...grpc.CallOption) (*DataResponse, error) } @@ -403,8 +351,8 @@ func (c *accountantClient) Register(ctx context.Context, in *RegisterInfo, opts return out, nil } -func (c *accountantClient) AssignValue(ctx context.Context, in *DataKeyValue, opts ...grpc.CallOption) (*Response, error) { - out := new(Response) +func (c *accountantClient) AssignValue(ctx context.Context, in *DataKeyValue, opts ...grpc.CallOption) (*DataKeyResponse, error) { + out := new(DataKeyResponse) err := c.cc.Invoke(ctx, "/accounts.Accountant/AssignValue", in, out, opts...) if err != nil { return nil, err @@ -427,7 +375,7 @@ type AccountantServer interface { // It will return an error if the account already exists Register(context.Context, *RegisterInfo) (*RegisterResponse, error) // AssignValue assigns a key-value pair to an account, or overwrites an existing key - AssignValue(context.Context, *DataKeyValue) (*Response, error) + AssignValue(context.Context, *DataKeyValue) (*DataKeyResponse, error) // GetValue will get the value for a key for an account GetValue(context.Context, *DataKey) (*DataResponse, error) } @@ -439,7 +387,7 @@ type UnimplementedAccountantServer struct { func (*UnimplementedAccountantServer) Register(ctx context.Context, req *RegisterInfo) (*RegisterResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") } -func (*UnimplementedAccountantServer) AssignValue(ctx context.Context, req *DataKeyValue) (*Response, error) { +func (*UnimplementedAccountantServer) AssignValue(ctx context.Context, req *DataKeyValue) (*DataKeyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AssignValue not implemented") } func (*UnimplementedAccountantServer) GetValue(ctx context.Context, req *DataKey) (*DataResponse, error) { diff --git a/pkg/accounts/accounts.proto b/pkg/accounts/accounts.proto index 90ba7e1..50f0dd6 100644 --- a/pkg/accounts/accounts.proto +++ b/pkg/accounts/accounts.proto @@ -10,7 +10,7 @@ service Accountant { rpc Register(RegisterInfo) returns (RegisterResponse) {} // AssignValue assigns a key-value pair to an account, or overwrites an existing key - rpc AssignValue(DataKeyValue) returns (Response) {} + rpc AssignValue(DataKeyValue) returns (DataKeyResponse) {} // GetValue will get the value for a key for an account rpc GetValue(DataKey) returns (DataResponse) {} @@ -23,11 +23,7 @@ message RegisterInfo { } // RegisterResponse is the response information from registering an account -message RegisterResponse { - // The error value should only be populated if success is false - bool success = 1; - string error = 2; -} +message RegisterResponse {} // DataKeyValue represents a simple key value pair to assign to an account message DataKeyValue { @@ -39,12 +35,8 @@ message DataKeyValue { string value = 3; } -// Response is a simple response with success and error -message Response { - // error should only be populated if success is false - bool success = 1; - string error = 2; -} +// DataKeyResponse is a simple response +message DataKeyResponse {} // DataKey describes a simple key value with an account, for fetching message DataKey { @@ -57,10 +49,6 @@ message DataKey { // DataResponse describes a data fetch response message DataResponse { - // error should only be populated if success is false - bool success = 1; - string error = 2; - // The value of the key string value = 3; } diff --git a/pkg/atlas/atlas.go b/pkg/atlas/atlas.go index 66a2baa..f6c63f6 100644 --- a/pkg/atlas/atlas.go +++ b/pkg/atlas/atlas.go @@ -12,7 +12,7 @@ import ( // Chunk represents a fixed square grid of tiles type Chunk struct { // Tiles represents the tiles within the chunk - Tiles []Tile `json:"tiles"` + Tiles []byte `json:"tiles"` } // Atlas represents a grid of Chunks @@ -43,7 +43,7 @@ func NewAtlas(size, chunkSize int) Atlas { // Initialise all the chunks for i := range a.Chunks { a.Chunks[i] = Chunk{ - Tiles: make([]Tile, chunkSize*chunkSize), + Tiles: make([]byte, chunkSize*chunkSize), } } @@ -90,7 +90,7 @@ func (a *Atlas) SpawnWalls() error { } // SetTile sets an individual tile's kind -func (a *Atlas) SetTile(v vector.Vector, tile Tile) error { +func (a *Atlas) SetTile(v vector.Vector, tile byte) error { chunk := a.toChunk(v) if chunk >= len(a.Chunks) { return fmt.Errorf("location outside of allocated atlas") @@ -106,7 +106,7 @@ func (a *Atlas) SetTile(v vector.Vector, tile Tile) error { } // GetTile will return an individual tile -func (a *Atlas) GetTile(v vector.Vector) (Tile, error) { +func (a *Atlas) GetTile(v vector.Vector) (byte, error) { chunk := a.toChunk(v) if chunk >= len(a.Chunks) { return 0, fmt.Errorf("location outside of allocated atlas") diff --git a/pkg/atlas/atlas_test.go b/pkg/atlas/atlas_test.go index a9c7021..9d74138 100644 --- a/pkg/atlas/atlas_test.go +++ b/pkg/atlas/atlas_test.go @@ -81,13 +81,13 @@ func TestAtlas_GetSetTile(t *testing.T) { assert.NoError(t, a.SetTile(vector.Vector{X: 0, Y: 0}, 1)) tile, err := a.GetTile(vector.Vector{X: 0, Y: 0}) assert.NoError(t, err) - assert.Equal(t, Tile(1), tile) + assert.Equal(t, byte(1), tile) // Set another tile to 1 and test it assert.NoError(t, a.SetTile(vector.Vector{X: 5, Y: -2}, 2)) tile, err = a.GetTile(vector.Vector{X: 5, Y: -2}) assert.NoError(t, err) - assert.Equal(t, Tile(2), tile) + assert.Equal(t, byte(2), tile) } func TestAtlas_Grown(t *testing.T) { @@ -108,15 +108,15 @@ func TestAtlas_Grown(t *testing.T) { tile, err := a.GetTile(vector.Vector{X: 0, Y: 0}) assert.NoError(t, err) - assert.Equal(t, Tile(1), tile) + assert.Equal(t, byte(1), tile) tile, err = a.GetTile(vector.Vector{X: -1, Y: -1}) assert.NoError(t, err) - assert.Equal(t, Tile(2), tile) + assert.Equal(t, byte(2), tile) tile, err = a.GetTile(vector.Vector{X: 1, Y: -2}) assert.NoError(t, err) - assert.Equal(t, Tile(3), tile) + assert.Equal(t, byte(3), tile) // Grow it again even bigger err = a.Grow(10) @@ -125,15 +125,15 @@ func TestAtlas_Grown(t *testing.T) { tile, err = a.GetTile(vector.Vector{X: 0, Y: 0}) assert.NoError(t, err) - assert.Equal(t, Tile(1), tile) + assert.Equal(t, byte(1), tile) tile, err = a.GetTile(vector.Vector{X: -1, Y: -1}) assert.NoError(t, err) - assert.Equal(t, Tile(2), tile) + assert.Equal(t, byte(2), tile) tile, err = a.GetTile(vector.Vector{X: 1, Y: -2}) assert.NoError(t, err) - assert.Equal(t, Tile(3), tile) + assert.Equal(t, byte(3), tile) } func TestAtlas_SpawnWorld(t *testing.T) { diff --git a/pkg/atlas/tile.go b/pkg/atlas/tile.go index af44e87..2897647 100644 --- a/pkg/atlas/tile.go +++ b/pkg/atlas/tile.go @@ -1,12 +1,9 @@ package atlas -// Tile represents the type of a tile on the map -type Tile byte - const ( - TileEmpty = Tile(0) - TileRover = Tile(1) + TileEmpty = byte(0) + TileRover = byte(1) - TileWall = Tile(2) - TileRock = Tile(3) + TileWall = byte(2) + TileRock = byte(3) ) diff --git a/pkg/game/command_test.go b/pkg/game/command_test.go index c1fabcc..439d2f3 100644 --- a/pkg/game/command_test.go +++ b/pkg/game/command_test.go @@ -22,7 +22,7 @@ func TestCommand_Move(t *testing.T) { err = world.WarpRover(a, pos) assert.NoError(t, err, "Failed to set position for rover") - duration := 1 + var duration = 1 // Try the move command moveCommand := Command{Command: CommandMove, Bearing: "N", Duration: duration} assert.NoError(t, world.Enqueue(a, moveCommand), "Failed to execute move command") @@ -33,6 +33,6 @@ func TestCommand_Move(t *testing.T) { newatributes, err := world.RoverAttributes(a) assert.NoError(t, err, "Failed to set position for rover") - pos.Add(vector.Vector{X: 0.0, Y: duration * attribs.Speed}) // We should have moved duration*speed north + pos.Add(vector.Vector{X: 0.0, Y: int(duration) * int(attribs.Speed)}) // We should have moved duration*speed north assert.Equal(t, pos, newatributes.Pos, "Failed to correctly set position for rover") } diff --git a/pkg/game/world.go b/pkg/game/world.go index 1880b74..af0af11 100644 --- a/pkg/game/world.go +++ b/pkg/game/world.go @@ -225,7 +225,7 @@ func (w *World) MoveRover(id uuid.UUID, b bearing.Bearing) (RoverAttributes, err } // RadarFromRover can be used to query what a rover can currently see -func (w *World) RadarFromRover(id uuid.UUID) ([]atlas.Tile, error) { +func (w *World) RadarFromRover(id uuid.UUID) ([]byte, error) { w.worldMutex.RLock() defer w.worldMutex.RUnlock() @@ -256,7 +256,7 @@ func (w *World) RadarFromRover(id uuid.UUID) ([]atlas.Tile, error) { } // Gather up all tiles within the range - var radar = make([]atlas.Tile, radarSpan*radarSpan) + var radar = make([]byte, radarSpan*radarSpan) for j := scanMin.Y; j <= scanMax.Y; j++ { for i := scanMin.X; i <= scanMax.X; i++ { q := vector.Vector{X: i, Y: j} @@ -381,7 +381,7 @@ func (w *World) ExecuteCommand(c *Command, rover uuid.UUID) (finished bool, err } // PrintTiles simply prints the input tiles directly for debug -func PrintTiles(tiles []atlas.Tile) { +func PrintTiles(tiles []byte) { num := int(math.Sqrt(float64(len(tiles)))) for j := num - 1; j >= 0; j-- { for i := 0; i < num; i++ { diff --git a/pkg/rove/api.go b/pkg/rove/api.go deleted file mode 100644 index 4c258bc..0000000 --- a/pkg/rove/api.go +++ /dev/null @@ -1,94 +0,0 @@ -package rove - -import ( - "path" - - "github.com/mdiluz/rove/pkg/atlas" - "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"` - Tick int `json:"tick"` - NextTick string `json:"nexttick,omitempty"` -} - -// ============================== -// API: /register method: POST - -// Register registers a user by name -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 { - // Placeholder for future information -} - -// ============================== -// API: /{account}/command method: POST - -// Command issues a set of commands from the user -func (s Server) Command(account string, d CommandData) (r CommandResponse, err error) { - err = s.Post(path.Join(account, "command"), d, &r) - return -} - -// CommandData is a set of commands to execute in order -type CommandData struct { - Commands []game.Command `json:"commands"` -} - -// CommandResponse is the response to be sent back -type CommandResponse struct { - // Placeholder for future information -} - -// ================ -// API: /{account}/radar method: GET - -// Radar queries the current radar for the user -func (s Server) Radar(account string) (r RadarResponse, err error) { - err = s.Get(path.Join(account, "radar"), &r) - return -} - -// RadarResponse describes the response to a /radar call -type RadarResponse struct { - // The set of positions for nearby non-empty tiles - Range int `json:"range"` - Tiles []atlas.Tile `json:"tiles"` -} - -// ================ -// API: /{account}/rover method: GET - -// Rover queries the current state of the rover -func (s Server) Rover(account string) (r RoverResponse, err error) { - err = s.Get(path.Join(account, "rover"), &r) - return -} - -// RoverResponse includes information about the rover in question -type RoverResponse struct { - // The current position of this rover - Attributes game.RoverAttributes `json:"attributes"` -} diff --git a/pkg/rove/http.go b/pkg/rove/http.go deleted file mode 100644 index 37c16b9..0000000 --- a/pkg/rove/http.go +++ /dev/null @@ -1,73 +0,0 @@ -package rove - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "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 { - u := url.URL{ - Scheme: "http", - Host: string(s), - Path: path, - } - if resp, err := http.Get(u.String()); err != nil { - return err - - } else if resp.StatusCode != http.StatusOK { - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("failed to read response body to code %d", resp.StatusCode) - } - return fmt.Errorf("http returned status %d: %s", resp.StatusCode, string(body)) - - } else { - return json.NewDecoder(resp.Body).Decode(out) - } -} - -// Post performs a Post request -func (s Server) Post(path string, in, out interface{}) error { - u := 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", u.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 { - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf("failed to read response body to code %d", resp.StatusCode) - } - return fmt.Errorf("http returned status %d: %s", resp.StatusCode, string(body)) - - } else { - return json.NewDecoder(resp.Body).Decode(out) - } -} diff --git a/pkg/rove/rove.pb.go b/pkg/rove/rove.pb.go new file mode 100644 index 0000000..a9d0f02 --- /dev/null +++ b/pkg/rove/rove.pb.go @@ -0,0 +1,821 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: rove.proto + +package rove + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + empty "github.com/golang/protobuf/ptypes/empty" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Command struct { + // The command to execute, currently only accepts move, which requires a bearing and a duration. + Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` + Bearing string `protobuf:"bytes,2,opt,name=bearing,proto3" json:"bearing,omitempty"` + Duration int32 `protobuf:"varint,3,opt,name=duration,proto3" json:"duration,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Command) Reset() { *m = Command{} } +func (m *Command) String() string { return proto.CompactTextString(m) } +func (*Command) ProtoMessage() {} +func (*Command) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{0} +} + +func (m *Command) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Command.Unmarshal(m, b) +} +func (m *Command) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Command.Marshal(b, m, deterministic) +} +func (m *Command) XXX_Merge(src proto.Message) { + xxx_messageInfo_Command.Merge(m, src) +} +func (m *Command) XXX_Size() int { + return xxx_messageInfo_Command.Size(m) +} +func (m *Command) XXX_DiscardUnknown() { + xxx_messageInfo_Command.DiscardUnknown(m) +} + +var xxx_messageInfo_Command proto.InternalMessageInfo + +func (m *Command) GetCommand() string { + if m != nil { + return m.Command + } + return "" +} + +func (m *Command) GetBearing() string { + if m != nil { + return m.Bearing + } + return "" +} + +func (m *Command) GetDuration() int32 { + if m != nil { + return m.Duration + } + return 0 +} + +type CommandsRequest struct { + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` + Commands []*Command `protobuf:"bytes,2,rep,name=commands,proto3" json:"commands,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CommandsRequest) Reset() { *m = CommandsRequest{} } +func (m *CommandsRequest) String() string { return proto.CompactTextString(m) } +func (*CommandsRequest) ProtoMessage() {} +func (*CommandsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{1} +} + +func (m *CommandsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CommandsRequest.Unmarshal(m, b) +} +func (m *CommandsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CommandsRequest.Marshal(b, m, deterministic) +} +func (m *CommandsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CommandsRequest.Merge(m, src) +} +func (m *CommandsRequest) XXX_Size() int { + return xxx_messageInfo_CommandsRequest.Size(m) +} +func (m *CommandsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CommandsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CommandsRequest proto.InternalMessageInfo + +func (m *CommandsRequest) GetAccount() string { + if m != nil { + return m.Account + } + return "" +} + +func (m *CommandsRequest) GetCommands() []*Command { + if m != nil { + return m.Commands + } + return nil +} + +type Error struct { + // An explanation for the HTTP error returned + Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Error) Reset() { *m = Error{} } +func (m *Error) String() string { return proto.CompactTextString(m) } +func (*Error) ProtoMessage() {} +func (*Error) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{2} +} + +func (m *Error) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Error.Unmarshal(m, b) +} +func (m *Error) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Error.Marshal(b, m, deterministic) +} +func (m *Error) XXX_Merge(src proto.Message) { + xxx_messageInfo_Error.Merge(m, src) +} +func (m *Error) XXX_Size() int { + return xxx_messageInfo_Error.Size(m) +} +func (m *Error) XXX_DiscardUnknown() { + xxx_messageInfo_Error.DiscardUnknown(m) +} + +var xxx_messageInfo_Error proto.InternalMessageInfo + +func (m *Error) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +type RadarRequest struct { + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RadarRequest) Reset() { *m = RadarRequest{} } +func (m *RadarRequest) String() string { return proto.CompactTextString(m) } +func (*RadarRequest) ProtoMessage() {} +func (*RadarRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{3} +} + +func (m *RadarRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RadarRequest.Unmarshal(m, b) +} +func (m *RadarRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RadarRequest.Marshal(b, m, deterministic) +} +func (m *RadarRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RadarRequest.Merge(m, src) +} +func (m *RadarRequest) XXX_Size() int { + return xxx_messageInfo_RadarRequest.Size(m) +} +func (m *RadarRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RadarRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RadarRequest proto.InternalMessageInfo + +func (m *RadarRequest) GetAccount() string { + if m != nil { + return m.Account + } + return "" +} + +type RadarResponse struct { + // The range in tiles from the rover of the radar data + Range int32 `protobuf:"varint,1,opt,name=range,proto3" json:"range,omitempty"` + // A 1D array representing range*2 + 1 squared set of tiles, origin bottom left and in row->column order + Tiles []byte `protobuf:"bytes,2,opt,name=tiles,proto3" json:"tiles,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RadarResponse) Reset() { *m = RadarResponse{} } +func (m *RadarResponse) String() string { return proto.CompactTextString(m) } +func (*RadarResponse) ProtoMessage() {} +func (*RadarResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{4} +} + +func (m *RadarResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RadarResponse.Unmarshal(m, b) +} +func (m *RadarResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RadarResponse.Marshal(b, m, deterministic) +} +func (m *RadarResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RadarResponse.Merge(m, src) +} +func (m *RadarResponse) XXX_Size() int { + return xxx_messageInfo_RadarResponse.Size(m) +} +func (m *RadarResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RadarResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RadarResponse proto.InternalMessageInfo + +func (m *RadarResponse) GetRange() int32 { + if m != nil { + return m.Range + } + return 0 +} + +func (m *RadarResponse) GetTiles() []byte { + if m != nil { + return m.Tiles + } + return nil +} + +type RegisterRequest struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RegisterRequest) Reset() { *m = RegisterRequest{} } +func (m *RegisterRequest) String() string { return proto.CompactTextString(m) } +func (*RegisterRequest) ProtoMessage() {} +func (*RegisterRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{5} +} + +func (m *RegisterRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RegisterRequest.Unmarshal(m, b) +} +func (m *RegisterRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RegisterRequest.Marshal(b, m, deterministic) +} +func (m *RegisterRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisterRequest.Merge(m, src) +} +func (m *RegisterRequest) XXX_Size() int { + return xxx_messageInfo_RegisterRequest.Size(m) +} +func (m *RegisterRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RegisterRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RegisterRequest proto.InternalMessageInfo + +func (m *RegisterRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type RoverRequest struct { + Account string `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RoverRequest) Reset() { *m = RoverRequest{} } +func (m *RoverRequest) String() string { return proto.CompactTextString(m) } +func (*RoverRequest) ProtoMessage() {} +func (*RoverRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{6} +} + +func (m *RoverRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RoverRequest.Unmarshal(m, b) +} +func (m *RoverRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RoverRequest.Marshal(b, m, deterministic) +} +func (m *RoverRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoverRequest.Merge(m, src) +} +func (m *RoverRequest) XXX_Size() int { + return xxx_messageInfo_RoverRequest.Size(m) +} +func (m *RoverRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RoverRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RoverRequest proto.InternalMessageInfo + +func (m *RoverRequest) GetAccount() string { + if m != nil { + return m.Account + } + return "" +} + +type RoverResponse struct { + // The name of the rover + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Position of the rover in world coordinates + Position *Vector `protobuf:"bytes,2,opt,name=position,proto3" json:"position,omitempty"` + // The range of this rover's radar + Range int32 `protobuf:"varint,3,opt,name=range,proto3" json:"range,omitempty"` + // The speed the rover can move per tick + Speed int32 `protobuf:"varint,4,opt,name=speed,proto3" json:"speed,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RoverResponse) Reset() { *m = RoverResponse{} } +func (m *RoverResponse) String() string { return proto.CompactTextString(m) } +func (*RoverResponse) ProtoMessage() {} +func (*RoverResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{7} +} + +func (m *RoverResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RoverResponse.Unmarshal(m, b) +} +func (m *RoverResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RoverResponse.Marshal(b, m, deterministic) +} +func (m *RoverResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoverResponse.Merge(m, src) +} +func (m *RoverResponse) XXX_Size() int { + return xxx_messageInfo_RoverResponse.Size(m) +} +func (m *RoverResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RoverResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RoverResponse proto.InternalMessageInfo + +func (m *RoverResponse) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *RoverResponse) GetPosition() *Vector { + if m != nil { + return m.Position + } + return nil +} + +func (m *RoverResponse) GetRange() int32 { + if m != nil { + return m.Range + } + return 0 +} + +func (m *RoverResponse) GetSpeed() int32 { + if m != nil { + return m.Speed + } + return 0 +} + +type StatusResponse struct { + // The time the next tick will occur + NextTick string `protobuf:"bytes,1,opt,name=next_tick,json=nextTick,proto3" json:"next_tick,omitempty"` + // Whether the server is ready to accept requests + Ready bool `protobuf:"varint,2,opt,name=ready,proto3" json:"ready,omitempty"` + // The tick rate of the server in minutes (how many minutes per tick) + Tick int32 `protobuf:"varint,3,opt,name=tick,proto3" json:"tick,omitempty"` + // The version of the server in v{major}.{minor}-{delta}-{sha} form + Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatusResponse) Reset() { *m = StatusResponse{} } +func (m *StatusResponse) String() string { return proto.CompactTextString(m) } +func (*StatusResponse) ProtoMessage() {} +func (*StatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{8} +} + +func (m *StatusResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StatusResponse.Unmarshal(m, b) +} +func (m *StatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StatusResponse.Marshal(b, m, deterministic) +} +func (m *StatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatusResponse.Merge(m, src) +} +func (m *StatusResponse) XXX_Size() int { + return xxx_messageInfo_StatusResponse.Size(m) +} +func (m *StatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatusResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StatusResponse proto.InternalMessageInfo + +func (m *StatusResponse) GetNextTick() string { + if m != nil { + return m.NextTick + } + return "" +} + +func (m *StatusResponse) GetReady() bool { + if m != nil { + return m.Ready + } + return false +} + +func (m *StatusResponse) GetTick() int32 { + if m != nil { + return m.Tick + } + return 0 +} + +func (m *StatusResponse) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +type Vector struct { + X int32 `protobuf:"varint,1,opt,name=x,proto3" json:"x,omitempty"` + Y int32 `protobuf:"varint,2,opt,name=y,proto3" json:"y,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Vector) Reset() { *m = Vector{} } +func (m *Vector) String() string { return proto.CompactTextString(m) } +func (*Vector) ProtoMessage() {} +func (*Vector) Descriptor() ([]byte, []int) { + return fileDescriptor_cea399972d1e9fa7, []int{9} +} + +func (m *Vector) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Vector.Unmarshal(m, b) +} +func (m *Vector) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Vector.Marshal(b, m, deterministic) +} +func (m *Vector) XXX_Merge(src proto.Message) { + xxx_messageInfo_Vector.Merge(m, src) +} +func (m *Vector) XXX_Size() int { + return xxx_messageInfo_Vector.Size(m) +} +func (m *Vector) XXX_DiscardUnknown() { + xxx_messageInfo_Vector.DiscardUnknown(m) +} + +var xxx_messageInfo_Vector proto.InternalMessageInfo + +func (m *Vector) GetX() int32 { + if m != nil { + return m.X + } + return 0 +} + +func (m *Vector) GetY() int32 { + if m != nil { + return m.Y + } + return 0 +} + +func init() { + proto.RegisterType((*Command)(nil), "rove.Command") + proto.RegisterType((*CommandsRequest)(nil), "rove.CommandsRequest") + proto.RegisterType((*Error)(nil), "rove.Error") + proto.RegisterType((*RadarRequest)(nil), "rove.RadarRequest") + proto.RegisterType((*RadarResponse)(nil), "rove.RadarResponse") + proto.RegisterType((*RegisterRequest)(nil), "rove.RegisterRequest") + proto.RegisterType((*RoverRequest)(nil), "rove.RoverRequest") + proto.RegisterType((*RoverResponse)(nil), "rove.RoverResponse") + proto.RegisterType((*StatusResponse)(nil), "rove.StatusResponse") + proto.RegisterType((*Vector)(nil), "rove.Vector") +} + +func init() { + proto.RegisterFile("rove.proto", fileDescriptor_cea399972d1e9fa7) +} + +var fileDescriptor_cea399972d1e9fa7 = []byte{ + // 477 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x5d, 0x6b, 0xdb, 0x30, + 0x14, 0x8d, 0x93, 0x38, 0x75, 0x6f, 0x92, 0x15, 0xb4, 0x6e, 0x98, 0x94, 0x41, 0x10, 0x1b, 0x64, + 0x2f, 0x2e, 0x64, 0x2f, 0x83, 0x3e, 0x8e, 0xfe, 0x01, 0x75, 0x14, 0xf6, 0x34, 0x14, 0xfb, 0xce, + 0x98, 0x36, 0x96, 0x2b, 0xc9, 0x21, 0xf9, 0x49, 0xfb, 0x97, 0x43, 0xba, 0xb2, 0x97, 0x94, 0x8d, + 0xf6, 0xed, 0x9e, 0xab, 0xab, 0x73, 0xce, 0xfd, 0x00, 0xd0, 0x6a, 0x87, 0x59, 0xa3, 0x95, 0x55, + 0x6c, 0xec, 0xe2, 0xc5, 0x55, 0xa9, 0x54, 0xf9, 0x88, 0xd7, 0x3e, 0xb7, 0x69, 0x7f, 0x5d, 0xe3, + 0xb6, 0xb1, 0x07, 0x2a, 0xe1, 0x3f, 0xe0, 0xec, 0x9b, 0xda, 0x6e, 0x65, 0x5d, 0xb0, 0x14, 0xce, + 0x72, 0x0a, 0xd3, 0x68, 0x19, 0xad, 0xce, 0x45, 0x07, 0xdd, 0xcb, 0x06, 0xa5, 0xae, 0xea, 0x32, + 0x1d, 0xd2, 0x4b, 0x80, 0x6c, 0x01, 0x49, 0xd1, 0x6a, 0x69, 0x2b, 0x55, 0xa7, 0xa3, 0x65, 0xb4, + 0x8a, 0x45, 0x8f, 0xf9, 0x3d, 0x5c, 0x04, 0x6a, 0x23, 0xf0, 0xa9, 0x45, 0x63, 0x1d, 0x91, 0xcc, + 0x73, 0xd5, 0xd6, 0xb6, 0x93, 0x08, 0x90, 0x7d, 0x86, 0x24, 0xa8, 0x99, 0x74, 0xb8, 0x1c, 0xad, + 0xa6, 0xeb, 0x79, 0xe6, 0x3b, 0x09, 0x14, 0xa2, 0x7f, 0xe6, 0x1f, 0x20, 0xbe, 0xd5, 0x5a, 0x69, + 0x76, 0x09, 0x31, 0xba, 0x20, 0x70, 0x11, 0xe0, 0x2b, 0x98, 0x09, 0x59, 0x48, 0xfd, 0xa2, 0x26, + 0xbf, 0x81, 0x79, 0xa8, 0x34, 0x8d, 0xaa, 0x0d, 0x3a, 0x42, 0x2d, 0xeb, 0x12, 0x7d, 0x61, 0x2c, + 0x08, 0xb8, 0xac, 0xad, 0x1e, 0xd1, 0xf8, 0xde, 0x67, 0x82, 0x00, 0xff, 0x04, 0x17, 0x02, 0xcb, + 0xca, 0x58, 0xec, 0x95, 0x18, 0x8c, 0x6b, 0xb9, 0xc5, 0x20, 0xe3, 0x63, 0xef, 0x46, 0xed, 0xf0, + 0x15, 0x6e, 0x0e, 0x30, 0x0f, 0x95, 0xc1, 0xcd, 0x3f, 0xe8, 0xd8, 0x0a, 0x92, 0x46, 0x99, 0xca, + 0xcf, 0xdb, 0xd9, 0x99, 0xae, 0x67, 0x34, 0xa6, 0x7b, 0xcc, 0xad, 0xd2, 0xa2, 0x7f, 0xfd, 0xdb, + 0xcb, 0xe8, 0x59, 0x2f, 0xa6, 0x41, 0x2c, 0xd2, 0x31, 0x65, 0x3d, 0xe0, 0x4f, 0xf0, 0xe6, 0xce, + 0x4a, 0xdb, 0x9a, 0x5e, 0xfb, 0x0a, 0xce, 0x6b, 0xdc, 0xdb, 0x9f, 0xb6, 0xca, 0x1f, 0x82, 0x81, + 0xc4, 0x25, 0xbe, 0x57, 0xf9, 0x83, 0xa7, 0x46, 0x59, 0x1c, 0xbc, 0x83, 0x44, 0x10, 0x70, 0x76, + 0x7d, 0x35, 0xe9, 0xf9, 0xd8, 0x75, 0xbb, 0x43, 0x6d, 0x9c, 0xdb, 0x31, 0x75, 0x1b, 0x20, 0xff, + 0x08, 0x13, 0xb2, 0xcc, 0x66, 0x10, 0xed, 0xc3, 0xc0, 0xa3, 0xbd, 0x43, 0xc4, 0x1b, 0x8b, 0xe8, + 0xb0, 0xfe, 0x3d, 0x84, 0xa9, 0x1f, 0xca, 0x1d, 0xea, 0x1d, 0x6a, 0x76, 0x03, 0x49, 0x77, 0x52, + 0xec, 0xdd, 0xc9, 0x7d, 0x74, 0x27, 0xb6, 0x78, 0x9f, 0xd1, 0xb9, 0x67, 0xdd, 0xb9, 0x67, 0xb7, + 0xee, 0xdc, 0xf9, 0x80, 0xad, 0x21, 0xf6, 0xeb, 0x66, 0x8c, 0x7e, 0x1e, 0x5f, 0xc9, 0xe2, 0xed, + 0x49, 0x8e, 0xa6, 0xc0, 0x07, 0x4e, 0xb0, 0xdb, 0x72, 0x27, 0xf8, 0x6c, 0xeb, 0x2f, 0x08, 0x3a, + 0xf3, 0xbd, 0xe0, 0xd1, 0x21, 0xf4, 0x82, 0xc7, 0x2b, 0xe7, 0x03, 0xf6, 0x15, 0x26, 0xb4, 0x0a, + 0xf6, 0x1f, 0xde, 0xc5, 0x25, 0x7d, 0x3c, 0x5d, 0x18, 0x1f, 0x6c, 0x26, 0xbe, 0xee, 0xcb, 0x9f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xed, 0x84, 0x22, 0xdd, 0x01, 0x04, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// RoverServerClient is the client API for RoverServer service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type RoverServerClient interface { + // Send commands to rover + // + // Sending commands to this endpoint will queue them to be executed during the following ticks, in the order sent + Commands(ctx context.Context, in *CommandsRequest, opts ...grpc.CallOption) (*empty.Empty, error) + // Get radar information + // + // Gets the radar output for the given rover + Radar(ctx context.Context, in *RadarRequest, opts ...grpc.CallOption) (*RadarResponse, error) + // Register an account + // + // Tries to register an account with the given name + Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*empty.Empty, error) + // Get rover information + // + // Gets information for the account's rover + Rover(ctx context.Context, in *RoverRequest, opts ...grpc.CallOption) (*RoverResponse, error) + // Server status + // + // Responds with various details about the current server status + Status(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*StatusResponse, error) +} + +type roverServerClient struct { + cc grpc.ClientConnInterface +} + +func NewRoverServerClient(cc grpc.ClientConnInterface) RoverServerClient { + return &roverServerClient{cc} +} + +func (c *roverServerClient) Commands(ctx context.Context, in *CommandsRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/rove.RoverServer/Commands", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *roverServerClient) Radar(ctx context.Context, in *RadarRequest, opts ...grpc.CallOption) (*RadarResponse, error) { + out := new(RadarResponse) + err := c.cc.Invoke(ctx, "/rove.RoverServer/Radar", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *roverServerClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/rove.RoverServer/Register", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *roverServerClient) Rover(ctx context.Context, in *RoverRequest, opts ...grpc.CallOption) (*RoverResponse, error) { + out := new(RoverResponse) + err := c.cc.Invoke(ctx, "/rove.RoverServer/Rover", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *roverServerClient) Status(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*StatusResponse, error) { + out := new(StatusResponse) + err := c.cc.Invoke(ctx, "/rove.RoverServer/Status", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// RoverServerServer is the server API for RoverServer service. +type RoverServerServer interface { + // Send commands to rover + // + // Sending commands to this endpoint will queue them to be executed during the following ticks, in the order sent + Commands(context.Context, *CommandsRequest) (*empty.Empty, error) + // Get radar information + // + // Gets the radar output for the given rover + Radar(context.Context, *RadarRequest) (*RadarResponse, error) + // Register an account + // + // Tries to register an account with the given name + Register(context.Context, *RegisterRequest) (*empty.Empty, error) + // Get rover information + // + // Gets information for the account's rover + Rover(context.Context, *RoverRequest) (*RoverResponse, error) + // Server status + // + // Responds with various details about the current server status + Status(context.Context, *empty.Empty) (*StatusResponse, error) +} + +// UnimplementedRoverServerServer can be embedded to have forward compatible implementations. +type UnimplementedRoverServerServer struct { +} + +func (*UnimplementedRoverServerServer) Commands(ctx context.Context, req *CommandsRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Commands not implemented") +} +func (*UnimplementedRoverServerServer) Radar(ctx context.Context, req *RadarRequest) (*RadarResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Radar not implemented") +} +func (*UnimplementedRoverServerServer) Register(ctx context.Context, req *RegisterRequest) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") +} +func (*UnimplementedRoverServerServer) Rover(ctx context.Context, req *RoverRequest) (*RoverResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Rover not implemented") +} +func (*UnimplementedRoverServerServer) Status(ctx context.Context, req *empty.Empty) (*StatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") +} + +func RegisterRoverServerServer(s *grpc.Server, srv RoverServerServer) { + s.RegisterService(&_RoverServer_serviceDesc, srv) +} + +func _RoverServer_Commands_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CommandsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoverServerServer).Commands(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/rove.RoverServer/Commands", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoverServerServer).Commands(ctx, req.(*CommandsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RoverServer_Radar_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RadarRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoverServerServer).Radar(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/rove.RoverServer/Radar", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoverServerServer).Radar(ctx, req.(*RadarRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RoverServer_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoverServerServer).Register(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/rove.RoverServer/Register", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoverServerServer).Register(ctx, req.(*RegisterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RoverServer_Rover_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RoverRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoverServerServer).Rover(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/rove.RoverServer/Rover", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoverServerServer).Rover(ctx, req.(*RoverRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RoverServer_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(empty.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RoverServerServer).Status(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/rove.RoverServer/Status", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RoverServerServer).Status(ctx, req.(*empty.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +var _RoverServer_serviceDesc = grpc.ServiceDesc{ + ServiceName: "rove.RoverServer", + HandlerType: (*RoverServerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Commands", + Handler: _RoverServer_Commands_Handler, + }, + { + MethodName: "Radar", + Handler: _RoverServer_Radar_Handler, + }, + { + MethodName: "Register", + Handler: _RoverServer_Register_Handler, + }, + { + MethodName: "Rover", + Handler: _RoverServer_Rover_Handler, + }, + { + MethodName: "Status", + Handler: _RoverServer_Status_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "rove.proto", +} diff --git a/pkg/rove/rove.proto b/pkg/rove/rove.proto new file mode 100644 index 0000000..a4ce6b7 --- /dev/null +++ b/pkg/rove/rove.proto @@ -0,0 +1,103 @@ +syntax = "proto3"; + +package rove; + +import "google/protobuf/empty.proto"; + +service RoverServer { + // Send commands to rover + // + // Sending commands to this endpoint will queue them to be executed during the following ticks, in the order sent + rpc Commands(CommandsRequest) returns (google.protobuf.Empty) {} + + // Get radar information + // + // Gets the radar output for the given rover + rpc Radar(RadarRequest) returns (RadarResponse) {} + + // Register an account + // + // Tries to register an account with the given name + rpc Register(RegisterRequest) returns (google.protobuf.Empty) {} + + // Get rover information + // + // Gets information for the account's rover + rpc Rover(RoverRequest) returns (RoverResponse) {} + + // Server status + // + // Responds with various details about the current server status + rpc Status(google.protobuf.Empty) returns (StatusResponse) {} +} + +message Command { + // The command to execute, currently only accepts move, which requires a bearing and a duration. + string command = 1; + + string bearing = 2; + int32 duration = 3; +} + +message CommandsRequest { + string account = 1; + repeated Command commands = 2; +} + +message Error { + // An explanation for the HTTP error returned + string error = 1; +} + +message RadarRequest { + string account = 1; +} + +message RadarResponse { + // The range in tiles from the rover of the radar data + int32 range = 1; + + // A 1D array representing range*2 + 1 squared set of tiles, origin bottom left and in row->column order + bytes tiles = 2; +} + +message RegisterRequest { + string name = 1; +} + +message RoverRequest { + string account = 1; +} + +message RoverResponse { + // The name of the rover + string name = 1; + + // Position of the rover in world coordinates + Vector position = 2; + + // The range of this rover's radar + int32 range = 3; + + // The speed the rover can move per tick + int32 speed = 4; +} + +message StatusResponse { + // The time the next tick will occur + string next_tick = 1; + + // Whether the server is ready to accept requests + bool ready = 2; + + // The tick rate of the server in minutes (how many minutes per tick) + int32 tick = 3; + + // The version of the server in v{major}.{minor}-{delta}-{sha} form + string version = 4; +} + +message Vector { + int32 x = 1; + int32 y = 2; +} \ No newline at end of file diff --git a/swagger.yml b/swagger.yml deleted file mode 100644 index 8f9e9d7..0000000 --- a/swagger.yml +++ /dev/null @@ -1,246 +0,0 @@ -swagger: "2.0" -info: - description: "Rove is an asychronous nomadic game about exploring a planet as part of a loose community" - version: "0.1" - title: "Rove Server" -host: "api.rove-game.com:8080" -basePath: "/" -tags: -- name: "server" - description: "Interactions with the server itself" -- name: "accounts" - description: "Access to accounts" -- name: "rove" - description: "Operations for the game" -schemes: -- "http" -consumes: - - application/json -produces: - - application/json -paths: - /status: - get: - tags: - - "server" - summary: "Server status" - description: "Responds with various details about the current server status" - operationId: "Status" - responses: - "200": - description: "Server is active" - schema: - $ref: '#/definitions/status' - /register: - post: - tags: - - "accounts" - summary: "Register an account" - description: "Tries to register an account with the given name" - operationId: "Register" - parameters: - - in: body - name: name - schema: - $ref: '#/definitions/register-data' - responses: - "200": - description: "Successfully created account" - "400": - description: "Bad request, typically due to duplicate name" - schema: - $ref: '#/definitions/error' - "500": - description: "Server encountered error, please report this as a bug" - schema: - $ref: '#/definitions/error' - - /{account}/commands: - post: - tags: - - rove - summary: Send commands to rover - description: "Sending commands to this endpoint will queue them to be executed during the following ticks, in the order sent" - operationId: "Commands" - parameters: - - in: path - name: account - required: true - type: string - - in: body - name: commands - schema: - $ref: '#/definitions/commands-data' - responses: - "200": - description: "Successfully queued commands" - "400": - description: "Bad request, typically due to unknown command parameters" - schema: - $ref: '#/definitions/error' - "500": - description: "Server encountered error, please report this as a bug" - schema: - $ref: '#/definitions/error' - - /{account}/radar: - get: - tags: - - rove - summary: Get radar information - description: "Gets the radar output for the given rover" - operationId: "Radar" - parameters: - - in: path - name: account - required: true - type: string - responses: - "200": - description: "Successfully returned rover radar" - schema: - $ref: '#/definitions/radar-response' - "400": - description: "Bad request, typically due to unknown account" - schema: - $ref: '#/definitions/error' - "500": - description: "Server encountered error, please report this as a bug" - schema: - $ref: '#/definitions/error' - - /{account}/rover: - get: - tags: - - rove - summary: Get rover information - description: "Gets information for the account's rover" - operationId: "Rover" - parameters: - - in: path - name: account - required: true - type: string - responses: - "200": - description: "Successfully returned rover information" - schema: - $ref: '#/definitions/rover-response' - "400": - description: "Bad request, typically due to unknown account" - schema: - $ref: '#/definitions/error' - "500": - description: "Server encountered error, please report this as a bug" - schema: - $ref: '#/definitions/error' - -definitions: - status: - properties: - ready: - description: Whether the server is ready to accept requests - type: boolean - example: true - version: - description: The version of the server in v{major}.{minor}-{delta}-{sha} form - type: string - example: "v0.12-1-g7d1a2d7" - tick: - description: The tick rate of the server in minutes (how many minutes per tick) - type: integer - example: 5 - nexttick: - description: The time the next tick will occur - type: string - example: "15:30:00" - - error: - properties: - error: - description: An explanation for the HTTP error returned - type: string - example: "account not found" - - register-data: - properties: - name: - description: The account name - type: string - example: "myname" - required: - - name - - command: - properties: - command: - description: "The command to execute, currently only accepts move, which requires a bearing and a duration." - type: string - example: move - bearing: - type: string - example: NE - duration: - type: integer - example: 5 - - commands-data: - properties: - commands: - description: A set of commands to exectute in the order given - type: array - items: - type: object - properties: - schema: - $ref: '#/definitions/command' - - radar-response: - properties: - range: - description: The range in tiles from the rover of the radar data - type: integer - example: 5 - tiles: - description: A 1D array representing range*2 + 1 squared set of tiles, origin bottom left and in row->column order - type: array - items: - type: integer - - vector: - properties: - 'x': - type: integer - example: 1 - 'y': - type: integer - example: 2 - - rover-attributes: - properties: - speed: - description: The speed the rover can move per tick - type: integer - example: 1 - range: - description: The range of this rover's radar - type: integer - example: 5 - name: - description: The name of the rover - type: string - example: rover-one - position: - description: Position of the rover in world coordinates - type: object - properties: - schema: - $ref: '#/definitions/vector' - - rover-response: - properties: - attributes: - description: The attributes of the given rover - type: object - $ref: '#/definitions/rover-attributes' -