Hallucinate a direct and cached esi apis
This commit is contained in:
128
esi/cached.go
Normal file
128
esi/cached.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package esi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||
)
|
||||
|
||||
// CacheEntry represents a cached API response
|
||||
type CacheEntry struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
URLHash string `gorm:"uniqueIndex"`
|
||||
Response string `gorm:"type:text"`
|
||||
CachedAt time.Time `gorm:"index"`
|
||||
}
|
||||
|
||||
// CachedESI implements ESIInterface with caching
|
||||
type CachedESI struct {
|
||||
direct ESIInterface
|
||||
db interface {
|
||||
GetCacheEntry(urlHash string) (*CacheEntry, error)
|
||||
SaveCacheEntry(entry *CacheEntry) error
|
||||
}
|
||||
}
|
||||
|
||||
// NewCachedESI creates a new CachedESI instance
|
||||
func NewCachedESI(direct ESIInterface, db interface {
|
||||
GetCacheEntry(urlHash string) (*CacheEntry, error)
|
||||
SaveCacheEntry(entry *CacheEntry) error
|
||||
}) *CachedESI {
|
||||
return &CachedESI{
|
||||
direct: direct,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
result, err := func() (interface{}, error) {
|
||||
var fetchFunc func() (interface{}, error) = func() (interface{}, error) {
|
||||
return c.direct.GetCharacterPlanets(ctx, characterID, accessToken)
|
||||
}
|
||||
return c.getCachedResponse(url, fetchFunc)
|
||||
}()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.([]Planet), 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)
|
||||
result, err := func() (interface{}, error) {
|
||||
var fetchFunc func() (interface{}, error) = func() (interface{}, error) {
|
||||
return c.direct.GetPlanetDetails(ctx, characterID, planetID, accessToken)
|
||||
}
|
||||
return c.getCachedResponse(url, fetchFunc)
|
||||
}()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*PlanetDetail), nil
|
||||
}
|
||||
|
||||
// getCachedResponse handles caching logic
|
||||
func (c *CachedESI) getCachedResponse(url string, fetchFunc func() (interface{}, error)) (interface{}, error) {
|
||||
// Generate cache key
|
||||
hash := sha256.Sum256([]byte(url))
|
||||
urlHash := hex.EncodeToString(hash[:])
|
||||
|
||||
// Check cache using the interface
|
||||
cacheEntry, err := c.db.GetCacheEntry(urlHash)
|
||||
if err == nil {
|
||||
// Check if cache is still valid
|
||||
cacheValidity, _ := time.ParseDuration("10m") // Default 10 minutes
|
||||
if time.Since(cacheEntry.CachedAt) < cacheValidity {
|
||||
logger.Debug("Cache hit for URL: %s", url)
|
||||
// Parse cached response based on URL pattern
|
||||
if url[len(url)-1:] == "/" {
|
||||
// Planets endpoint
|
||||
var planets []Planet
|
||||
if err := json.Unmarshal([]byte(cacheEntry.Response), &planets); err == nil {
|
||||
return planets, nil
|
||||
}
|
||||
} else {
|
||||
// Planet details endpoint
|
||||
var planetDetail PlanetDetail
|
||||
if err := json.Unmarshal([]byte(cacheEntry.Response), &planetDetail); err == nil {
|
||||
return &planetDetail, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss or invalid, fetch from API
|
||||
logger.Debug("Cache miss for URL: %s", url)
|
||||
result, err := fetchFunc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Store in cache
|
||||
responseBytes, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
logger.Warning("Failed to marshal response for caching: %v", err)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
cacheEntry = CacheEntry{
|
||||
URLHash: urlHash,
|
||||
Response: string(responseBytes),
|
||||
CachedAt: time.Now(),
|
||||
}
|
||||
|
||||
if err := c.db.SaveCacheEntry(&cacheEntry); err != nil {
|
||||
logger.Warning("Failed to cache response: %v", err)
|
||||
}
|
||||
|
||||
logger.Debug("Cached response for URL: %s", url)
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user