149 lines
3.7 KiB
Go
149 lines
3.7 KiB
Go
package rediskv
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/gomodule/redigo/redis"
|
|
)
|
|
|
|
// ErrNotFound is returned when an error is not found
|
|
var ErrNotFound = errors.New("not found")
|
|
|
|
// Rediskv stores the values that is set or retrieved in Redis
|
|
type Rediskv struct {
|
|
c redis.Conn
|
|
}
|
|
|
|
// Get returns the value from the requested key.
|
|
func (r Rediskv) Get(key string) (string, error) {
|
|
return redis.String(r.c.Do("GET", key))
|
|
}
|
|
|
|
// Set stores the value with the given key
|
|
func (r Rediskv) Set(key string, value interface{}) error {
|
|
_, err := r.c.Do("SET", key, value)
|
|
return err
|
|
}
|
|
|
|
// SetExp stores the value with the given key and expiration duration
|
|
func (r Rediskv) SetExp(key string, value interface{}, expiration time.Duration) error {
|
|
_, err := r.c.Do("SET", key, value, "EX", expiration.Seconds())
|
|
return err
|
|
}
|
|
|
|
// Del removes the keys matching the given key
|
|
// returns the number of keys removed
|
|
func (r Rediskv) Del(key string) (bool, error) {
|
|
removed, err := redis.Int(r.c.Do("DEL", key))
|
|
return removed == 1, err
|
|
}
|
|
|
|
//Exists return whether the key is existing or not
|
|
func (r Rediskv) Exists(key string) (bool, error) {
|
|
ok, err := redis.Bool(r.c.Do("EXISTS", key))
|
|
return ok, err
|
|
}
|
|
|
|
// Keys returns a list of keys matched by pattern
|
|
func (r Rediskv) Keys(pattern string) ([]string, error) {
|
|
// Note: maybe use scan instead of keys. Keys has a great performance impact
|
|
// See: https://redis.io/commands/keys, https://redis.io/commands/scan
|
|
return redis.Strings(r.c.Do("KEYS", pattern))
|
|
}
|
|
|
|
// HKeys returns all keys in a hash
|
|
func (r Rediskv) HKeys(key string) ([]string, error) {
|
|
return redis.Strings(r.c.Do("HKEYS", key))
|
|
}
|
|
|
|
// HGetAll returns all key-values in a map
|
|
func (r Rediskv) HGetAll(key string) (map[string]string, error) {
|
|
return redis.StringMap(r.c.Do("HGETALL", key))
|
|
}
|
|
|
|
// HGet retrieve the value from the given field in the given key
|
|
func (r Rediskv) HGet(key, field string) (string, error) {
|
|
ret, err := redis.String(r.c.Do("HGET", key, field))
|
|
if err == redis.ErrNil {
|
|
return ret, ErrNotFound
|
|
}
|
|
return ret, err
|
|
}
|
|
|
|
// HSet sets the value in the given field in the given key
|
|
func (r Rediskv) HSet(key, field string, value interface{}) error {
|
|
_, err := r.c.Do("HSET", key, field, value)
|
|
return err
|
|
}
|
|
|
|
// HDel removes the value in the given field in the given key
|
|
func (r Rediskv) HDel(key, field string) error {
|
|
_, err := r.c.Do("HDEL", key, field)
|
|
return err
|
|
}
|
|
|
|
// New creates a Redis key value instance
|
|
func New(hosts ...string) (*Rediskv, error) {
|
|
if len(hosts) == 0 {
|
|
return nil, errors.New("no hosts provided")
|
|
}
|
|
if c, err := newClusterConn(hosts); err == nil {
|
|
return &Rediskv{c: c}, nil
|
|
}
|
|
|
|
dial, err := redis.Dial("tcp", hosts[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c := &ReconnectionDoer{Conn: dial, address: hosts[0]}
|
|
|
|
_, err = c.Do("PING")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Rediskv{c: c}, nil
|
|
}
|
|
|
|
// IsClustered checks if redis is in clustered mode
|
|
func (r Rediskv) IsClustered() bool {
|
|
_, ok := r.c.(*clusterConn)
|
|
return ok
|
|
}
|
|
|
|
// Close closes the redis connection(s)
|
|
func (r Rediskv) Close() error {
|
|
return r.c.Close()
|
|
}
|
|
|
|
// ReconnectionDoer implements Do with reconnect
|
|
type ReconnectionDoer struct {
|
|
redis.Conn
|
|
address string
|
|
}
|
|
|
|
func (rc *ReconnectionDoer) redial() error {
|
|
conn, err := redis.Dial("tcp", rc.address)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rc.Conn = conn
|
|
return nil
|
|
}
|
|
|
|
//Do will execute redis commands, but redial and try again on error
|
|
func (rc *ReconnectionDoer) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
|
|
reply, err = rc.Conn.Do(commandName, args...)
|
|
if err != nil {
|
|
err = rc.redial()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
reply, err = rc.Conn.Do(commandName, args...)
|
|
return reply, err
|
|
}
|
|
return reply, err
|
|
}
|