223 lines
4.8 KiB
Go
223 lines
4.8 KiB
Go
|
package localcache
|
|||
|
|
|||
|
import (
|
|||
|
"encoding/json"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"github.com/winc-link/hummingbird/internal/pkg/cache"
|
|||
|
"strings"
|
|||
|
"time"
|
|||
|
|
|||
|
gocache "github.com/patrickmn/go-cache"
|
|||
|
)
|
|||
|
|
|||
|
var defaultTime = 24 * 60 * time.Minute
|
|||
|
|
|||
|
var (
|
|||
|
Nil = errors.New("cache:nil")
|
|||
|
KeyNull = errors.New("key is null")
|
|||
|
ValueNull = errors.New("value is null")
|
|||
|
FieldNull = errors.New("field is null")
|
|||
|
HashSetFieldTypeError = errors.New("hash set field's type is not string")
|
|||
|
FieldValueNumberError = errors.New("hash set field and value number is fault")
|
|||
|
)
|
|||
|
|
|||
|
type RamCacheClient struct {
|
|||
|
c *gocache.Cache
|
|||
|
}
|
|||
|
|
|||
|
func NewRamCacheClient() cache.Cache {
|
|||
|
return &RamCacheClient{
|
|||
|
c: gocache.New(gocache.DefaultExpiration, gocache.DefaultExpiration),
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) invalidKey(key string) error {
|
|||
|
if key == "" {
|
|||
|
return KeyNull
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) invalidField(field string) error {
|
|||
|
if field == "" {
|
|||
|
return FieldNull
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) invalidValue(value string) error {
|
|||
|
if value == "" {
|
|||
|
return ValueNull
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) invalidKeyValue(key, value string) error {
|
|||
|
if err := rcc.invalidKey(key); err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
return rcc.invalidValue(value)
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) invalidFieldValue(field, value string) error {
|
|||
|
if err := rcc.invalidField(field); err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
return rcc.invalidValue(value)
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) SetOneDay(key string, value interface{}) error {
|
|||
|
val, err := marshalValue(value)
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
if err = rcc.invalidKeyValue(key, val); err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
rcc.c.Set(key, val, defaultTime)
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) Set(key string, value interface{}, expiration time.Duration) error {
|
|||
|
val, err := marshalValue(value)
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
if err = rcc.invalidKeyValue(key, val); err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
rcc.c.Set(key, val, expiration)
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) Get(key string) (data string, err error) {
|
|||
|
value, exist := rcc.c.Get(key)
|
|||
|
if !exist {
|
|||
|
return "", Nil
|
|||
|
}
|
|||
|
data = value.(string)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) Del(keys ...string) error {
|
|||
|
for _, key := range keys {
|
|||
|
rcc.c.Delete(key)
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) getHashCache(key string) (*gocache.Cache, bool, error) {
|
|||
|
if err := rcc.invalidKey(key); err != nil {
|
|||
|
return nil, false, err
|
|||
|
}
|
|||
|
data, exist := rcc.c.Get(key)
|
|||
|
if !exist {
|
|||
|
return nil, false, nil
|
|||
|
}
|
|||
|
value := data.(*gocache.Cache)
|
|||
|
return value, true, nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) HSet(key string, values ...interface{}) error {
|
|||
|
hashCache, exist, err := rcc.getHashCache(key)
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
if !exist {
|
|||
|
hashCache = gocache.New(gocache.DefaultExpiration, gocache.DefaultExpiration)
|
|||
|
}
|
|||
|
var field, val string
|
|||
|
for i := 0; i < len(values); i += 2 {
|
|||
|
// 防止panic,此处对hash set field做类型断言
|
|||
|
switch values[i].(type) {
|
|||
|
case string:
|
|||
|
field = values[i].(string)
|
|||
|
default:
|
|||
|
err = HashSetFieldTypeError
|
|||
|
return err
|
|||
|
}
|
|||
|
// hash set的field和value数目不匹配
|
|||
|
if i+1 >= len(values) {
|
|||
|
err = FieldValueNumberError
|
|||
|
return err
|
|||
|
}
|
|||
|
val, err = marshalValue(values[i+1])
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
field = fmt.Sprintf("%v:%v", key, field)
|
|||
|
if err = rcc.invalidFieldValue(field, val); err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
hashCache.Set(field, val, gocache.DefaultExpiration)
|
|||
|
}
|
|||
|
rcc.c.Set(key, hashCache, gocache.DefaultExpiration)
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) HGet(key, field string) (string, error) {
|
|||
|
hashCache, exist, err := rcc.getHashCache(key)
|
|||
|
if err != nil {
|
|||
|
return "", err
|
|||
|
}
|
|||
|
if !exist {
|
|||
|
return "", Nil
|
|||
|
}
|
|||
|
var value interface{}
|
|||
|
value, exist = hashCache.Get(fmt.Sprintf("%v:%v", key, field))
|
|||
|
if !exist {
|
|||
|
return "", Nil
|
|||
|
}
|
|||
|
return value.(string), nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) HDel(key string, fields ...string) error {
|
|||
|
hashCache, exist, err := rcc.getHashCache(key)
|
|||
|
if err != nil {
|
|||
|
return err
|
|||
|
}
|
|||
|
if !exist {
|
|||
|
return nil
|
|||
|
}
|
|||
|
for _, field := range fields {
|
|||
|
hashCache.Delete(fmt.Sprintf("%v:%v", key, field))
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) HGetAll(key string) (map[string]string, error) {
|
|||
|
hashCache, exist, err := rcc.getHashCache(key)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
var mp = make(map[string]string)
|
|||
|
if !exist {
|
|||
|
return make(map[string]string), nil
|
|||
|
}
|
|||
|
for k, v := range hashCache.Items() {
|
|||
|
mp[strings.TrimPrefix(strings.TrimPrefix(k, key), ":")] = v.Object.(string)
|
|||
|
}
|
|||
|
return mp, nil
|
|||
|
}
|
|||
|
|
|||
|
func (rcc *RamCacheClient) Close() {
|
|||
|
rcc.c.Flush()
|
|||
|
}
|
|||
|
|
|||
|
func marshalValue(value interface{}) (string, error) {
|
|||
|
if value == nil {
|
|||
|
return "", ValueNull
|
|||
|
}
|
|||
|
switch value.(type) {
|
|||
|
case string:
|
|||
|
return value.(string), nil
|
|||
|
default:
|
|||
|
data, err := json.Marshal(value)
|
|||
|
if err != nil {
|
|||
|
return "", err
|
|||
|
}
|
|||
|
return string(data), nil
|
|||
|
}
|
|||
|
}
|