package cache import ( "encoding/json" "fmt" redis "gopkg.in/redis.v5" "time" "sync" "bitbucket.org/nemt/nemt-portal-api/domain" "bitbucket.org/nemt/nemt-portal-api/domain/contract" "bitbucket.org/nemt/nemt-portal-api/infra/config" "bitbucket.org/nemt/nemt-portal-api/infra/errors" ) var ( instance *RedisCache once sync.Once ) // RedisCache implements the CacheManager interface type RedisCache struct { cfg *config.Config redis *redis.Client } // Instance returns a CacheManager instance func Instance(cfg *config.Config) contract.CacheManager { once.Do(func() { client := redis.NewFailoverClient(&redis.FailoverOptions{ MasterName: "master01", SentinelAddrs: []string{fmt.Sprintf("%s:%v", cfg.Cache.Server, cfg.Cache.Port)}, Password: cfg.Cache.Pass, DB: cfg.Cache.DB, }) instance = &RedisCache{cfg, client} }) return instance } func (r *RedisCache) buildKey(key string) string { return fmt.Sprintf("%s-%s", r.cfg.Cache.Prefix, key) } // GetItem returns an Item from cache func (r *RedisCache) GetItem(key string) (data []byte, err error) { val, err := r.redis.Get(r.buildKey(key)).Bytes() if err == redis.Nil { return val, domain.ErrCacheMiss } else if err != nil { return val, errors.Wrap(err) } return val, nil } // SetItem sets an item in cache func (r *RedisCache) SetItem(key string, data []byte) error { err := r.redis.Set(r.buildKey(key), data, r.cfg.Cache.DefaultExpiration).Err() if err != nil { return errors.Wrap(err) } return nil } // GetString returns an string from cache func (r *RedisCache) GetString(key string) (data string, err error) { val, err := r.GetItem(key) if err == domain.ErrCacheMiss { return data, domain.ErrCacheMiss } else if err != nil { return data, errors.Wrap(err) } return string(val), nil } // SetString sets an item in cache func (r *RedisCache) SetString(key string, data string) error { err := r.SetItem(key, []byte(data)) if err != nil { return errors.Wrap(err) } return nil } // GetStruct returns an struct from cache func (r *RedisCache) GetStruct(key string, data interface{}) (err error) { val, err := r.GetItem(key) if err == domain.ErrCacheMiss { return domain.ErrCacheMiss } else if err != nil { return errors.Wrap(err) } err = json.Unmarshal(val, &data) if err != nil { return errors.Wrap(err) } return nil } // SetStruct sets an item in cache func (r *RedisCache) SetStruct(key string, data interface{}) error { dataString, err := json.Marshal(data) if err != nil { return errors.Wrap(err) } err = r.SetItem(key, dataString) if err != nil { return errors.Wrap(err) } return nil } // GetExpiration returns the expiration time for a key func (r *RedisCache) GetExpiration(key string) (expiration time.Duration, err error) { expiration, err = r.redis.TTL(r.buildKey(key)).Result() if err != nil { return expiration, errors.Wrap(err) } return expiration, nil } // SetExpiration sets the expiration time for a key func (r *RedisCache) SetExpiration(key string, expiration time.Duration) (err error) { err = r.redis.Expire(r.buildKey(key), expiration).Err() if err != nil { return errors.Wrap(err) } return nil }