169 lines
4.9 KiB
Go
169 lines
4.9 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/mdiluz/rove/pkg/version"
|
|
"github.com/mdiluz/rove/proto/roveapi"
|
|
)
|
|
|
|
// ServerStatus returns the status of the current server to a gRPC request
|
|
func (s *Server) ServerStatus(context.Context, *roveapi.ServerStatusRequest) (*roveapi.ServerStatusResponse, error) {
|
|
response := &roveapi.ServerStatusResponse{
|
|
Ready: true,
|
|
Version: version.Version,
|
|
TickRate: int32(s.minutesPerTick),
|
|
CurrentTick: int32(s.world.CurrentTicks),
|
|
}
|
|
|
|
// 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")
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// Register registers a new account for a gRPC request
|
|
func (s *Server) Register(ctx context.Context, req *roveapi.RegisterRequest) (*roveapi.RegisterResponse, error) {
|
|
log.Printf("Handling register request: %s\n", req.Name)
|
|
|
|
if len(req.Name) == 0 {
|
|
return nil, fmt.Errorf("empty account name")
|
|
}
|
|
|
|
if acc, err := s.world.Accountant.RegisterAccount(req.Name); err != nil {
|
|
return nil, err
|
|
|
|
} 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 {
|
|
return nil, fmt.Errorf("internal server error when saving world: %s", err)
|
|
|
|
} else {
|
|
return &roveapi.RegisterResponse{
|
|
Account: &roveapi.Account{
|
|
Name: acc.Name,
|
|
Secret: acc.Data["secret"],
|
|
},
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
// Status returns rover information for a gRPC request
|
|
func (s *Server) Status(ctx context.Context, req *roveapi.StatusRequest) (response *roveapi.StatusResponse, err error) {
|
|
log.Printf("Handling status request: %s\n", req.Account.Name)
|
|
|
|
if valid, err := s.world.Accountant.VerifySecret(req.Account.Name, req.Account.Secret); err != nil {
|
|
return nil, err
|
|
|
|
} else if !valid {
|
|
return nil, fmt.Errorf("Secret incorrect for account %s", req.Account.Name)
|
|
|
|
} else if resp, err := s.world.Accountant.GetValue(req.Account.Name, "rover"); err != nil {
|
|
return nil, err
|
|
|
|
} else if rover, err := s.world.GetRover(resp); err != nil {
|
|
return nil, fmt.Errorf("error getting rover: %s", err)
|
|
|
|
} else {
|
|
var inv []byte
|
|
for _, i := range rover.Inventory {
|
|
inv = append(inv, byte(i.Type))
|
|
}
|
|
|
|
queued := s.world.RoverCommands(resp)
|
|
var logs []*roveapi.Log
|
|
for _, log := range rover.Logs {
|
|
logs = append(logs, &roveapi.Log{
|
|
Text: log.Text,
|
|
Time: fmt.Sprintf("%d", log.Time.Unix()), // proto uses strings under the hood for 64bit ints anyway
|
|
})
|
|
}
|
|
|
|
response = &roveapi.StatusResponse{
|
|
Readings: &roveapi.RoverReadings{
|
|
Position: &roveapi.Vector{
|
|
X: int32(rover.Pos.X),
|
|
Y: int32(rover.Pos.Y),
|
|
},
|
|
Logs: logs,
|
|
Wind: s.world.Wind,
|
|
},
|
|
Spec: &roveapi.RoverSpecifications{
|
|
Name: rover.Name,
|
|
Range: int32(rover.Range),
|
|
Capacity: int32(rover.Capacity),
|
|
MaximumIntegrity: int32(rover.MaximumIntegrity),
|
|
MaximumCharge: int32(rover.MaximumCharge),
|
|
},
|
|
Status: &roveapi.RoverStatus{
|
|
Bearing: rover.Bearing,
|
|
Inventory: inv,
|
|
Integrity: int32(rover.Integrity),
|
|
Charge: int32(rover.Charge),
|
|
QueuedCommands: queued,
|
|
SailPosition: rover.SailPosition,
|
|
},
|
|
}
|
|
}
|
|
return response, nil
|
|
}
|
|
|
|
// Radar returns the radar information for a rover
|
|
func (s *Server) Radar(ctx context.Context, req *roveapi.RadarRequest) (*roveapi.RadarResponse, error) {
|
|
log.Printf("Handling radar request: %s\n", req.Account.Name)
|
|
|
|
if valid, err := s.world.Accountant.VerifySecret(req.Account.Name, req.Account.Secret); err != nil {
|
|
return nil, err
|
|
|
|
} else if !valid {
|
|
return nil, fmt.Errorf("Secret incorrect for account %s", req.Account.Name)
|
|
}
|
|
|
|
response := &roveapi.RadarResponse{}
|
|
|
|
resp, err := s.world.Accountant.GetValue(req.Account.Name, "rover")
|
|
if err != nil {
|
|
return nil, err
|
|
|
|
} else if rover, err := s.world.GetRover(resp); err != nil {
|
|
return nil, fmt.Errorf("error getting rover attributes: %s", err)
|
|
|
|
} else if radar, objs, err := s.world.RadarFromRover(resp); err != nil {
|
|
return nil, fmt.Errorf("error getting radar from rover: %s", err)
|
|
|
|
} else {
|
|
response.Objects = objs
|
|
response.Tiles = radar
|
|
response.Range = int32(rover.Range)
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// Command issues commands to the world based on a gRPC request
|
|
func (s *Server) Command(ctx context.Context, req *roveapi.CommandRequest) (*roveapi.CommandResponse, error) {
|
|
log.Printf("Handling command request: %s and %+v\n", req.Account.Name, req.Commands)
|
|
|
|
if valid, err := s.world.Accountant.VerifySecret(req.Account.Name, req.Account.Secret); err != nil {
|
|
return nil, err
|
|
|
|
} else if !valid {
|
|
return nil, fmt.Errorf("Secret incorrect for account %s", req.Account.Name)
|
|
}
|
|
|
|
resp, err := s.world.Accountant.GetValue(req.Account.Name, "rover")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := s.world.Enqueue(resp, req.Commands...); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &roveapi.CommandResponse{}, nil
|
|
}
|