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