2019-10-02 04:10:27 +00:00
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2019-10-03 00:17:34 +00:00
|
|
|
"github.com/vmihailenco/msgpack/v4"
|
2019-10-02 04:10:27 +00:00
|
|
|
"net/url"
|
2019-10-03 00:17:34 +00:00
|
|
|
"strconv"
|
2019-10-02 04:10:27 +00:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
Memcache = "memcache"
|
|
|
|
Redis = "redis"
|
2019-10-03 00:17:34 +00:00
|
|
|
Memory = "memory"
|
2019-10-02 04:10:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrInvalidDriver = errors.New("invalid driver")
|
|
|
|
)
|
|
|
|
|
|
|
|
type CacheInterface interface {
|
|
|
|
Has(key string) bool
|
2019-10-03 00:17:34 +00:00
|
|
|
Get(key string, dst ...interface{}) ([]byte, error)
|
2019-10-02 04:10:27 +00:00
|
|
|
Set(key string, val interface{}, ttl time.Duration) (err error)
|
|
|
|
Del(key string) error
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(uri string) (CacheInterface, error) {
|
|
|
|
u, err := url.Parse(uri)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
query := u.Query()
|
|
|
|
|
|
|
|
switch u.Scheme {
|
|
|
|
case Redis:
|
|
|
|
return NewRedisCache(RedisSettings{
|
|
|
|
Address: u.Host,
|
|
|
|
Password: query.Get("password"),
|
|
|
|
})
|
|
|
|
case Memcache:
|
|
|
|
return NewMemcacheCache(MemcacheSettings{
|
|
|
|
Servers: strings.Split(u.Host, ","),
|
|
|
|
})
|
2019-10-03 00:17:34 +00:00
|
|
|
case Memory:
|
|
|
|
cleanupTime := query.Get("cleanupTime")
|
|
|
|
|
|
|
|
if cleanupTime == "" {
|
|
|
|
cleanupTime = "30"
|
|
|
|
}
|
|
|
|
|
|
|
|
i, err := strconv.Atoi(cleanupTime)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewMemoryCache(time.Duration(i) * time.Second)
|
2019-10-02 04:10:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil, ErrInvalidDriver
|
|
|
|
}
|
2019-10-03 00:17:34 +00:00
|
|
|
|
|
|
|
func encodeValue(val interface{}) ([]byte, error) {
|
|
|
|
var v []byte
|
|
|
|
|
|
|
|
if b, ok := val.([]byte); ok {
|
|
|
|
v = b
|
|
|
|
} else if s, ok := val.(string); ok {
|
|
|
|
b = []byte(s)
|
|
|
|
} else {
|
|
|
|
b, err := msgpack.Marshal(val)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
v = b
|
|
|
|
}
|
|
|
|
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeDst(b []byte, v interface{}) ([]byte, error) {
|
|
|
|
switch v := v.(type) {
|
|
|
|
case *[]byte:
|
|
|
|
if v != nil {
|
|
|
|
*v = b
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
case *string:
|
|
|
|
if v != nil {
|
|
|
|
*v = string(b)
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err := msgpack.Unmarshal(b, v)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return b, nil
|
|
|
|
}
|