Initial commit
This commit is contained in:
commit
a205315b2f
|
@ -0,0 +1,26 @@
|
|||
CacheInterface
|
||||
--------------
|
||||
|
||||
An experimental interface to use different caches interchangeably via URIs
|
||||
|
||||
Example Cache URIs:
|
||||
|
||||
```
|
||||
redis://server:port?db=0&password=test
|
||||
memcache://server1:11211,server2:11211
|
||||
```
|
||||
|
||||
Code
|
||||
####
|
||||
|
||||
The CacheInterface interface has all methods. All clients will implement this on a best-effort basis.
|
||||
|
||||
```go
|
||||
type CacheInterface interface {
|
||||
Has(key string) bool
|
||||
Get(key string) ([]byte, error)
|
||||
Set(key string, val interface{}, ttl time.Duration) (err error)
|
||||
Del(key string) error
|
||||
}
|
||||
```
|
||||
Note: Set will automatically attempt to store byte arrays and strings directly, and encode the rest with JSON.
|
|
@ -0,0 +1,48 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Memcache = "memcache"
|
||||
Redis = "redis"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidDriver = errors.New("invalid driver")
|
||||
)
|
||||
|
||||
type CacheInterface interface {
|
||||
Has(key string) bool
|
||||
Get(key string) ([]byte, error)
|
||||
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, ","),
|
||||
})
|
||||
}
|
||||
|
||||
return nil, ErrInvalidDriver
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/bradfitz/gomemcache/memcache"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MemcacheSettings struct {
|
||||
Servers []string
|
||||
}
|
||||
|
||||
type MemcacheCache struct {
|
||||
backend *memcache.Client
|
||||
}
|
||||
|
||||
func NewMemcacheCache(s MemcacheSettings) (CacheInterface, error) {
|
||||
c := memcache.New(s.Servers...)
|
||||
|
||||
return &MemcacheCache{
|
||||
backend: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (mc *MemcacheCache) Has(key string) bool {
|
||||
_, err := mc.backend.Get(key)
|
||||
|
||||
return err != nil
|
||||
}
|
||||
|
||||
func (mc *MemcacheCache) Get(key string) ([]byte, error) {
|
||||
item, err := mc.backend.Get(key)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return item.Value, nil
|
||||
}
|
||||
|
||||
func (mc *MemcacheCache) Set(key string, val interface{}, ttl time.Duration) 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 := json.Marshal(val)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v = b
|
||||
}
|
||||
|
||||
return mc.backend.Set(&memcache.Item{Key: key, Value: v, Expiration: int32(ttl.Seconds())})
|
||||
}
|
||||
|
||||
func (mc *MemcacheCache) Del(key string) error {
|
||||
return mc.backend.Delete(key)
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/hoisie/redis"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RedisSettings struct {
|
||||
Address string
|
||||
DB int
|
||||
Password string
|
||||
}
|
||||
|
||||
type RedisCache struct {
|
||||
CacheInterface
|
||||
|
||||
c *redis.Client
|
||||
}
|
||||
|
||||
func NewRedisCache(c RedisSettings) (CacheInterface, error) {
|
||||
rc := &redis.Client{Addr: c.Address, Db: c.DB, Password: c.Password}
|
||||
|
||||
return &RedisCache{
|
||||
c: rc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (rc *RedisCache) Has(key string) bool {
|
||||
b, _ := rc.c.Exists(key)
|
||||
return b
|
||||
}
|
||||
|
||||
func (rc *RedisCache) Get(key string) ([]byte, error) {
|
||||
return rc.c.Get(key)
|
||||
}
|
||||
|
||||
func (rc *RedisCache) Set(key string, val interface{}, ttl time.Duration) 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 := json.Marshal(val)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v = b
|
||||
}
|
||||
|
||||
return rc.c.Setex(key, int64(ttl.Seconds()), v)
|
||||
}
|
||||
|
||||
func (rc *RedisCache) Del(key string) error {
|
||||
_, err := rc.c.Del(key)
|
||||
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
module meow.tf/go/cacheinterface
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
|
||||
github.com/hoisie/redis v0.0.0-20160730154456-b5c6e81454e0
|
||||
)
|
|
@ -0,0 +1,4 @@
|
|||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||
github.com/hoisie/redis v0.0.0-20160730154456-b5c6e81454e0 h1:mjZV3MTu2A5gwfT5G9IIiLGdwZNciyVq5qqnmJJZ2JI=
|
||||
github.com/hoisie/redis v0.0.0-20160730154456-b5c6e81454e0/go.mod h1:pMYMxVaKJqCDC1JUg/XbPJ4/fSazB25zORpFzqsIGIc=
|
Loading…
Reference in New Issue