add an base driver struct. suppoort auto encode value

This commit is contained in:
inhere
2021-06-27 13:37:32 +08:00
parent ecbadc42b7
commit 9945945c15
19 changed files with 501 additions and 168 deletions

View File

@@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: true
matrix:
go: [ 1.15 ]
go: [ 1.16 ]
steps:
- name: Checkout

View File

@@ -1,18 +0,0 @@
language: go
go:
# - '1.11'
- '1.12'
- '1.13'
- '1.14'
env:
- GO111MODULE=on
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
script:
# - go test -v -cover
- $HOME/gopath/bin/goveralls -v -service=travis-ci

View File

@@ -83,11 +83,11 @@ func main() {
// register one(or some) cache driver
cache.Register(cache.DvrFile, cache.NewFileCache(""))
cache.Register(cache.DvrMemory, cache.NewMemoryCache())
cache.Register(cache.DvrRedis, redis.Connect("127.0.0.1:6379", "", 0))
cache.Register(redis.Name, redis.Connect("127.0.0.1:6379", "", 0))
cache.Register(goredis.Name, goredis.Connect("127.0.0.1:6379", "", 0))
// setting default driver name
cache.DefaultUse(cache.DvrRedis)
cache.DefaultUse(redis.Name)
// quick use.(it is default driver)
//
@@ -108,6 +108,22 @@ func main() {
}
```
## With Options
```go
gords := goredis.Connect("127.0.0.1:6379", "", 0)
gords.WithOptions(cache.WithPrefix("cache_"), cache.WithEncode(true))
cache.Register(goredis.Name, gords)
// set
// real key is: "cache_name"
cache.Set("name", "cache value", cache.TwoMinutes)
// get: "cache value"
val := cache.Get("name")
```
## License
**MIT**

View File

@@ -1,4 +1,4 @@
# cache
# Cache
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/cache?style=flat-square)
[![GoDoc](https://godoc.org/github.com/gookit/cache?status.svg)](https://pkg.go.dev/github.com/gookit/cache)
@@ -8,7 +8,6 @@
> **[EN README](README.md)**
Golang 通用的缓存管理使用库。
通过包装各种常用的驱动屏蔽掉底层各个驱动的不同使用方法来提供统一的使用API。
> 所有缓存驱动程序都实现了 `cache.Cache` 接口。 因此,您可以添加任何自定义驱动程序。
@@ -82,7 +81,7 @@ func main() {
// 注册一个(或多个)缓存驱动
cache.Register(cache.DvrFile, cache.NewFileCache(""))
cache.Register(cache.DvrMemory, cache.NewMemoryCache())
cache.Register(cache.DvrRedis, redis.Connect("127.0.0.1:6379", "", 0))
cache.Register(redis.Name, redis.Connect("127.0.0.1:6379", "", 0))
cache.Register(goredis.Name, goredis.Connect("127.0.0.1:6379", "", 0))
// 设置默认驱动名称
@@ -109,6 +108,22 @@ func main() {
}
```
## 设置选项
```go
gords := goredis.Connect("127.0.0.1:6379", "", 0)
gords.WithOptions(cache.WithPrefix("cache_"), cache.WithEncode(true))
cache.Register(goredis.Name, gords)
// set
// real key is: "cache_name"
cache.Set("name", "cache value", cache.TwoMinutes)
// get: "cache value"
val := cache.Get("name")
```
## License
**[MIT](LICENSE)**

View File

@@ -9,6 +9,8 @@ import (
"go.etcd.io/bbolt"
)
const Name = "boltDB"
// BoltDB definition
type BoltDB struct {
// db file path. eg "path/to/my.db"

View File

@@ -10,6 +10,7 @@ import (
// Memory open a file that does not persist to disk.
const Memory = ":memory:"
const Name = "buntDB"
// BuntDB definition.
type BuntDB struct {

View File

@@ -4,7 +4,6 @@
package cache
import (
"encoding/json"
"time"
"github.com/gookit/gsr"
@@ -75,69 +74,6 @@ const (
OneWeek = 604800 * time.Second
)
type (
// MarshalFunc define
MarshalFunc func(v interface{}) ([]byte, error)
// UnmarshalFunc define
UnmarshalFunc func(data []byte, v interface{}) error
)
// data (Un)marshal func
var (
Marshal MarshalFunc = json.Marshal
Unmarshal UnmarshalFunc = json.Unmarshal
)
/*************************************************************
* base driver
*************************************************************/
// BaseDriver struct
type BaseDriver struct {
Debug bool
Logger gsr.Printer
// Prefix key prefix
Prefix string
// last error
lastErr error
}
// Debugf print an debug message
func (l *BaseDriver) Debugf(format string, v ...interface{}) {
if l.Debug && l.Logger != nil {
l.Logger.Printf(format, v...)
}
}
// Logf print an log message
func (l *BaseDriver) Logf(format string, v ...interface{}) {
if l.Logger != nil {
l.Logger.Printf(format, v...)
}
}
// Key Cache key build
func (l *BaseDriver) Key(key string) string {
if l.Prefix != "" {
return l.Prefix + ":" + key
}
return key
}
// SetLastErr save last error
func (l *BaseDriver) SetLastErr(err error) {
if err != nil {
l.lastErr = err
l.Logf("redis error: %s\n", err.Error())
}
}
// LastErr get
func (l *BaseDriver) LastErr(key string) error {
return l.lastErr
}
/*************************************************************
* config default cache manager
*************************************************************/

167
driver.go Normal file
View File

@@ -0,0 +1,167 @@
package cache
import (
"encoding/json"
"errors"
"github.com/gookit/gsr"
)
type (
// MarshalFunc define
MarshalFunc func(v interface{}) ([]byte, error)
// UnmarshalFunc define
UnmarshalFunc func(data []byte, v interface{}) error
)
// data (Un)marshal func
var (
Marshal MarshalFunc = json.Marshal
Unmarshal UnmarshalFunc = json.Unmarshal
errNoMarshal = errors.New("must set Marshal func")
errNoUnmarshal = errors.New("must set Unmarshal func")
)
// Option struct
type Option struct {
Debug bool
// Encode (Un)marshal save data
Encode bool
Logger gsr.Printer
// Prefix key prefix
Prefix string
}
/*************************************************************
* base driver
*************************************************************/
// BaseDriver struct
type BaseDriver struct {
opt Option
// last error
lastErr error
}
// WithDebug add option: debug
func WithDebug(debug bool) func(opt *Option) {
return func (opt *Option) {
opt.Debug = debug
}
}
// WithEncode add option: encode
func WithEncode(encode bool) func(opt *Option) {
return func (opt *Option) {
opt.Encode = encode
}
}
// WithPrefix add option: prefix
func WithPrefix(prefix string) func(opt *Option) {
return func (opt *Option) {
opt.Prefix = prefix
}
}
// WithOptions for driver
func (l *BaseDriver) WithOptions(optFns ...func(option *Option)) {
for _, optFn := range optFns {
optFn(&l.opt)
}
}
// MustMarshal cache value
func (l *BaseDriver) MustMarshal(val interface{}) ([]byte, error) {
if Marshal != nil {
return nil, errNoMarshal
}
return Marshal(val)
}
// Marshal cache value
func (l *BaseDriver) Marshal(val interface{}) (interface{}, error) {
if Marshal != nil {
return Marshal(val)
}
return val, nil
}
// MustUnmarshal cache value
func (l *BaseDriver) MustUnmarshal(bts []byte, ptr interface{}) error {
if Unmarshal != nil {
return errNoUnmarshal
}
return Unmarshal(bts, ptr)
}
// Unmarshal cache value
func (l *BaseDriver) Unmarshal(val []byte, err error) interface{} {
if err != nil {
l.SetLastErr(err)
return nil
}
var newV interface{}
if Unmarshal != nil {
err := Unmarshal(val, &newV)
l.SetLastErr(err)
return newV
}
return val
}
// GetAs get cache value and unmarshal as ptr.
func (l *BaseDriver) GetAs(key string, ptr interface{}) error {
// TODO bts, err := c.Get(key)
// if Unmarshal != nil {
// err := Unmarshal(bts, ptr)
// return err
// }
return errNoUnmarshal
}
// Key cache key build
func (l *BaseDriver) Key(key string) string {
if l.opt.Prefix != "" {
return l.opt.Prefix + key
}
return key
}
// Debugf print an debug message
func (l *BaseDriver) Debugf(format string, v ...interface{}) {
if l.opt.Debug && l.opt.Logger != nil {
l.opt.Logger.Printf(format, v...)
}
}
// Logf print an log message
func (l *BaseDriver) Logf(format string, v ...interface{}) {
if l.opt.Logger != nil {
l.opt.Logger.Printf(format, v...)
}
}
// SetLastErr save last error
func (l *BaseDriver) SetLastErr(err error) {
if err != nil {
l.lastErr = err
l.Logf("redis error: %s\n", err.Error())
}
}
// LastErr get
func (l *BaseDriver) LastErr(key string) error {
return l.lastErr
}
// IsDebug get
func (l *BaseDriver) IsDebug() bool {
return l.opt.Debug
}

View File

@@ -3,10 +3,10 @@ package cache
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
@@ -17,7 +17,7 @@ type FileCache struct {
// cache directory path
cacheDir string
// cache file prefix
prefix string
// prefix string
// security key for generate cache file name.
securityKey string
}
@@ -35,7 +35,8 @@ func NewFileCache(dir string, pfxAndKey ...string) *FileCache {
}
if ln := len(pfxAndKey); ln > 0 {
c.prefix = pfxAndKey[0]
// c.prefix = pfxAndKey[0]
c.opt.Prefix = pfxAndKey[0]
if ln > 1 {
c.securityKey = pfxAndKey[1]
@@ -73,13 +74,13 @@ func (c *FileCache) get(key string) interface{} {
// read cache from file
bs, err := ioutil.ReadFile(c.GetFilename(key))
if err != nil {
c.lastErr = err
c.SetLastErr(err)
return nil
}
item := &Item{}
if err = Unmarshal(bs, item); err != nil {
c.lastErr = err
if err = c.MustUnmarshal(bs, item); err != nil {
c.SetLastErr(err)
return nil
}
@@ -90,7 +91,7 @@ func (c *FileCache) get(key string) interface{} {
}
// has been expired. delete it.
c.lastErr = c.del(key)
c.SetLastErr(c.del(key))
return nil
}
@@ -104,21 +105,21 @@ func (c *FileCache) Set(key string, val interface{}, ttl time.Duration) (err err
func (c *FileCache) set(key string, val interface{}, ttl time.Duration) (err error) {
if err = c.MemoryCache.set(key, val, ttl); err != nil {
c.lastErr = err
c.SetLastErr(err)
return
}
// cache item data to file
bs, err := Marshal(c.caches[key])
bs, err := c.MustMarshal(c.caches[key])
if err != nil {
c.lastErr = err
c.SetLastErr(err)
return
}
file := c.GetFilename(key)
dir := filepath.Dir(file)
if err = os.MkdirAll(dir, 0755); err != nil {
c.lastErr = err
c.SetLastErr(err)
return
}
@@ -144,7 +145,9 @@ func (c *FileCache) Del(key string) error {
}
func (c *FileCache) del(key string) error {
c.lastErr = c.MemoryCache.del(key)
if err := c.MemoryCache.del(key); err != nil {
return err
}
file := c.GetFilename(key)
if fileExists(file) {
@@ -177,7 +180,6 @@ func (c *FileCache) SetMulti(values map[string]interface{}, ttl time.Duration) (
return
}
}
return
}
@@ -227,7 +229,13 @@ func (c *FileCache) GetFilename(key string) string {
str := hex.EncodeToString(h.Sum(nil))
return fmt.Sprintf("%s/%s/%s.data", c.cacheDir, str[0:6], c.prefix+str)
// return fmt.Sprintf("%s/%s/%s.data", c.cacheDir, str[0:6], c.prefix+str)
return strings.Join([]string{
c.cacheDir,
str[0:6],
c.opt.Prefix+str,
".data",
}, "/")
}
// fileExists reports whether the named file or directory exists.

View File

@@ -7,6 +7,7 @@ import (
// MemoryCache definition.
type MemoryCache struct {
BaseDriver
// locker
lock sync.RWMutex
// cache data in memory. or use sync.Map
@@ -163,8 +164,3 @@ func (c *MemoryCache) DumpDB(file string) error {
func (c *MemoryCache) Iter(file string) error {
return nil
}
// LastErr get
func (c *MemoryCache) LastErr() error {
return c.lastErr
}

View File

@@ -1,10 +1,13 @@
package cache_test
import (
"math/rand"
"strconv"
"testing"
"time"
"github.com/gookit/cache"
"github.com/gookit/goutil/dump"
"github.com/stretchr/testify/assert"
)
@@ -28,7 +31,34 @@ func TestNewMemoryCache(t *testing.T) {
is.False(c.Has(key))
}
func TestMemoryCache_Get_expired(t *testing.T) {
func TestMemoryCache_object(t *testing.T) {
is := assert.New(t)
type user struct {
Age int
Name string
}
b1 := user {
Age: 1,
Name: "inhere",
}
c := cache.NewMemoryCache()
key := randomKey()
t.Log("cache key:", key)
is.False(c.Has(key))
err := c.Set(key, b1, cache.Seconds3)
is.NoError(err)
is.True(c.Has(key))
b2 := c.Get(key).(user)
dump.P(b2)
is.Equal("inhere", b2.Name)
}
func TestMemoryCache_expired(t *testing.T) {
is := assert.New(t)
c := cache.NewMemoryCache()
@@ -47,8 +77,8 @@ func TestMemoryCache_Get_expired(t *testing.T) {
func TestNewFileCache(t *testing.T) {
is := assert.New(t)
c := cache.NewFileCache("./testdata")
key := "key"
key := "key"
is.False(c.Has(key))
// set
@@ -68,3 +98,8 @@ func TestNewFileCache(t *testing.T) {
is.NoError(err)
is.False(c.Has(key))
}
func randomKey() string {
rand.Seed(time.Now().UnixNano())
return "k" + time.Now().Format("20060102") + strconv.Itoa(rand.Intn(999))
}

View File

@@ -6,13 +6,14 @@ import (
"github.com/gookit/cache"
"github.com/gookit/cache/goredis"
"github.com/gookit/cache/redis"
"github.com/gookit/goutil/dump"
)
func Example() {
// register some cache driver
cache.Register(cache.DvrFile, cache.NewFileCache(""))
cache.Register(cache.DvrMemory, cache.NewMemoryCache())
cache.Register(cache.DvrRedis, redis.Connect("127.0.0.1:6379", "", 0))
cache.Register(redis.Name, redis.Connect("127.0.0.1:6379", "", 0))
cache.Register(goredis.Name, goredis.Connect("127.0.0.1:6379", "", 0))
// setting default driver name
@@ -79,3 +80,20 @@ func ExampleFileCache() {
// cache value
// false
}
func Example_withOptions() {
gords := goredis.Connect("127.0.0.1:6379", "", 0)
gords.WithOptions(cache.WithPrefix("cache_"), cache.WithEncode(true))
// register
cache.Register(goredis.Name, gords)
// set
// real key is: "cache_name"
cache.Set("name", "cache value", cache.TwoMinutes)
// get: "cache value"
val := cache.Get("name")
dump.P(val)
}

1
go.mod
View File

@@ -11,6 +11,7 @@ require (
github.com/go-redis/redis/v8 v8.10.0
github.com/golang/snappy v0.0.1 // indirect
github.com/gomodule/redigo v2.0.0+incompatible
github.com/gookit/goutil v0.3.14
github.com/gookit/gsr v0.0.2
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1 // indirect

22
go.sum
View File

@@ -66,19 +66,30 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/goutil v0.3.14 h1:ZEdZR+Vkvcjz0SSC0MpjtD+Kwlg/uagpiddh6L2ko+0=
github.com/gookit/goutil v0.3.14/go.mod h1:YdGV0ObqRUlRq4/RzAQBHcd1Wzl/jKw7cppDBtD3q+U=
github.com/gookit/gsr v0.0.2 h1:yerDAhSeW8BHhQYksESoDQslAZV1ig+ytxUXDPXE9TM=
github.com/gookit/gsr v0.0.2/go.mod h1:oCrmIEBod7DNBBFP5sckUY2yrOmJgNpG3xyxryLyJKY=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -112,7 +123,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@@ -136,6 +149,8 @@ github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSR
github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
@@ -152,6 +167,7 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -181,12 +197,16 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@@ -45,7 +45,7 @@ func New(url, pwd string, dbNum int) *GoRedis {
// String get
func (c *GoRedis) String() string {
pwd := "*"
if c.Debug {
if c.IsDebug() {
pwd = c.pwd
}
@@ -91,17 +91,18 @@ func (c *GoRedis) Has(key string) bool {
// Get cache by key
func (c *GoRedis) Get(key string) interface{} {
str, err := c.rdb.Get(CtxForExec, c.Key(key)).Result()
if err != nil {
c.SetLastErr(err)
return nil
}
bts, err := c.rdb.Get(CtxForExec, c.Key(key)).Bytes()
return str
return c.Unmarshal(bts, err)
}
// Set cache by key
func (c *GoRedis) Set(key string, val interface{}, ttl time.Duration) (err error) {
val, err = c.Marshal(val)
if err != nil {
return err
}
return c.rdb.SetEX(CtxForExec, c.Key(key), val, ttl).Err()
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/gookit/cache"
"github.com/gookit/cache/goredis"
"github.com/gookit/goutil/dump"
"github.com/stretchr/testify/assert"
)
@@ -29,16 +30,69 @@ func Example() {
fmt.Print(val)
}
func TestGoRedis_Get(t *testing.T) {
c := goredis.New("127.0.0.1:6379", "", 0).Connect()
c.Prefix = "gr_"
var c *goredis.GoRedis
func getC() *goredis.GoRedis {
if c != nil {
return c
}
c = goredis.New("127.0.0.1:6379", "", 0).Connect()
c.WithOptions(cache.WithPrefix("gr"), cache.WithEncode(true))
return c
}
func TestGoRedis_basic(t *testing.T) {
c := getC()
key := randomKey()
t.Log("cache key", key)
assert.False(t, c.Has(key))
err := c.Set(key, "value", cache.Seconds3)
assert.NoError(t, err)
assert.True(t, c.Has(key))
assert.Equal(t, "value", c.Get(key).(string))
err = c.Del(key)
assert.NoError(t, err)
assert.False(t, c.Has(key))
}
type user struct {
Age int
Name string
}
func TestRedigo_object(t *testing.T) {
c := getC()
b1 := user {
Age: 12,
Name: "inhere",
}
key := randomKey()
t.Log("cache key", c.Key(key))
assert.False(t, c.Has(key))
err := c.Set(key, b1, cache.Seconds3)
assert.NoError(t, err)
assert.True(t, c.Has(key))
v := c.Get(key)
assert.NotEmpty(t, v)
// dump.P(v.(string))
dump.P(v)
err = c.Del(key)
assert.NoError(t, err)
assert.False(t, c.Has(key))
assert.Empty(t, c.Get(key))
}
func randomKey() string {

View File

@@ -1,16 +1,27 @@
package memcached
package memcached_test
import "fmt"
import (
"fmt"
"github.com/gookit/cache/memcached"
)
func Example() {
c := New("10.0.0.1:11211", "10.0.0.2:11211")
c := memcached.Connect("10.0.0.1:11211", "10.0.0.2:11211")
// set
c.Set("name", "cache value", 60)
err := c.Set("name", "cache value", 60)
if err != nil {
panic(err)
}
// get
val := c.Get("name")
// del
c.Del("name")
err = c.Del("name")
if err != nil {
panic(err)
}
// get: "cache value"
fmt.Print(val)

View File

@@ -1,5 +1,5 @@
// Package redis is a simple redis cache implement.
// base on the package: github.com/gomodule/redigo
// base on the package: https://github.com/gomodule/redigo
package redis
import (
@@ -11,10 +11,14 @@ import (
"github.com/gookit/cache"
)
const Name = "redigo"
// RedisCache fallback alias
type RedisCache = RediGo
// RediGo definition. redigo doc link: https://godoc.org/github.com/gomodule/redigo/redis
type RediGo struct {
type RedisCache = Redigo
// Redigo driver definition.
// redigo doc link: https://pkg.go.dev/github.com/gomodule/redigo/redis#pkg-examples
type Redigo struct {
cache.BaseDriver
// redis connection pool
pool *redis.Pool
@@ -25,8 +29,8 @@ type RediGo struct {
}
// New redis cache
func New(url, pwd string, dbNum int) *RediGo {
rc := &RediGo{
func New(url, pwd string, dbNum int) *Redigo {
rc := &Redigo{
url: url, pwd: pwd, dbNum: dbNum,
}
@@ -34,12 +38,12 @@ func New(url, pwd string, dbNum int) *RediGo {
}
// Connect create and connect to redis server
func Connect(url, pwd string, dbNum int) *RediGo {
func Connect(url, pwd string, dbNum int) *Redigo {
return New(url, pwd, dbNum).Connect()
}
// Connect to redis server
func (c *RediGo) Connect() *RediGo {
func (c *Redigo) Connect() *Redigo {
c.pool = newPool(c.url, c.pwd, c.dbNum)
c.Logf("connect to server %s db is %d", c.url, c.dbNum)
@@ -51,34 +55,31 @@ func (c *RediGo) Connect() *RediGo {
*************************************************************/
// Get value by key
func (c *RediGo) Get(key string) interface{} {
val, err := c.exec("Get", c.Key(key))
if err != nil {
c.SetLastErr(err)
return nil
}
func (c *Redigo) Get(key string) interface{} {
val, err := redis.Bytes(c.exec("Get", c.Key(key)))
return val
return c.Unmarshal(val, err)
}
// Set value by key
func (c *RediGo) Set(key string, val interface{}, ttl time.Duration) (err error) {
// bs, _ := cache.Marshal(val)
// _, err = c.exec("SetEx", c.Key(key), int64(ttl/time.Second), bs)
func (c *Redigo) Set(key string, val interface{}, ttl time.Duration) (err error) {
val, err = c.Marshal(val)
if err != nil {
return err
}
_, err = c.exec("SetEx", c.Key(key), int64(ttl/time.Second), val)
return
}
// Del value by key
func (c *RediGo) Del(key string) (err error) {
func (c *Redigo) Del(key string) (err error) {
_, err = c.exec("Del", c.Key(key))
c.SetLastErr(err)
return
}
// Has cache key
func (c *RediGo) Has(key string) bool {
func (c *Redigo) Has(key string) bool {
// return 0 OR 1
one, err := redis.Int(c.exec("Exists", c.Key(key)))
c.SetLastErr(err)
@@ -87,16 +88,16 @@ func (c *RediGo) Has(key string) bool {
}
// GetMulti values by keys
func (c *RediGo) GetMulti(keys []string) map[string]interface{} {
func (c *Redigo) GetMulti(keys []string) map[string]interface{} {
conn := c.pool.Get()
defer conn.Close()
var args []interface{}
args := make([]interface{}, 0, len(keys))
for _, key := range keys {
args = append(args, c.Key(key))
}
list, err := redis.Values(conn.Do("MGet", args...))
list, err := redis.Values(c.exec("MGet", args...))
if err != nil {
c.SetLastErr(err)
return nil
@@ -111,7 +112,7 @@ func (c *RediGo) GetMulti(keys []string) map[string]interface{} {
}
// SetMulti values
func (c *RediGo) SetMulti(values map[string]interface{}, ttl time.Duration) (err error) {
func (c *Redigo) SetMulti(values map[string]interface{}, ttl time.Duration) (err error) {
conn := c.pool.Get()
defer conn.Close()
@@ -133,29 +134,24 @@ func (c *RediGo) SetMulti(values map[string]interface{}, ttl time.Duration) (err
}
// DelMulti values by keys
func (c *RediGo) DelMulti(keys []string) (err error) {
conn := c.pool.Get()
defer conn.Close()
var args []interface{}
func (c *Redigo) DelMulti(keys []string) (err error) {
args := make([]interface{}, 0, len(keys))
for _, key := range keys {
args = append(args, c.Key(key))
}
_, err = conn.Do("Del", args...)
_, err = c.exec("Del", args...)
return
}
// Close connection
func (c *RediGo) Close() error {
func (c *Redigo) Close() error {
return c.pool.Close()
}
// Clear all caches
func (c *RediGo) Clear() error {
conn := c.pool.Get()
defer conn.Close()
_, err := conn.Do("FlushDb")
func (c *Redigo) Clear() error {
_, err := c.exec("FlushDb")
return err
}
@@ -164,14 +160,14 @@ func (c *RediGo) Clear() error {
*************************************************************/
// Pool get
func (c *RediGo) Pool() *redis.Pool {
func (c *Redigo) Pool() *redis.Pool {
return c.pool
}
// String get
func (c *RediGo) String() string {
func (c *Redigo) String() string {
pwd := "*"
if c.Debug {
if c.IsDebug() {
pwd = c.pwd
}
@@ -179,7 +175,7 @@ func (c *RediGo) String() string {
}
// actually do the redis cmds, args[0] must be the key name.
func (c *RediGo) exec(commandName string, args ...interface{}) (reply interface{}, err error) {
func (c *Redigo) exec(commandName string, args ...interface{}) (reply interface{}, err error) {
if len(args) < 1 {
return nil, errors.New("missing required arguments")
}
@@ -187,7 +183,7 @@ func (c *RediGo) exec(commandName string, args ...interface{}) (reply interface{
conn := c.pool.Get()
defer conn.Close()
if c.Debug {
if c.IsDebug() {
st := time.Now()
reply, err = conn.Do(commandName, args...)
c.Logf(

View File

@@ -2,8 +2,15 @@ package redis_test
import (
"fmt"
"math/rand"
"strconv"
"testing"
"time"
"github.com/gookit/cache"
"github.com/gookit/cache/redis"
"github.com/gookit/goutil/dump"
"github.com/stretchr/testify/assert"
)
func Example() {
@@ -22,3 +29,70 @@ func Example() {
// get: "cache value"
fmt.Print(val)
}
var c *redis.Redigo
func getC() *redis.Redigo {
if c != nil {
return c
}
c = redis.New("127.0.0.1:6379", "", 0).Connect()
c.WithOptions(cache.WithPrefix("rdg"), cache.WithEncode(true))
return c
}
func TestRedigo_basic(t *testing.T) {
c := getC()
key := randomKey()
t.Log("cache key", c.Key(key))
assert.False(t, c.Has(key))
err := c.Set(key, "value", cache.Seconds3)
assert.NoError(t, err)
assert.True(t, c.Has(key))
assert.Equal(t, "value", c.Get(key))
err = c.Del(key)
assert.NoError(t, err)
assert.False(t, c.Has(key))
}
type user struct {
Age int
Name string
}
func TestRedigo_object(t *testing.T) {
c := getC()
b1 := user {
Age: 12,
Name: "inhere",
}
key := randomKey()
t.Log("cache key", c.Key(key))
assert.False(t, c.Has(key))
err := c.Set(key, b1, cache.Seconds3)
assert.NoError(t, err)
assert.True(t, c.Has(key))
v := c.Get(key)
assert.NotEmpty(t, v)
// dump.P(v.(string))
dump.P(v)
err = c.Del(key)
assert.NoError(t, err)
assert.False(t, c.Has(key))
assert.Empty(t, c.Get(key))
}
func randomKey() string {
return "k" + time.Now().Format("20060102") + strconv.Itoa(rand.Intn(999))
}