package cache import ( "encoding/json" "fiskerinc.com/modules/common" orm "fiskerinc.com/modules/db/queries" "fmt" "github.com/ReneKroon/ttlcache/v2" "github.com/pkg/errors" "sync" "time" ) var ( ErrCacheNotInitialized = errors.New("cache is not initialized") ) type VehicleCacher interface { Set(key VehiclesTTLParams, value *VehiclesTTLResult) error Get(key VehiclesTTLParams) (*VehiclesTTLResult, error) } type VehiclesCache struct { duration time.Duration limit int cache *ttlcache.Cache onceCache *sync.Once } func (c *VehiclesCache) Duration() time.Duration { return c.duration } func (c *VehiclesCache) Limit() int { return c.limit } func (c *VehiclesCache) Once() *sync.Once { return c.onceCache } func (c *VehiclesCache) SetCache(cache *ttlcache.Cache) { c.cache = cache } func (c *VehiclesCache) Cache() *ttlcache.Cache { return c.cache } type VehiclesTTLParams struct { Options orm.PageQueryOptions `json:"options"` CarOnlineFilter *common.CarOnlineFilter `json:"car_online_filter"` Search string `json:"search"` } type VehiclesTTLResult struct { Data []common.Car `json:"data"` Total int `json:"total"` } func NewVehiclesCache(duration time.Duration, limit int) (*VehiclesCache, error) { c := &VehiclesCache{ duration: duration, limit: limit, onceCache: &sync.Once{}, } if cache := logCache(c); cache == nil { return nil, ErrCacheNotInitialized } return c, nil } func (c *VehiclesCache) Set(key VehiclesTTLParams, value *VehiclesTTLResult) error { if cache := logCache(c); cache == nil { return ErrCacheNotInitialized } keyBts, err := json.Marshal(key) if err != nil { return errors.WithMessagef(err, "failed to marshal key") } return c.cache.Set(string(keyBts), value) } func (c *VehiclesCache) Get(key VehiclesTTLParams) (*VehiclesTTLResult, error) { if cache := logCache(c); cache == nil { return nil, ErrCacheNotInitialized } keyBts, err := json.Marshal(key) if err != nil { return nil, errors.WithMessagef(err, "failed to marshal key") } value, err := c.cache.Get(string(keyBts)) if err != nil { return nil, fmt.Errorf("failed to get value from cache: %w", err) } return value.(*VehiclesTTLResult), nil } type Cacher interface { Duration() time.Duration Limit() int Once() *sync.Once Cache() *ttlcache.Cache SetCache(*ttlcache.Cache) } func logCache(cacher Cacher) *ttlcache.Cache { cacher.Once().Do(func() { if cacher.Cache() == nil { cache := ttlcache.NewCache() cache.SetTTL(cacher.Duration()) cache.SetCacheSizeLimit(cacher.Limit()) cacher.SetCache(cache) } }) return cacher.Cache() }