summaryrefslogtreecommitdiff
path: root/backend-go/internal/esi/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend-go/internal/esi/api.go')
-rw-r--r--backend-go/internal/esi/api.go215
1 files changed, 215 insertions, 0 deletions
diff --git a/backend-go/internal/esi/api.go b/backend-go/internal/esi/api.go
new file mode 100644
index 0000000..706ea32
--- /dev/null
+++ b/backend-go/internal/esi/api.go
@@ -0,0 +1,215 @@
+package esi
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "time"
+)
+
+type WaypointResult struct {
+ RequestedCount int `json:"requested_count"`
+ SuccessCount int `json:"success_count"`
+ AppliedWaypoints []int `json:"applied_waypoints"`
+ FailedWaypoints []int `json:"failed_waypoints"`
+ Errors []string `json:"errors"`
+ Success bool `json:"success"`
+}
+
+type WalletTransaction struct {
+ TransactionID int `json:"transaction_id"`
+ Date time.Time `json:"date"`
+ LocationID int `json:"location_id"`
+ TypeID int `json:"type_id"`
+ UnitPrice float64 `json:"unit_price"`
+ Quantity int `json:"quantity"`
+ ClientID int `json:"client_id"`
+ IsBuy bool `json:"is_buy"`
+ IsPersonal bool `json:"is_personal"`
+ JournalRefID int `json:"journal_ref_id"`
+}
+
+type LocationData struct {
+ SolarSystemID int `json:"solar_system_id"`
+ StationID int `json:"station_id"`
+}
+
+func (c *EsiClient) GetLocation() (*LocationData, error) {
+ characterIDStr := os.Getenv("character_id")
+ if characterIDStr == "" {
+ return nil, fmt.Errorf("character_id not set in environment variables")
+ }
+ characterID, _ := strconv.Atoi(characterIDStr)
+
+ endpoint := fmt.Sprintf("/characters/%d/location/?datasource=tranquility", characterID)
+ resp, err := c.doRequest("GET", endpoint, nil, true)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("failed to get location, status: %d body: %s", resp.StatusCode, string(body))
+ }
+
+var data LocationData
+ if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+ return nil, err
+ }
+
+ return &data, nil
+}
+
+func (c *EsiClient) SetWaypoints(waypoints []int) (*WaypointResult, error) {
+ res := &WaypointResult{
+ RequestedCount: len(waypoints),
+ Success: true,
+ }
+
+ for i, wp := range waypoints {
+ clearOther := "false"
+ if i == 0 {
+ clearOther = "true"
+ }
+
+ endpoint := fmt.Sprintf("/ui/autopilot/waypoint/?add_to_beginning=false&clear_other_waypoints=%s&destination_id=%d&datasource=tranquility", clearOther, wp)
+
+ resp, err := c.doRequest("POST", endpoint, nil, true)
+ if err != nil {
+ res.FailedWaypoints = append(res.FailedWaypoints, wp)
+ res.Errors = append(res.Errors, err.Error())
+ res.Success = false
+ continue
+ }
+
+ if resp.StatusCode >= 200 && resp.StatusCode < 300 {
+ res.SuccessCount++
+ res.AppliedWaypoints = append(res.AppliedWaypoints, wp)
+ } else {
+ body, _ := io.ReadAll(resp.Body)
+ res.Errors = append(res.Errors, fmt.Sprintf("status %d body %s", resp.StatusCode, string(body)))
+ res.FailedWaypoints = append(res.FailedWaypoints, wp)
+ res.Success = false
+ }
+ resp.Body.Close()
+ time.Sleep(50 * time.Millisecond) // Rate limiting
+ }
+
+ res.Success = len(res.FailedWaypoints) == 0
+ return res, nil
+}
+
+func (c *EsiClient) GetWalletTransactions(fromID *int) ([]WalletTransaction, error) {
+ characterIDStr := os.Getenv("character_id")
+ if characterIDStr == "" {
+ return nil, fmt.Errorf("character_id not set in environment variables")
+ }
+ characterID, _ := strconv.Atoi(characterIDStr)
+ endpoint := fmt.Sprintf("/characters/%d/wallet/transactions/?datasource=tranquility", characterID)
+ if fromID != nil {
+ endpoint += fmt.Sprintf("&from_id=%d", *fromID)
+ }
+
+ resp, err := c.doRequest("GET", endpoint, nil, true)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, fmt.Errorf("failed to get transactions, status: %d body: %s", resp.StatusCode, string(body))
+ }
+
+ var baseTx []struct {
+ TransactionID int `json:"transaction_id"`
+ Date string `json:"date"`
+ LocationID int `json:"location_id"`
+ TypeID int `json:"type_id"`
+ UnitPrice float64 `json:"unit_price"`
+ Quantity int `json:"quantity"`
+ ClientID int `json:"client_id"`
+ IsBuy bool `json:"is_buy"`
+ IsPersonal bool `json:"is_personal"`
+ JournalRefID int `json:"journal_ref_id"`
+ }
+
+ if err := json.NewDecoder(resp.Body).Decode(&baseTx); err != nil {
+ return nil, err
+ }
+
+ var results []WalletTransaction
+ for _, bt := range baseTx {
+ // ESI dates look like `2026-04-26T01:23:45Z`
+ t, _ := time.Parse(time.RFC3339, bt.Date)
+ results = append(results, WalletTransaction{
+ TransactionID: bt.TransactionID,
+ Date: t,
+ LocationID: bt.LocationID,
+ TypeID: bt.TypeID,
+ UnitPrice: bt.UnitPrice,
+ Quantity: bt.Quantity,
+ ClientID: bt.ClientID,
+ IsBuy: bt.IsBuy,
+ IsPersonal: bt.IsPersonal,
+ JournalRefID: bt.JournalRefID,
+ })
+ }
+ return results, nil
+}
+
+func (c *EsiClient) OpenMarketWindow(typeID int) error {
+ endpoint := fmt.Sprintf("/ui/openwindow/marketdetails/?datasource=tranquility&type_id=%d", typeID)
+ resp, err := c.doRequest("POST", endpoint, nil, true)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode >= 200 && resp.StatusCode < 300 {
+ return nil
+ }
+ body, _ := io.ReadAll(resp.Body)
+ return fmt.Errorf("failed to open market window, status: %d body: %s", resp.StatusCode, string(body))
+}
+
+func (c *EsiClient) GetRegionOrders(regionID int, page int) ([]map[string]interface{}, string, int, error) {
+ endpoint := fmt.Sprintf("/markets/%d/orders/?datasource=tranquility&order_type=all&page=%d", regionID, page)
+ resp, err := c.doRequest("GET", endpoint, nil, true)
+ if err != nil {
+ return nil, "", 0, err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ body, _ := io.ReadAll(resp.Body)
+ return nil, "", 0, fmt.Errorf("failed to get region orders, status: %d body: %s", resp.StatusCode, string(body))
+ }
+
+ var orders []map[string]interface{}
+ if err := json.NewDecoder(resp.Body).Decode(&orders); err != nil {
+ return nil, "", 0, err
+ }
+
+ expires := resp.Header.Get("Expires")
+ totalPagesStr := resp.Header.Get("X-Pages")
+ totalPages, _ := strconv.Atoi(totalPagesStr)
+ if totalPages == 0 {
+ totalPages = 1
+ }
+
+ // Add RegionID and drop 0 volume
+ var filtered []map[string]interface{}
+ for _, o := range orders {
+ volRemain, _ := o["volume_remain"].(float64)
+ if volRemain > 0 {
+ o["region_id"] = regionID
+ filtered = append(filtered, o)
+ }
+ }
+
+ return filtered, expires, totalPages, nil
+}