mirror of
https://github.com/status-im/proxy-common.git
synced 2026-08-30 12:01:06 +00:00
* l1 biggache, l2 keydb * extracted from status-im/eth-rpc-proxy to reuse in another projects fixes status-im/eth-rpc-proxy#106
148 lines
3.4 KiB
Go
148 lines
3.4 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// CacheType represents the type of caching for a method
|
|
type CacheType string
|
|
|
|
const (
|
|
CacheTypePermanent CacheType = "permanent"
|
|
CacheTypeShort CacheType = "short"
|
|
CacheTypeMinimal CacheType = "minimal"
|
|
CacheTypeNone CacheType = "none"
|
|
)
|
|
|
|
// UnmarshalYAML implements custom YAML unmarshaling for CacheType
|
|
func (c *CacheType) UnmarshalYAML(value *yaml.Node) error {
|
|
var str string
|
|
if err := value.Decode(&str); err != nil {
|
|
return err
|
|
}
|
|
|
|
switch str {
|
|
case "permanent", "short", "minimal", "none":
|
|
*c = CacheType(str)
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("invalid cache type '%s': must be one of 'permanent', 'short', 'minimal', 'none'", str)
|
|
}
|
|
}
|
|
|
|
// CacheStatus represents the cache status for a request
|
|
type CacheStatus string
|
|
|
|
const (
|
|
CacheStatusHit CacheStatus = "HIT"
|
|
CacheStatusMiss CacheStatus = "MISS"
|
|
CacheStatusBypass CacheStatus = "BYPASS"
|
|
)
|
|
|
|
func (cs CacheStatus) String() string {
|
|
return string(cs)
|
|
}
|
|
|
|
// IsValid checks if the cache status is one of the valid values
|
|
func (cs CacheStatus) IsValid() bool {
|
|
switch cs {
|
|
case CacheStatusHit, CacheStatusMiss, CacheStatusBypass:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// CacheInfo contains cache configuration information
|
|
type CacheInfo struct {
|
|
TTL time.Duration `json:"ttl"`
|
|
CacheType CacheType `json:"cache_type"`
|
|
}
|
|
|
|
// TTL represents cache time-to-live configuration
|
|
type TTL struct {
|
|
Fresh time.Duration // How long the data is considered fresh
|
|
Stale time.Duration // How long stale data can be served (stale-if-error)
|
|
}
|
|
|
|
// CacheLevel represents the cache level where data was found
|
|
type CacheLevel string
|
|
|
|
const (
|
|
CacheLevelL1 CacheLevel = "L1"
|
|
CacheLevelL2 CacheLevel = "L2"
|
|
CacheLevelMiss CacheLevel = "MISS"
|
|
)
|
|
|
|
func (cl CacheLevel) String() string {
|
|
return string(cl)
|
|
}
|
|
|
|
// CacheLevelFromIndex creates a CacheLevel from a cache index.
|
|
// Index 0 returns L1, index 1 returns L2, higher indices return L3, L4, etc.
|
|
// Negative indices are treated as L1 (fallback to first level)
|
|
func CacheLevelFromIndex(index int) CacheLevel {
|
|
if index < 0 {
|
|
return CacheLevelL1
|
|
}
|
|
|
|
switch index {
|
|
case 0:
|
|
return CacheLevelL1
|
|
case 1:
|
|
return CacheLevelL2
|
|
default:
|
|
return CacheLevel(fmt.Sprintf("L%d", index+1))
|
|
}
|
|
}
|
|
|
|
// CacheResult represents the result of a cache operation with level information
|
|
type CacheResult struct {
|
|
Entry *CacheEntry `json:"entry,omitempty"`
|
|
Found bool `json:"found"`
|
|
Level CacheLevel `json:"level"`
|
|
}
|
|
|
|
// CacheEntry represents an entry in the cache with TTL information
|
|
type CacheEntry struct {
|
|
Data []byte `json:"data"`
|
|
ExpiresAt int64 `json:"expires_at"`
|
|
StaleAt int64 `json:"stale_at"`
|
|
CreatedAt int64 `json:"created_at"`
|
|
}
|
|
|
|
// IsExpired checks if the cache entry is completely expired
|
|
func (ce *CacheEntry) IsExpired() bool {
|
|
now := time.Now().Unix()
|
|
return now > ce.ExpiresAt
|
|
}
|
|
|
|
// IsFresh checks if the cache entry is still fresh
|
|
func (ce *CacheEntry) IsFresh() bool {
|
|
now := time.Now().Unix()
|
|
return now <= ce.StaleAt
|
|
}
|
|
|
|
// RemainingTTL calculates the remaining TTL for this cache entry
|
|
func (ce *CacheEntry) RemainingTTL() TTL {
|
|
now := time.Now().Unix()
|
|
|
|
freshRemaining := ce.StaleAt - now
|
|
if freshRemaining < 0 {
|
|
freshRemaining = 0
|
|
}
|
|
|
|
staleRemaining := ce.ExpiresAt - ce.StaleAt
|
|
if staleRemaining < 0 {
|
|
staleRemaining = 0
|
|
}
|
|
|
|
return TTL{
|
|
Fresh: time.Duration(freshRemaining) * time.Second,
|
|
Stale: time.Duration(staleRemaining) * time.Second,
|
|
}
|
|
}
|