checkpoint: updated main

This commit is contained in:
Dan Anglin 2024-09-19 11:34:51 +01:00
parent 70faf8366a
commit b6088bfd88
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638

159
main.go
View file

@ -2,14 +2,13 @@ package main
import ( import (
"bufio" "bufio"
"context"
"encoding/json"
"fmt" "fmt"
"maps" "maps"
"net/http"
"os" "os"
"slices" "slices"
"time" "time"
"codeflow.dananglin.me.uk/apollo/pokedex/internal/pokeclient"
) )
const ( const (
@ -27,40 +26,22 @@ var state State
type command struct { type command struct {
name string name string
description string description string
callback func() error callback callbackFunc
} }
type callbackFunc func() error
func main() { func main() {
run() run()
} }
func run() { func run() {
fmt.Print("pokedex > ") client := pokeclient.NewClient(
5*time.Minute,
10*time.Second,
)
scanner := bufio.NewScanner(os.Stdin) commandMap := map[string]command{
for scanner.Scan() {
command := scanner.Text()
cmdMap := getCommandMap()
if _, ok := cmdMap[command]; !ok {
fmt.Println("ERROR: Unrecognised command.")
fmt.Print("\npokedex > ")
continue
}
if err := cmdMap[command].callback(); err != nil {
fmt.Printf("ERROR: %v.\n", err)
}
fmt.Print("pokedex > ")
}
}
func getCommandMap() map[string]command {
return map[string]command{
"exit": { "exit": {
name: "exit", name: "exit",
description: "Exit the Pokedex", description: "Exit the Pokedex",
@ -69,41 +50,81 @@ func getCommandMap() map[string]command {
"help": { "help": {
name: "help", name: "help",
description: "Displays a help message", description: "Displays a help message",
callback: commandHelp, callback: nil,
}, },
"map": { "map": {
name: "map", name: "map",
description: "Displays the next 20 locations in the Pokemon world", description: "Displays the next 20 locations in the Pokemon world",
callback: commandMap, callback: commandMap(client),
}, },
"mapb": { "mapb": {
name: "map back", name: "map back",
description: "Displays the previous 20 locations in the Pokemon world", description: "Displays the previous 20 locations in the Pokemon world",
callback: commandMapB, callback: commandMapB(client),
}, },
} }
summaries := summaryMap(commandMap)
commandMap["help"] = command{
name: "help",
description: "Displays a help message",
callback: commandHelp(summaries),
}
fmt.Printf("\nWelcome to the Pokedex!\n")
fmt.Print("\npokedex > ")
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
command := scanner.Text()
cmd, ok := commandMap[command]
if !ok {
fmt.Println("ERROR: Unrecognised command.")
fmt.Print("\npokedex > ")
continue
}
if cmd.callback == nil {
fmt.Println("ERROR: This command is defined but does not have a callback function.")
fmt.Print("\npokedex > ")
continue
}
if err := commandMap[command].callback(); err != nil {
fmt.Printf("ERROR: %v.\n", err)
}
fmt.Print("pokedex > ")
}
} }
func commandHelp() error { func commandHelp(summaries map[string]string) callbackFunc {
cmdMap := getCommandMap() return func() error {
keys := []string{} keys := []string{}
for key := range maps.All(cmdMap) { for key := range maps.All(summaries) {
keys = append(keys, key) keys = append(keys, key)
} }
slices.Sort(keys) slices.Sort(keys)
fmt.Printf("\nWelcome to the Pokedex!\nUsage:\n") fmt.Printf("\nCommands:\n")
for _, key := range slices.All(keys) { for _, key := range slices.All(keys) {
fmt.Printf("\n%s: %s", key, cmdMap[key].description) fmt.Printf("\n%s: %s", key, summaries[key])
} }
fmt.Println("\n") fmt.Printf("\n\n")
return nil return nil
}
} }
func commandExit() error { func commandExit() error {
@ -112,63 +133,51 @@ func commandExit() error {
return nil return nil
} }
func commandMap() error { func commandMap(client *pokeclient.Client) callbackFunc {
return func() error {
url := state.Next url := state.Next
if url == nil { if url == nil {
url = new(string) url = new(string)
*url = baseURL + locationAreaEndpoint *url = baseURL + locationAreaEndpoint
} }
return printMap(*url) return printResourceList(client, *url)
}
} }
func commandMapB() error { func commandMapB(client *pokeclient.Client) callbackFunc {
return func() error {
url := state.Previous url := state.Previous
if url == nil { if url == nil {
return fmt.Errorf("no previous locations available") return fmt.Errorf("no previous locations available")
} }
return printMap(*url) return printResourceList(client, *url)
}
} }
func printMap(url string) error { func printResourceList(client *pokeclient.Client, url string) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) list, err := client.GetNamedAPIResourceList(url)
defer cancel()
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil { if err != nil {
return fmt.Errorf("error creating the HTTP request: %w", err) return fmt.Errorf("unable to get the list of resources: %w", err)
} }
client := http.Client{} state.Next = list.Next
state.Previous = list.Previous
resp, err := client.Do(request) for _, location := range slices.All(list.Results) {
if err != nil {
return fmt.Errorf("error getting the response from the server: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return fmt.Errorf(
"received a bad status from %s: (%d) %s",
url,
resp.StatusCode,
resp.Status,
)
}
var result NamedAPIResourceList
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return fmt.Errorf("unable to decode the JSON response: %w", err)
}
state.Next = result.Next
state.Previous = result.Previous
for _, location := range slices.All(result.Results) {
fmt.Println(location.Name) fmt.Println(location.Name)
} }
return nil return nil
} }
func summaryMap(commandMap map[string]command) map[string]string {
summaries := make(map[string]string)
for key, value := range maps.All(commandMap) {
summaries[key] = value.description
}
return summaries
}