Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Superstack CLI

`superstack` is the command line interface to Superstack: log in, create
fleets, pair devices, and manage who can reach them. It is a single static
fleets, manage devices, and control who can reach them. It is a single static
binary for managing Superstack from a terminal.

Uploading Lua code and streaming logs are not available yet.
Expand Down
10 changes: 5 additions & 5 deletions internal/account/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func Balance(invocation api.Invocation, arguments []string) error {
balances := []api.BalanceEntry{}

for _, balance := range fetched {
if chosenFleetId == 0 || balance.Fleet == chosenFleetId {
if chosenFleetId == 0 || balance.FleetId == chosenFleetId {
balances = append(balances, balance)
}
}
Expand All @@ -87,7 +87,7 @@ func Balance(invocation api.Invocation, arguments []string) error {
amountValues := make([]string, len(balances))

for index, balance := range balances {
name, known := fleetNames[balance.Fleet]
name, known := fleetNames[balance.FleetId]

if !known {
name = "-"
Expand All @@ -97,14 +97,14 @@ func Balance(invocation api.Invocation, arguments []string) error {

nameValues[index] = api.Printable(name)
amountValues[index] = api.Printable(formatted)
idWidth = max(idWidth, len(strconv.FormatInt(balance.Fleet, 10)))
idWidth = max(idWidth, len(strconv.FormatInt(balance.FleetId, 10)))
nameWidth = max(nameWidth, len(nameValues[index]))
}

fmt.Fprintf(invocation.Out, "%-*s %-*s %s\n", idWidth, "ID", nameWidth, "NAME", "BALANCE")

for index, balance := range balances {
fmt.Fprintf(invocation.Out, "%-*d %-*s %s\n", idWidth, balance.Fleet, nameWidth, nameValues[index], amountValues[index])
fmt.Fprintf(invocation.Out, "%-*d %-*s %s\n", idWidth, balance.FleetId, nameWidth, nameValues[index], amountValues[index])
}

return nil
Expand All @@ -122,7 +122,7 @@ func TopUp(invocation api.Invocation, arguments []string) error {
}

request, err := api.AuthenticatedRequest(invocation, http.MethodPost,
"/fleets/"+strconv.FormatInt(fleetId, 10)+"/topup", nil)
"/fleets/"+strconv.FormatInt(fleetId, 10)+"/top-ups", nil)

if err != nil {
return err
Expand Down
26 changes: 13 additions & 13 deletions internal/account/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,38 @@ func TestAccountBalance(t *testing.T) {
name: "every fleet",
arguments: []string{},
fleets: `[{"id":1,"name":"crew","owner":true},{"id":2,"name":"pilot","owner":false}]`,
balances: `[{"fleet":1,"balance":"15.000000","currency":"eur"},{"fleet":2,"balance":"0","currency":"eur"}]`,
balances: `[{"fleet_id":1,"balance":"15.000000","currency":"eur"},{"fleet_id":2,"balance":"0","currency":"eur"}]`,
wantLines: []string{"ID", "NAME", "BALANCE", "crew", "€15.00", "pilot", "€0.00"},
},
{
name: "one fleet",
arguments: []string{"2"},
fleets: `[{"id":1,"name":"crew","owner":true},{"id":2,"name":"pilot","owner":false}]`,
balances: `[{"fleet":1,"balance":"15.000000","currency":"eur"},{"fleet":2,"balance":"0","currency":"eur"}]`,
balances: `[{"fleet_id":1,"balance":"15.000000","currency":"eur"},{"fleet_id":2,"balance":"0","currency":"eur"}]`,
wantLines: []string{"pilot", "€0.00"},
wantAbsent: []string{"crew"},
},
{
name: "a fleet name with control characters is escaped",
arguments: []string{},
fleets: `[{"id":1,"name":"\u001b[2Kquiet","owner":true}]`,
balances: `[{"fleet":1,"balance":"15.000000","currency":"eur"}]`,
balances: `[{"fleet_id":1,"balance":"15.000000","currency":"eur"}]`,
wantLines: []string{`\x1b[2Kquiet`},
wantAbsent: []string{"\x1b"},
},
{
name: "machine readable",
arguments: []string{"--json"},
fleets: `[{"id":1,"name":"crew","owner":true}]`,
balances: `[{"fleet":1,"balance":"15.000000","currency":"eur"}]`,
wantExact: `[{"fleet":1,"balance":"15.000000","currency":"eur"}]` + "\n",
balances: `[{"fleet_id":1,"balance":"15.000000","currency":"eur"}]`,
wantExact: `[{"fleet_id":1,"balance":"15.000000","currency":"eur"}]` + "\n",
},
{
name: "machine readable for one fleet",
arguments: []string{"2", "--json"},
fleets: `[{"id":1,"name":"crew","owner":true},{"id":2,"name":"pilot","owner":false}]`,
balances: `[{"fleet":1,"balance":"15.000000","currency":"eur"},{"fleet":2,"balance":"0","currency":"eur"}]`,
wantExact: `[{"fleet":2,"balance":"0","currency":"eur"}]` + "\n",
balances: `[{"fleet_id":1,"balance":"15.000000","currency":"eur"},{"fleet_id":2,"balance":"0","currency":"eur"}]`,
wantExact: `[{"fleet_id":2,"balance":"0","currency":"eur"}]` + "\n",
},
{
name: "machine readable with no fleets",
Expand All @@ -86,7 +86,7 @@ func TestAccountBalance(t *testing.T) {
name: "a fleet the list does not name",
arguments: []string{},
fleets: `[{"id":1,"name":"crew","owner":true}]`,
balances: `[{"fleet":99,"balance":"15.000000","currency":"eur"}]`,
balances: `[{"fleet_id":99,"balance":"15.000000","currency":"eur"}]`,
wantLines: []string{"99 -"},
},
{
Expand Down Expand Up @@ -184,13 +184,13 @@ func TestAccountTopUp(t *testing.T) {
name: "the top-up page opened on enter",
arguments: []string{"3"},
stdin: "\n",
wantPath: "/fleets/3/topup",
wantPath: "/fleets/3/top-ups",
wantBrowser: true,
},
{
name: "the top-up page left alone",
arguments: []string{"3"},
wantPath: "/fleets/3/topup",
wantPath: "/fleets/3/top-ups",
},
{
name: "no fleet id",
Expand All @@ -210,14 +210,14 @@ func TestAccountTopUp(t *testing.T) {
{
name: "response has no url",
arguments: []string{"3"},
wantPath: "/fleets/3/topup",
wantPath: "/fleets/3/top-ups",
emptyBody: true,
wantError: "could not open the top-up page, try again",
},
{
name: "the server refuses",
arguments: []string{"9"},
wantPath: "/fleets/9/topup",
wantPath: "/fleets/9/top-ups",
refusal: "no such fleet",
wantError: "no such fleet",
},
Expand All @@ -227,7 +227,7 @@ func TestAccountTopUp(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
mux := http.NewServeMux()

mux.HandleFunc("POST /fleets/{id}/topup", func(w http.ResponseWriter, r *http.Request) {
mux.HandleFunc("POST /fleets/{id}/top-ups", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != test.wantPath {
t.Errorf("the request went to %s, want %s", r.URL.Path, test.wantPath)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func TestFetchFleetKeysFailures(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
mux := http.NewServeMux()
mux.HandleFunc("GET /keys", func(w http.ResponseWriter, r *http.Request) {
mux.HandleFunc("GET /fleet-keys", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(test.status)
fmt.Fprint(w, test.body)
})
Expand Down
2 changes: 1 addition & 1 deletion internal/api/balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

type BalanceEntry struct {
Fleet int64 `json:"fleet"`
FleetId int64 `json:"fleet_id"`
Balance string `json:"balance"`
Currency string `json:"currency"`
}
Expand Down
37 changes: 6 additions & 31 deletions internal/api/devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ import (
)

type DeviceEntry struct {
Imei string `json:"imei"`
Name *string `json:"name"`
FleetId int64 `json:"fleet_id"`
LastSeenAt *string `json:"last_seen_at"`
RunState *int `json:"run_state"`
StorageUsed *int64 `json:"storage_used"`
StorageTotal *int64 `json:"storage_total"`
Imei string `json:"imei"`
Name *string `json:"name"`
FleetId int64 `json:"fleet_id"`
LastSeenAt *string `json:"last_seen_at"`
}

func FetchDevices(invocation Invocation) ([]DeviceEntry, error) {
Expand All @@ -34,35 +31,13 @@ func FetchDevices(invocation Invocation) ([]DeviceEntry, error) {
return nil, ServerError(response)
}

serverDevices := []struct {
Imei string `json:"imei"`
Name *string `json:"name"`
FleetId int64 `json:"fleet_id"`
LastSeenAt *string `json:"last_seen_at"`
RunState *int `json:"reported_state"`
StorageUsed *int64 `json:"storage_used"`
StorageTotal *int64 `json:"storage_total"`
}{}
devices := []DeviceEntry{}

err = Decode(response, &serverDevices)
err = Decode(response, &devices)

if err != nil {
return nil, err
}

devices := make([]DeviceEntry, len(serverDevices))

for index, device := range serverDevices {
devices[index] = DeviceEntry{
Imei: device.Imei,
Name: device.Name,
FleetId: device.FleetId,
LastSeenAt: device.LastSeenAt,
RunState: device.RunState,
StorageUsed: device.StorageUsed,
StorageTotal: device.StorageTotal,
}
}

return devices, nil
}
10 changes: 5 additions & 5 deletions internal/api/fleet_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import (
)

type FleetKeyEntry struct {
Id int64 `json:"id"`
Fleet int64 `json:"fleet"`
Label string `json:"label"`
Suffix string `json:"suffix"`
Id int64 `json:"id"`
FleetId int64 `json:"fleet_id"`
Label string `json:"label"`
FleetKeySuffix string `json:"fleet_key_suffix"`
}

func FetchFleetKeys(invocation Invocation) ([]FleetKeyEntry, error) {
request, err := AuthenticatedRequest(invocation, http.MethodGet, "/keys", nil)
request, err := AuthenticatedRequest(invocation, http.MethodGet, "/fleet-keys", nil)

if err != nil {
return nil, err
Expand Down
Loading