rove/cmd/rove/main.go
Marc Di Luzio 7749854eb7 Remove account IDs in favor of just account names
These were a "security" feature but pre-emptive and just add complications when we can implement secrets later
2020-06-10 18:57:43 +01:00

226 lines
5.3 KiB
Go

package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"path"
"github.com/mdiluz/rove/pkg/game"
"github.com/mdiluz/rove/pkg/rove"
"github.com/mdiluz/rove/pkg/version"
)
var USAGE = ""
// Command usage
func Usage() {
fmt.Fprintf(os.Stderr, "Usage: %s COMMAND [OPTIONS]...\n", os.Args[0])
fmt.Fprintln(os.Stderr, "\nCommands:")
fmt.Fprintln(os.Stderr, "\tstatus \tprints the server status")
fmt.Fprintln(os.Stderr, "\tregister\tregisters an account and stores it (use with -name)")
fmt.Fprintln(os.Stderr, "\tmove \tissues move command to rover")
fmt.Fprintln(os.Stderr, "\tradar \tgathers radar data for the current rover")
fmt.Fprintln(os.Stderr, "\trover \tgets data for current rover")
fmt.Fprintln(os.Stderr, "\nOptions:")
flag.PrintDefaults()
}
var home = os.Getenv("HOME")
var filepath = path.Join(home, ".local/share/rove.json")
// General usage
var ver = flag.Bool("version", false, "Display version number")
var host = flag.String("host", "", "path to game host server")
var data = flag.String("data", filepath, "data file for storage")
// For register command
var name = flag.String("name", "", "used with status command for the account name")
// For the duration command
var duration = flag.Int("duration", 1, "used for the move command duration")
var bearing = flag.String("bearing", "", "used for the move command bearing (compass direction)")
// Config is used to store internal data
type Config struct {
Host string `json:"host,omitempty"`
Accounts map[string]string `json:"accounts,omitempty"`
}
// verifyId will verify an account ID
func verifyId(id string) error {
if len(id) == 0 {
return fmt.Errorf("no account ID set, must register first")
}
return nil
}
// InnerMain wraps the main function so we can test it
func InnerMain(command string) error {
// Load in the persistent file
var config = Config{
Accounts: make(map[string]string),
}
_, err := os.Stat(*data)
if !os.IsNotExist(err) {
if b, err := ioutil.ReadFile(*data); err != nil {
return fmt.Errorf("failed to read file %s error: %s", *data, err)
} else if len(b) == 0 {
return fmt.Errorf("file %s was empty, assumin fresh data", *data)
} else if err := json.Unmarshal(b, &config); err != nil {
return fmt.Errorf("failed to unmarshal file %s error: %s", *data, err)
}
}
// If there's a host set on the command line, override the one in the config
if len(*host) != 0 {
config.Host = *host
}
// If there's still no host, bail
if len(config.Host) == 0 {
return fmt.Errorf("no host set, please set one with -host")
}
// Set up the server
var server = rove.Server(config.Host)
// Grab the account
var account = config.Accounts[config.Host]
// Print the config info
fmt.Printf("host: %s\taccount: %s\n", config.Host, account)
// Handle all the commands
switch command {
case "status":
response, err := server.Status()
switch {
case err != nil:
return err
default:
fmt.Printf("Ready: %t\n", response.Ready)
fmt.Printf("Version: %s\n", response.Version)
fmt.Printf("Tick: %d\n", response.Tick)
fmt.Printf("Next Tick: %s\n", response.NextTick)
}
case "register":
d := rove.RegisterData{
Name: *name,
}
response, err := server.Register(d)
switch {
case err != nil:
return err
case !response.Success:
return fmt.Errorf("Server returned failure: %s", response.Error)
default:
fmt.Printf("Registered account with id: %s\n", d.Name)
config.Accounts[config.Host] = d.Name
}
case "move":
d := rove.CommandData{
Commands: []game.Command{
{
Command: game.CommandMove,
Duration: *duration,
Bearing: *bearing,
},
},
}
if err := verifyId(account); err != nil {
return err
}
response, err := server.Command(account, d)
switch {
case err != nil:
return err
case !response.Success:
return fmt.Errorf("Server returned failure: %s", response.Error)
default:
fmt.Printf("Request succeeded\n")
}
case "radar":
if err := verifyId(account); err != nil {
return err
}
response, err := server.Radar(account)
switch {
case err != nil:
return err
case !response.Success:
return fmt.Errorf("Server returned failure: %s", response.Error)
default:
// Print out the radar
game.PrintTiles(response.Tiles)
}
case "rover":
if err := verifyId(account); err != nil {
return err
}
response, err := server.Rover(account)
switch {
case err != nil:
return err
case !response.Success:
return fmt.Errorf("Server returned failure: %s", response.Error)
default:
fmt.Printf("attributes: %+v\n", response.Attributes)
}
default:
// Print the usage
fmt.Fprintf(os.Stderr, "Unknown command: %s\n", command)
Usage()
}
// Save out the persistent file
if b, err := json.MarshalIndent(config, "", "\t"); err != nil {
return fmt.Errorf("failed to marshal data error: %s", err)
} else if err := ioutil.WriteFile(*data, b, os.ModePerm); err != nil {
return fmt.Errorf("failed to save file %s error: %s", *data, err)
}
return nil
}
// Simple main
func main() {
flag.Usage = Usage
flag.CommandLine.Parse(os.Args[2:])
// Print the version if requested
if *ver {
fmt.Println(version.Version)
return
}
// Run the inner main
if err := InnerMain(os.Args[1]); err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
os.Exit(1)
}
}