cacheinterface/memory.go

179 lines
3.0 KiB
Go

package cache
import (
"errors"
"github.com/patrickmn/go-cache"
"github.com/vmihailenco/msgpack/v4"
"reflect"
"time"
)
var (
ErrMemoryCacheNotExists = errors.New("item does not exist")
ErrMemoryCacheNotSupported = errors.New("memory cache does not support retrieving items without a destination pointer")
)
type MemoryCache struct {
c *cache.Cache
}
func NewMemoryCache(cleanupTime time.Duration) (CacheInterface, error) {
c := cache.New(1*time.Minute, cleanupTime)
return &MemoryCache{c: c}, nil
}
func (mc *MemoryCache) Has(key string) bool {
_, exists := mc.c.Get(key)
return exists
}
func (mc *MemoryCache) Get(key string, dst ...interface{}) ([]byte, error) {
item, exists := mc.c.Get(key)
if !exists {
return nil, ErrMemoryCacheNotExists
}
if len(dst) == 0 {
switch item.(type) {
case string:
return []byte(item.(string)), nil
case []byte:
return item.([]byte), nil
}
return msgpack.Marshal(item)
}
v := dst[0]
switch v := v.(type) {
case *string:
if v != nil {
*v = item.(string)
return nil, nil
}
case *[]byte:
if v != nil {
*v = item.([]byte)
return nil, nil
}
case *int:
if v != nil {
*v = item.(int)
return nil, nil
}
case *int8:
if v != nil {
*v = item.(int8)
return nil, nil
}
case *int16:
if v != nil {
*v = item.(int16)
return nil, nil
}
case *int32:
if v != nil {
*v = item.(int32)
return nil, nil
}
case *int64:
if v != nil {
*v = item.(int64)
return nil, nil
}
case *uint:
if v != nil {
*v = item.(uint)
return nil, nil
}
case *uint8:
if v != nil {
*v = item.(uint8)
return nil, nil
}
case *uint16:
if v != nil {
*v = item.(uint16)
return nil, nil
}
case *uint32:
if v != nil {
*v = item.(uint32)
return nil, nil
}
case *uint64:
if v != nil {
*v = item.(uint64)
return nil, nil
}
case *bool:
if v != nil {
*v = item.(bool)
return nil, nil
}
case *float32:
if v != nil {
*v = item.(float32)
return nil, nil
}
case *float64:
if v != nil {
*v = item.(float64)
return nil, nil
}
case *[]string:
*v = item.([]string)
return nil, nil
case *map[string]string:
*v = item.(map[string]string)
return nil, nil
case *map[string]interface{}:
*v = item.(map[string]interface{})
return nil, nil
case *time.Duration:
if v != nil {
*v = item.(time.Duration)
return nil, nil
}
case *time.Time:
if v != nil {
*v = item.(time.Time)
return nil, nil
}
}
vv := reflect.ValueOf(dst[0])
if !vv.IsValid() {
return nil, errors.New("dst pointer is not valid")
}
if vv.Kind() != reflect.Ptr {
return nil, errors.New("dst pointer is not a pointer")
}
vv = vv.Elem()
if !vv.IsValid() {
return nil, errors.New("dst pointer is not a valid element")
}
vv.Set(reflect.ValueOf(item))
return nil, nil
}
func (mc *MemoryCache) Set(key string, val interface{}, ttl time.Duration) error {
mc.c.Set(key, val, ttl)
return nil
}
func (mc *MemoryCache) Del(key string) error {
mc.c.Delete(key)
return nil
}