Rework the fucking esi planet PI fetching
This commit is contained in:
115
esi/cached.go
115
esi/cached.go
@@ -15,23 +15,20 @@ import (
|
||||
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||
)
|
||||
|
||||
// CacheEntry is now defined in the types package
|
||||
type CacheDB interface {
|
||||
GetCacheEntry(urlHash string) (*types.CacheEntry, error)
|
||||
SaveCacheEntry(entry *types.CacheEntry) error
|
||||
}
|
||||
|
||||
// CachedESI implements ESIInterface with caching
|
||||
type CachedESI struct {
|
||||
direct ESIInterface
|
||||
db interface {
|
||||
GetCacheEntry(urlHash string) (*types.CacheEntry, error)
|
||||
SaveCacheEntry(entry *types.CacheEntry) error
|
||||
}
|
||||
db CacheDB
|
||||
cacheValidity time.Duration
|
||||
}
|
||||
|
||||
// NewCachedESI creates a new CachedESI instance
|
||||
func NewCachedESI(direct ESIInterface, db interface {
|
||||
GetCacheEntry(urlHash string) (*types.CacheEntry, error)
|
||||
SaveCacheEntry(entry *types.CacheEntry) error
|
||||
}) *CachedESI {
|
||||
func NewCachedESI(direct ESIInterface, db CacheDB) *CachedESI {
|
||||
// Parse cache validity ONCE at initialization
|
||||
cacheValidity, err := time.ParseDuration(options.GlobalOptions.CacheValidity)
|
||||
if err != nil {
|
||||
@@ -47,113 +44,90 @@ func NewCachedESI(direct ESIInterface, db interface {
|
||||
}
|
||||
}
|
||||
|
||||
// GetCharacterPlanets retrieves a list of planets for a character with caching
|
||||
func (c *CachedESI) GetCharacterPlanets(ctx context.Context, characterID int, accessToken string) ([]Planet, error) {
|
||||
url := fmt.Sprintf("/v1/characters/%d/planets/", characterID)
|
||||
logger.Info("CachedESI.GetCharacterPlanets: Starting for character %d", characterID)
|
||||
// GetPlanetPI retrieves detailed information about a specific planet with caching
|
||||
func (c *CachedESI) GetPlanetPI(ctx context.Context, characterID int, planetID int64, accessToken string) (*PlanetPI, error) {
|
||||
funclog := logger.Default.WithPrefix("CachedESI.GetPlanetPI").WithPrefix(fmt.Sprintf("characterID=%d", characterID)).WithPrefix(fmt.Sprintf("planetID=%d", planetID))
|
||||
|
||||
fetchFunc := func() ([]Planet, error) {
|
||||
logger.Info("CachedESI.GetCharacterPlanets: Calling direct ESI for character %d planets", characterID)
|
||||
result, err := c.direct.GetCharacterPlanets(ctx, characterID, accessToken)
|
||||
if err != nil {
|
||||
logger.Error("CachedESI.GetCharacterPlanets: Direct ESI call failed for character %d: %v", characterID, err)
|
||||
return nil, err
|
||||
}
|
||||
logger.Info("CachedESI.GetCharacterPlanets: Direct ESI returned %d planets for character %d", len(result), characterID)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result, err := getCachedResponse(c, url, fetchFunc)
|
||||
if err != nil {
|
||||
logger.Error("CachedESI.GetCharacterPlanets: Failed to get planets for character %d: %v", characterID, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Info("CachedESI.GetCharacterPlanets: Successfully retrieved %d planets for character %d", len(result), characterID)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetPlanetDetails retrieves detailed information about a specific planet with caching
|
||||
func (c *CachedESI) GetPlanetDetails(ctx context.Context, characterID, planetID int, accessToken string) (*PlanetDetail, error) {
|
||||
url := fmt.Sprintf("/v3/characters/%d/planets/%d/", characterID, planetID)
|
||||
logger.Info("CachedESI.GetPlanetDetails: Starting for character %d, planet %d", characterID, planetID)
|
||||
funclog.Info("Starting")
|
||||
|
||||
fetchFunc := func() (*PlanetDetail, error) {
|
||||
logger.Info("CachedESI.GetPlanetDetails: Calling direct ESI for character %d planet %d details", characterID, planetID)
|
||||
result, err := c.direct.GetPlanetDetails(ctx, characterID, planetID, accessToken)
|
||||
fetchFunc := func() (*PlanetPI, error) {
|
||||
funclog.Info("Calling direct ESI")
|
||||
result, err := c.direct.GetPlanetPI(ctx, characterID, planetID, accessToken)
|
||||
if err != nil {
|
||||
logger.Error("CachedESI.GetPlanetDetails: Direct ESI call failed for character %d planet %d: %v", characterID, planetID, err)
|
||||
funclog.Error("Direct ESI call failed: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if result != nil {
|
||||
logger.Info("CachedESI.GetPlanetDetails: Direct ESI returned planet details with %d pins for character %d planet %d", len(result.Pins), characterID, planetID)
|
||||
funclog.Info("Direct ESI returned planet details with %d pins", len(result.Pins))
|
||||
} else {
|
||||
logger.Info("CachedESI.GetPlanetDetails: Direct ESI returned nil planet details for character %d planet %d", characterID, planetID)
|
||||
funclog.Info("Direct ESI returned nil planet details")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result, err := getCachedResponse(c, url, fetchFunc)
|
||||
if err != nil {
|
||||
logger.Error("CachedESI.GetPlanetDetails: Failed to get planet details for character %d, planet %d: %v", characterID, planetID, err)
|
||||
funclog.Error("Failed to get planet details: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
logger.Info("CachedESI.GetPlanetDetails: Successfully retrieved planet details with %d pins for character %d, planet %d", len(result.Pins), characterID, planetID)
|
||||
funclog.Info("Successfully retrieved planet details with %d pins", len(result.Pins))
|
||||
} else {
|
||||
logger.Info("CachedESI.GetPlanetDetails: Successfully retrieved nil planet details for character %d, planet %d", characterID, planetID)
|
||||
funclog.Info("Successfully retrieved nil planet details")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// getCachedResponse handles caching logic with generics
|
||||
func getCachedResponse[T any](c *CachedESI, url string, fetchFunc func() (T, error)) (T, error) {
|
||||
funclog := logger.Default.WithPrefix("getCachedResponse").WithPrefix(fmt.Sprintf("url=%s", url))
|
||||
// Generate cache key
|
||||
hash := sha256.Sum256([]byte(url))
|
||||
urlHash := hex.EncodeToString(hash[:])
|
||||
logger.Debug("CachedESI: Generated cache key %s for URL: %s", urlHash[:8], url)
|
||||
funclog.Debug("Generated cache key %s for URL: %s", urlHash[:8], url)
|
||||
|
||||
// Check cache using the interface
|
||||
logger.Debug("CachedESI: Checking cache for URL: %s", url)
|
||||
funclog.Debug("Checking cache for URL: %s", url)
|
||||
cacheEntry, err := c.db.GetCacheEntry(urlHash)
|
||||
if err == nil {
|
||||
// Check if cache is still valid
|
||||
age := time.Since(cacheEntry.CachedAt)
|
||||
if age < c.cacheValidity {
|
||||
logger.Info("Cache HIT for URL: %s (cached %v ago, valid for %v more)", url, age, c.cacheValidity-age)
|
||||
funclog.Info("Cache HIT for URL: %s (cached %v ago, valid for %v more)", url, age, c.cacheValidity-age)
|
||||
// Parse cached response
|
||||
var result T
|
||||
if err := json.Unmarshal([]byte(cacheEntry.Response), &result); err == nil {
|
||||
logger.Debug("CachedESI: Successfully unmarshaled cached response for URL: %s", url)
|
||||
funclog.Debug("Successfully unmarshaled cached response for URL: %s", url)
|
||||
return result, nil
|
||||
}
|
||||
logger.Warning("Failed to unmarshal cached response for URL: %s: %v", url, err)
|
||||
funclog.Warning("Failed to unmarshal cached response for URL: %s: %v", url, err)
|
||||
} else {
|
||||
logger.Info("Cache EXPIRED for URL: %s (cached %v ago, validity: %v)", url, age, c.cacheValidity)
|
||||
}
|
||||
} else {
|
||||
logger.Info("Cache MISS for URL: %s (no cache entry found): %v", url, err)
|
||||
funclog.Info("Cache MISS for URL: %s (no cache entry found): %v", url, err)
|
||||
}
|
||||
|
||||
// Cache miss or invalid, fetch from API
|
||||
logger.Info("Fetching from API for URL: %s", url)
|
||||
funclog.Info("Fetching from API for URL: %s", url)
|
||||
result, err := fetchFunc()
|
||||
if err != nil {
|
||||
logger.Error("CachedESI: API fetch failed for URL: %s: %v", url, err)
|
||||
funclog.Error("API fetch failed for URL: %s: %v", url, err)
|
||||
var zero T
|
||||
return zero, err
|
||||
}
|
||||
logger.Debug("CachedESI: API fetch successful for URL: %s", url)
|
||||
funclog.Debug("API fetch successful for URL: %s", url)
|
||||
|
||||
// Store in cache
|
||||
logger.Debug("CachedESI: Marshaling response for caching URL: %s", url)
|
||||
funclog.Debug("Marshaling response for caching URL: %s", url)
|
||||
responseBytes, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
logger.Warning("Failed to marshal response for caching URL: %s: %v", url, err)
|
||||
funclog.Warning("Failed to marshal response for caching URL: %s: %v", url, err)
|
||||
return result, nil
|
||||
}
|
||||
logger.Debug("CachedESI: Response marshaled successfully for URL: %s (%d bytes)", url, len(responseBytes))
|
||||
funclog.Debug("Response marshaled successfully for URL: %s (%d bytes)", url, len(responseBytes))
|
||||
|
||||
cacheEntry = &types.CacheEntry{
|
||||
URLHash: urlHash,
|
||||
@@ -161,46 +135,47 @@ func getCachedResponse[T any](c *CachedESI, url string, fetchFunc func() (T, err
|
||||
CachedAt: time.Now(),
|
||||
}
|
||||
|
||||
logger.Debug("CachedESI: Saving cache entry for URL: %s", url)
|
||||
funclog.Debug("Saving cache entry for URL: %s", url)
|
||||
if err := c.db.SaveCacheEntry(cacheEntry); err != nil {
|
||||
logger.Warning("Failed to cache response for URL: %s: %v", url, err)
|
||||
funclog.Warning("Failed to cache response for URL: %s: %v", url, err)
|
||||
} else {
|
||||
logger.Info("Cached response for URL: %s (valid for %v, %d bytes)", url, c.cacheValidity, len(responseBytes))
|
||||
funclog.Info("Cached response for URL: %s (valid for %v, %d bytes)", url, c.cacheValidity, len(responseBytes))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetPlanetName retrieves planet name with caching
|
||||
func (c *CachedESI) GetPlanetName(ctx context.Context, planetID int) (*PlanetName, error) {
|
||||
func (c *CachedESI) GetPlanetName(ctx context.Context, planetID int64) (*PlanetName, error) {
|
||||
funclog := logger.Default.WithPrefix("CachedESI.GetPlanetName").WithPrefix(fmt.Sprintf("planetID=%d", planetID))
|
||||
url := fmt.Sprintf("/v1/universe/planets/%d/", planetID)
|
||||
logger.Info("CachedESI.GetPlanetName: Starting for planet %d", planetID)
|
||||
funclog.Info("Starting")
|
||||
|
||||
fetchFunc := func() (*PlanetName, error) {
|
||||
logger.Info("CachedESI.GetPlanetName: Calling direct ESI for planet %d name", planetID)
|
||||
funclog.Info("Calling direct ESI for planet %d name", planetID)
|
||||
result, err := c.direct.GetPlanetName(ctx, planetID)
|
||||
if err != nil {
|
||||
logger.Error("CachedESI.GetPlanetName: Direct ESI call failed for planet %d: %v", planetID, err)
|
||||
funclog.Error("Direct ESI call failed for planet %d: %v", planetID, err)
|
||||
return nil, err
|
||||
}
|
||||
if result != nil {
|
||||
logger.Info("CachedESI.GetPlanetName: Direct ESI returned planet name '%s' for planet %d", result.Name, planetID)
|
||||
funclog.Info("Direct ESI returned planet name '%s' for planet %d", result.Name, planetID)
|
||||
} else {
|
||||
logger.Info("CachedESI.GetPlanetName: Direct ESI returned nil planet name for planet %d", planetID)
|
||||
funclog.Info("Direct ESI returned nil planet name for planet %d", planetID)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result, err := getCachedResponse(c, url, fetchFunc)
|
||||
if err != nil {
|
||||
logger.Error("CachedESI.GetPlanetName: Failed to get planet name for planet %d: %v", planetID, err)
|
||||
funclog.Error("Failed to get planet name for planet %d: %v", planetID, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
logger.Info("CachedESI.GetPlanetName: Successfully retrieved planet name '%s' for planet %d", result.Name, planetID)
|
||||
funclog.Info("Successfully retrieved planet name '%s' for planet %d", result.Name, planetID)
|
||||
} else {
|
||||
logger.Info("CachedESI.GetPlanetName: Successfully retrieved nil planet name for planet %d", planetID)
|
||||
funclog.Info("Successfully retrieved nil planet name for planet %d", planetID)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
51
esi/types.go
Normal file
51
esi/types.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package esi
|
||||
|
||||
import "time"
|
||||
|
||||
type PlanetPI struct {
|
||||
Links []Link `json:"links"`
|
||||
Pins []Pin `json:"pins"`
|
||||
Routes []Route `json:"routes"`
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
DestinationPinID int64 `json:"destination_pin_id"`
|
||||
LinkLevel int64 `json:"link_level"`
|
||||
SourcePinID int64 `json:"source_pin_id"`
|
||||
}
|
||||
|
||||
type Pin struct {
|
||||
Contents []Content `json:"contents"`
|
||||
LastCycleStart *time.Time `json:"last_cycle_start,omitempty"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
PinID int64 `json:"pin_id"`
|
||||
TypeID int64 `json:"type_id"`
|
||||
SchematicID *int64 `json:"schematic_id,omitempty"`
|
||||
}
|
||||
|
||||
type Content struct {
|
||||
Amount int64 `json:"amount"`
|
||||
TypeID int64 `json:"type_id"`
|
||||
}
|
||||
|
||||
type Route struct {
|
||||
ContentTypeID int64 `json:"content_type_id"`
|
||||
DestinationPinID int64 `json:"destination_pin_id"`
|
||||
Quantity int64 `json:"quantity"`
|
||||
RouteID int64 `json:"route_id"`
|
||||
SourcePinID int64 `json:"source_pin_id"`
|
||||
Waypoints []int64 `json:"waypoints"`
|
||||
}
|
||||
|
||||
type Planets []Planet
|
||||
|
||||
type Planet struct {
|
||||
LastUpdate time.Time `json:"last_update"`
|
||||
NumPins int64 `json:"num_pins"`
|
||||
OwnerID int64 `json:"owner_id"`
|
||||
PlanetID int64 `json:"planet_id"`
|
||||
PlanetType string `json:"planet_type"`
|
||||
SolarSystemID int64 `json:"solar_system_id"`
|
||||
UpgradeLevel int64 `json:"upgrade_level"`
|
||||
}
|
||||
Reference in New Issue
Block a user