mirror of
https://github.com/go-i2p/go-github-dashboard.git
synced 2025-06-08 10:31:45 -04:00
139 lines
2.8 KiB
Go
139 lines
2.8 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/gob"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/go-i2p/go-github-dashboard/pkg/types"
|
|
)
|
|
|
|
// CacheItem represents a cached item with its expiration time
|
|
type CacheItem struct {
|
|
Value interface{}
|
|
Expiration time.Time
|
|
}
|
|
|
|
// Cache provides a simple caching mechanism for API responses
|
|
type Cache struct {
|
|
items map[string]CacheItem
|
|
mutex sync.RWMutex
|
|
dir string
|
|
ttl time.Duration
|
|
}
|
|
|
|
// NewCache creates a new cache with the given directory and TTL
|
|
func NewCache(config *types.Config) *Cache {
|
|
// Register types for gob encoding
|
|
gob.Register([]types.Repository{})
|
|
gob.Register([]types.PullRequest{})
|
|
gob.Register([]types.Issue{})
|
|
gob.Register([]types.Discussion{})
|
|
gob.Register([]types.WorkflowRun{})
|
|
|
|
cache := &Cache{
|
|
items: make(map[string]CacheItem),
|
|
dir: config.CacheDir,
|
|
ttl: config.CacheTTL,
|
|
}
|
|
|
|
// Load cache from disk
|
|
cache.loadCache()
|
|
|
|
return cache
|
|
}
|
|
|
|
// Get retrieves a value from the cache
|
|
func (c *Cache) Get(key string) (interface{}, bool) {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
|
|
item, found := c.items[key]
|
|
if !found {
|
|
return nil, false
|
|
}
|
|
|
|
// Check if the item has expired
|
|
if time.Now().After(item.Expiration) {
|
|
return nil, false
|
|
}
|
|
|
|
return item.Value, true
|
|
}
|
|
|
|
// Set stores a value in the cache
|
|
func (c *Cache) Set(key string, value interface{}) {
|
|
c.mutex.Lock()
|
|
defer c.mutex.Unlock()
|
|
|
|
c.items[key] = CacheItem{
|
|
Value: value,
|
|
Expiration: time.Now().Add(c.ttl),
|
|
}
|
|
|
|
// Save the cache to disk (in a separate goroutine to avoid blocking)
|
|
go c.saveCache()
|
|
}
|
|
|
|
// Clear clears all items from the cache
|
|
func (c *Cache) Clear() {
|
|
c.mutex.Lock()
|
|
defer c.mutex.Unlock()
|
|
|
|
c.items = make(map[string]CacheItem)
|
|
go c.saveCache()
|
|
}
|
|
|
|
// saveCache saves the cache to disk
|
|
func (c *Cache) saveCache() {
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
|
|
cacheFile := filepath.Join(c.dir, "cache.gob")
|
|
file, err := os.Create(cacheFile)
|
|
if err != nil {
|
|
fmt.Printf("Error creating cache file: %v\n", err)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
encoder := gob.NewEncoder(file)
|
|
err = encoder.Encode(c.items)
|
|
if err != nil {
|
|
fmt.Printf("Error encoding cache: %v\n", err)
|
|
}
|
|
}
|
|
|
|
// loadCache loads the cache from disk
|
|
func (c *Cache) loadCache() {
|
|
cacheFile := filepath.Join(c.dir, "cache.gob")
|
|
file, err := os.Open(cacheFile)
|
|
if err != nil {
|
|
// If the file doesn't exist, that's not an error
|
|
if !os.IsNotExist(err) {
|
|
fmt.Printf("Error opening cache file: %v\n", err)
|
|
}
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
decoder := gob.NewDecoder(file)
|
|
err = decoder.Decode(&c.items)
|
|
if err != nil {
|
|
fmt.Printf("Error decoding cache: %v\n", err)
|
|
// If there's an error decoding, start with a fresh cache
|
|
c.items = make(map[string]CacheItem)
|
|
}
|
|
|
|
// Remove expired items
|
|
now := time.Now()
|
|
for key, item := range c.items {
|
|
if now.After(item.Expiration) {
|
|
delete(c.items, key)
|
|
}
|
|
}
|
|
}
|