diff options
author | Julien Dessaux | 2025-02-13 21:35:32 +0100 |
---|---|---|
committer | Julien Dessaux | 2025-02-13 21:35:32 +0100 |
commit | 3dad3f60f280289dee1b34ae04744f244d070bf7 (patch) | |
tree | 2e3d5ba10b1ac104708f557a520146f47fd6bf1f /golang | |
parent | [golang] update for registration API breaking changes (diff) | |
download | spacetraders-3dad3f60f280289dee1b34ae04744f244d070bf7.tar.gz spacetraders-3dad3f60f280289dee1b34ae04744f244d070bf7.tar.bz2 spacetraders-3dad3f60f280289dee1b34ae04744f244d070bf7.zip |
[golang] Bootstrap contracting and refactor the agent code
Diffstat (limited to '')
-rw-r--r-- | golang/cmd/spacetraders/main.go | 77 | ||||
-rw-r--r-- | golang/pkg/agent/agent.go | 26 | ||||
-rw-r--r-- | golang/pkg/agent/run.go | 78 | ||||
-rw-r--r-- | golang/pkg/api/contracts.go | 17 | ||||
-rw-r--r-- | golang/pkg/api/ships.go | 11 | ||||
-rw-r--r-- | golang/pkg/database/agents.go | 19 | ||||
-rw-r--r-- | golang/pkg/database/sql/001_trading.sql | 4 | ||||
-rw-r--r-- | golang/pkg/model/contract.go | 32 |
8 files changed, 158 insertions, 106 deletions
diff --git a/golang/cmd/spacetraders/main.go b/golang/cmd/spacetraders/main.go index d21e64b..bae6c27 100644 --- a/golang/cmd/spacetraders/main.go +++ b/golang/cmd/spacetraders/main.go @@ -2,12 +2,12 @@ package main import ( "context" - "errors" "fmt" "log/slog" "os" "os/signal" + "git.adyxax.org/adyxax/spacetraders/golang/pkg/agent" "git.adyxax.org/adyxax/spacetraders/golang/pkg/api" "git.adyxax.org/adyxax/spacetraders/golang/pkg/database" ) @@ -37,7 +37,7 @@ func main() { apiClient := api.NewClient(ctx) defer apiClient.Close() - if err := run( + if err := agent.Run( apiClient, db, os.Getenv, @@ -49,76 +49,3 @@ func main() { os.Exit(2) } } - -func run( - apiClient *api.Client, - db *database.DB, - getenv func(string) string, -) error { - accountToken := getenv("SPACETRADERS_ACCOUNT_TOKEN") - if accountToken == "" { - return fmt.Errorf("the SPACETRADERS_ACCOUNT_TOKEN environment variable is not set") - } - agent := getenv("SPACETRADERS_AGENT") - if agent == "" { - return fmt.Errorf("the SPACETRADERS_AGENT environment variable is not set") - } - faction := getenv("SPACETRADERS_FACTION") - if faction == "" { - return fmt.Errorf("the SPACETRADERS_FACTION environment variable is not set") - } - // ----- Get token or register --------------------------------------------- - apiClient.SetToken(accountToken) - register, err := apiClient.Register(faction, agent) - if err != nil { - apiError := &api.APIError{} - if errors.As(err, &apiError) { - switch apiError.Code { - case 4111: // Agent symbol has already been claimed - token, err := db.GetToken() - if err != nil || token == "" { - return fmt.Errorf("failed to register and failed to get a token from the database: someone stole our agent's callsign: %w", err) - } - apiClient.SetToken(token) - agent, err := apiClient.MyAgent() - if err != nil { - return fmt.Errorf("failed to get agent: %w", err) - } - slog.Info("agent", "/my/agent", agent) - default: - return fmt.Errorf("failed to register: %w", err) - } - } else { - return fmt.Errorf("failed to register with an invalid apiError: %w", err) - } - } else { - token, err := db.GetToken() - if err != nil || token == "" { - if err := db.AddToken(register.Token); err != nil { - return fmt.Errorf("failed to save token: %w", err) - } - apiClient.SetToken(register.Token) - } else { - // We successfully registered but have a tainted database - slog.Error("token", "token", register.Token) - return fmt.Errorf("TODO server reset not implemented yet") - } - } - // ----- run agent --------------------------------------------------------- - ships, err := apiClient.MyShips() - if err != nil { - return err - } - slog.Info("start", "ship", ships[0].Nav.Status, "err", err) - err = apiClient.Orbit(&ships[0]) - if err != nil { - return err - } - slog.Info("orbit", "ship", ships[0].Nav.Status, "err", err) - err = apiClient.Dock(&ships[0]) - if err != nil { - return err - } - slog.Info("dock", "ship", ships[0].Nav.Status, "err", err) - return nil -} diff --git a/golang/pkg/agent/agent.go b/golang/pkg/agent/agent.go deleted file mode 100644 index cf96bef..0000000 --- a/golang/pkg/agent/agent.go +++ /dev/null @@ -1,26 +0,0 @@ -package agent - -import ( - "sync" - - "git.adyxax.org/adyxax/spacetraders/golang/pkg/model" -) - -type Agent struct { - data *model.Agent - mutex sync.Mutex -} - -var agent Agent - -func GetAgent() *model.Agent { - agent.mutex.Lock() - defer agent.mutex.Unlock() - return agent.data -} - -func SetAgent(data *model.Agent) { - agent.mutex.Lock() - defer agent.mutex.Unlock() - agent.data = data -} diff --git a/golang/pkg/agent/run.go b/golang/pkg/agent/run.go new file mode 100644 index 0000000..db4c614 --- /dev/null +++ b/golang/pkg/agent/run.go @@ -0,0 +1,78 @@ +package agent + +import ( + "errors" + "fmt" + "log/slog" + + "git.adyxax.org/adyxax/spacetraders/golang/pkg/api" + "git.adyxax.org/adyxax/spacetraders/golang/pkg/database" +) + +func Run( + apiClient *api.Client, + db *database.DB, + getenv func(string) string, +) error { + accountToken := getenv("SPACETRADERS_ACCOUNT_TOKEN") + if accountToken == "" { + return fmt.Errorf("the SPACETRADERS_ACCOUNT_TOKEN environment variable is not set") + } + agent := getenv("SPACETRADERS_AGENT") + if agent == "" { + return fmt.Errorf("the SPACETRADERS_AGENT environment variable is not set") + } + faction := getenv("SPACETRADERS_FACTION") + if faction == "" { + return fmt.Errorf("the SPACETRADERS_FACTION environment variable is not set") + } + // ----- Get token or register --------------------------------------------- + apiClient.SetToken(accountToken) + register, err := apiClient.Register(faction, agent) + if err != nil { + apiError := &api.APIError{} + if errors.As(err, &apiError) { + switch apiError.Code { + case 4111: // Agent symbol has already been claimed + token, err := db.GetToken() + if err != nil || token == "" { + return fmt.Errorf("failed to register and failed to get a token from the database: someone stole our agent's callsign: %w", err) + } + apiClient.SetToken(token) + agent, err := apiClient.MyAgent() + if err != nil { + return fmt.Errorf("failed to get agent: %w", err) + } + slog.Info("agent", "/my/agent", agent) + default: + return fmt.Errorf("failed to register: %w", err) + } + } else { + return fmt.Errorf("failed to register with an invalid apiError: %w", err) + } + } else { + token, err := db.GetToken() + if err != nil || token == "" { + if err := db.AddToken(register.Token); err != nil { + return fmt.Errorf("failed to save token: %w", err) + } + apiClient.SetToken(register.Token) + } else { + // We successfully registered but have a tainted database + slog.Error("token", "token", register.Token) + return fmt.Errorf("TODO server reset not implemented yet") + } + } + // ----- run agent --------------------------------------------------------- + contracts, err := apiClient.MyContracts() + if err != nil { + return err + } + slog.Info("start", "contract", contracts[0], "err", err) + ships, err := apiClient.MyShips() + if err != nil { + return err + } + slog.Info("start", "ship", ships[0].Nav.Status, "err", err) + return nil +} diff --git a/golang/pkg/api/contracts.go b/golang/pkg/api/contracts.go new file mode 100644 index 0000000..f82ee6d --- /dev/null +++ b/golang/pkg/api/contracts.go @@ -0,0 +1,17 @@ +package api + +import ( + "fmt" + "net/url" + + "git.adyxax.org/adyxax/spacetraders/golang/pkg/model" +) + +func (c *Client) MyContracts() ([]model.Contract, error) { + uriRef := url.URL{Path: "my/contracts"} + var contracts []model.Contract + if err := c.Send("GET", &uriRef, nil, &contracts); err != nil { + return nil, fmt.Errorf("failed to get contracts: %w", err) + } + return contracts, nil +} diff --git a/golang/pkg/api/ships.go b/golang/pkg/api/ships.go index 0674b3d..485f437 100644 --- a/golang/pkg/api/ships.go +++ b/golang/pkg/api/ships.go @@ -5,12 +5,11 @@ import ( "net/url" "path" - "git.adyxax.org/adyxax/spacetraders/golang/pkg/agent" "git.adyxax.org/adyxax/spacetraders/golang/pkg/database" "git.adyxax.org/adyxax/spacetraders/golang/pkg/model" ) -func (c *Client) Dock(s *model.Ship) error { +func (c *Client) dock(s *model.Ship) error { if s.Nav.Status == "DOCKED" { return nil } @@ -35,7 +34,7 @@ func (c *Client) MyShips() ([]model.Ship, error) { return ships, nil } -func (c *Client) Orbit(s *model.Ship) error { +func (c *Client) orbit(s *model.Ship) error { if s.Nav.Status == "IN_ORBIT" { return nil } @@ -55,7 +54,7 @@ func (c *Client) Refuel(s *model.Ship, db *database.DB) error { if s.Fuel.Current == s.Fuel.Capacity { return nil } - if err := c.Dock(s); err != nil { + if err := c.dock(s); err != nil { return fmt.Errorf("failed to refuel ship %s: %w", s.Symbol, err) } uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "refuel")} @@ -68,7 +67,9 @@ func (c *Client) Refuel(s *model.Ship, db *database.DB) error { if err := c.Send("POST", &uriRef, nil, &response); err != nil { return fmt.Errorf("failed to refuel ship %s: %w", s.Symbol, err) } - agent.SetAgent(response.Agent) + if err := db.SaveAgent(response.Agent); err != nil { + return fmt.Errorf("failed to refuel ship %s: %w", s.Symbol, err) + } s.Fuel = response.Fuel if err := db.AppendTransaction(response.Transaction); err != nil { return fmt.Errorf("failed to refuel ship %s: %w", s.Symbol, err) diff --git a/golang/pkg/database/agents.go b/golang/pkg/database/agents.go new file mode 100644 index 0000000..cd9e0a2 --- /dev/null +++ b/golang/pkg/database/agents.go @@ -0,0 +1,19 @@ +package database + +import ( + "encoding/json" + "fmt" + + "git.adyxax.org/adyxax/spacetraders/golang/pkg/model" +) + +func (db *DB) SaveAgent(agent *model.Agent) error { + data, err := json.Marshal(agent) + if err != nil { + return fmt.Errorf("failed to marshal agent: %w", err) + } + if _, err := db.Exec(`INSERT INTO agents SET data = (json(?));`, data); err != nil { + return fmt.Errorf("failed to insert agent data: %w", err) + } + return nil +} diff --git a/golang/pkg/database/sql/001_trading.sql b/golang/pkg/database/sql/001_trading.sql index fa8cbfe..68f2568 100644 --- a/golang/pkg/database/sql/001_trading.sql +++ b/golang/pkg/database/sql/001_trading.sql @@ -1,3 +1,7 @@ +CREATE TABLE agents ( + id INTEGER PRIMARY KEY, + data TEXT NOT NULL +); CREATE TABLE markets ( id INTEGER PRIMARY KEY, systemSymbol TEXT NOT NULL, diff --git a/golang/pkg/model/contract.go b/golang/pkg/model/contract.go new file mode 100644 index 0000000..24ed403 --- /dev/null +++ b/golang/pkg/model/contract.go @@ -0,0 +1,32 @@ +package model + +import "time" + +type Contract struct { + Accepted bool `json:"accepted"` + DeadlineToAccept time.Time `json:"deadlineToAccept"` + Expiration time.Time `json:"expiration"` + FactionSymbol string `json:"factionSymbol"` + Fullfilled bool `json:"fulfilled"` + Id string `json:"id"` + Terms *Terms `json:"terms"` + Type string `json:"type"` +} + +type Deliver struct { + DestinationSymbol string `json:"destinationSymbol"` + TradeSymbol string `json:"tradeSymbol"` + UnitsFulfilled int `json:"unitsFulfilled"` + UnitsRequired int `json:"unitsRequired"` +} + +type Payment struct { + OnAccepted int `json:"onAccepted"` + OnFulfilled int `json:"onFulfilled"` +} + +type Terms struct { + Deadline time.Time `json:"deadline"` + Payment *Payment `json:"payment"` + Deliver []Deliver `json:"deliver"` +} |