forked from LaconicNetwork/kompose
#### What type of PR is this? <!-- Add one of the following kinds: /kind bug /kind documentation /kind feature --> /kind cleanup #### What this PR does / why we need it: Fixes the current broken examples by: * Removing all the old incompatible ones (we do not really support v3 anymore or v2... since switching libraries) * Uses quay.io/kompose/web as our front end example which is a fork of the guestbook-go kubernetes examples #### Which issue(s) this PR fixes: <!-- *Automatically closes linked issue when PR is merged. Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`. --> Closes https://github.com/kubernetes/kompose/issues/1757 #### Special notes for your reviewer: Test using docker-compose (you'll see it come up!), then try with kompose :) Signed-off-by: Charlie Drage <charlie@charliedrage.com>
738 lines
19 KiB
Go
738 lines
19 KiB
Go
// Package simpleredis provides an easy way to use Redis.
|
|
package simpleredis
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gomodule/redigo/redis"
|
|
)
|
|
|
|
const (
|
|
// Version number. Stable API within major version numbers.
|
|
Version = 2.6
|
|
|
|
// The default [url]:port that Redis is running at
|
|
defaultRedisServer = ":6379"
|
|
)
|
|
|
|
// Common for each of the Redis data structures used here
|
|
type redisDatastructure struct {
|
|
pool *ConnectionPool
|
|
id string
|
|
dbindex int
|
|
}
|
|
|
|
type (
|
|
// A pool of readily available Redis connections
|
|
ConnectionPool redis.Pool
|
|
|
|
List redisDatastructure
|
|
Set redisDatastructure
|
|
HashMap redisDatastructure
|
|
KeyValue redisDatastructure
|
|
)
|
|
|
|
var (
|
|
// Timeout settings for new connections
|
|
connectTimeout = 7 * time.Second
|
|
readTimeout = 7 * time.Second
|
|
writeTimeout = 7 * time.Second
|
|
idleTimeout = 240 * time.Second
|
|
|
|
// How many connections should stay ready for requests, at a maximum?
|
|
// When an idle connection is used, new idle connections are created.
|
|
maxIdleConnections = 3
|
|
)
|
|
|
|
/* --- Helper functions --- */
|
|
|
|
// Connect to the local instance of Redis at port 6379
|
|
func newRedisConnection() (redis.Conn, error) {
|
|
return newRedisConnectionTo(defaultRedisServer)
|
|
}
|
|
|
|
// Connect to host:port, host may be omitted, so ":6379" is valid.
|
|
// Will not try to AUTH with any given password (password@host:port).
|
|
func newRedisConnectionTo(hostColonPort string) (redis.Conn, error) {
|
|
// Discard the password, if provided
|
|
if _, theRest, ok := twoFields(hostColonPort, "@"); ok {
|
|
hostColonPort = theRest
|
|
}
|
|
hostColonPort = strings.TrimSpace(hostColonPort)
|
|
c, err := redis.Dial("tcp", hostColonPort, redis.DialConnectTimeout(connectTimeout), redis.DialReadTimeout(readTimeout), redis.DialWriteTimeout(writeTimeout))
|
|
if err != nil {
|
|
if c != nil {
|
|
c.Close()
|
|
}
|
|
return nil, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
// Get a string from a list of results at a given position
|
|
func getString(bi []interface{}, i int) string {
|
|
return string(bi[i].([]uint8))
|
|
}
|
|
|
|
// Test if the local Redis server is up and running
|
|
func TestConnection() (err error) {
|
|
return TestConnectionHost(defaultRedisServer)
|
|
}
|
|
|
|
// Test if a given Redis server at host:port is up and running.
|
|
// Does not try to PING or AUTH.
|
|
func TestConnectionHost(hostColonPort string) (err error) {
|
|
// Connect to the given host:port
|
|
conn, err := newRedisConnectionTo(hostColonPort)
|
|
defer func() {
|
|
if conn != nil {
|
|
conn.Close()
|
|
}
|
|
if r := recover(); r != nil {
|
|
err = errors.New("Could not connect to redis server: " + hostColonPort)
|
|
}
|
|
}()
|
|
return err
|
|
}
|
|
|
|
/* --- ConnectionPool functions --- */
|
|
|
|
func copyPoolValues(src *redis.Pool) ConnectionPool {
|
|
return ConnectionPool{
|
|
Dial: src.Dial,
|
|
DialContext: src.DialContext,
|
|
TestOnBorrow: src.TestOnBorrow,
|
|
MaxIdle: src.MaxIdle,
|
|
MaxActive: src.MaxActive,
|
|
IdleTimeout: src.IdleTimeout,
|
|
Wait: src.Wait,
|
|
MaxConnLifetime: src.MaxConnLifetime,
|
|
}
|
|
}
|
|
|
|
// Create a new connection pool
|
|
func NewConnectionPool() *ConnectionPool {
|
|
// The second argument is the maximum number of idle connections
|
|
redisPool := &redis.Pool{
|
|
MaxIdle: maxIdleConnections,
|
|
IdleTimeout: idleTimeout,
|
|
Dial: newRedisConnection,
|
|
}
|
|
|
|
pool := copyPoolValues(redisPool)
|
|
return &pool
|
|
}
|
|
|
|
// Split a string into two parts, given a delimiter.
|
|
// Returns the two parts and true if it works out.
|
|
func twoFields(s, delim string) (string, string, bool) {
|
|
if strings.Count(s, delim) != 1 {
|
|
return s, "", false
|
|
}
|
|
fields := strings.Split(s, delim)
|
|
return fields[0], fields[1], true
|
|
}
|
|
|
|
// Create a new connection pool given a host:port string.
|
|
// A password may be supplied as well, on the form "password@host:port".
|
|
func NewConnectionPoolHost(hostColonPort string) *ConnectionPool {
|
|
// Create a redis Pool
|
|
redisPool := &redis.Pool{
|
|
// Maximum number of idle connections to the redis database
|
|
MaxIdle: maxIdleConnections,
|
|
IdleTimeout: idleTimeout,
|
|
// Anonymous function for calling new RedisConnectionTo with the host:port
|
|
Dial: func() (redis.Conn, error) {
|
|
conn, err := newRedisConnectionTo(hostColonPort)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// If a password is given, use it to authenticate
|
|
if password, _, ok := twoFields(hostColonPort, "@"); ok {
|
|
if password != "" {
|
|
if _, err := conn.Do("AUTH", password); err != nil {
|
|
conn.Close()
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return conn, err
|
|
},
|
|
}
|
|
pool := copyPoolValues(redisPool)
|
|
return &pool
|
|
}
|
|
|
|
// Set the number of maximum *idle* connections standing ready when
|
|
// creating new connection pools. When an idle connection is used,
|
|
// a new idle connection is created. The default is 3 and should be fine
|
|
// for most cases.
|
|
func SetMaxIdleConnections(maximum int) {
|
|
maxIdleConnections = maximum
|
|
}
|
|
|
|
// Get one of the available connections from the connection pool, given a database index
|
|
func (pool *ConnectionPool) Get(dbindex int) redis.Conn {
|
|
redisPool := (*redis.Pool)(pool)
|
|
conn := redisPool.Get()
|
|
// The default database index is 0
|
|
if dbindex != 0 {
|
|
// SELECT is not critical, ignore the return values
|
|
conn.Do("SELECT", strconv.Itoa(dbindex))
|
|
}
|
|
return conn
|
|
}
|
|
|
|
// Ping the server by sending a PING command
|
|
func (pool *ConnectionPool) Ping() error {
|
|
redisPool := (*redis.Pool)(pool)
|
|
conn := redisPool.Get()
|
|
_, err := conn.Do("PING")
|
|
return err
|
|
}
|
|
|
|
// Close down the connection pool
|
|
func (pool *ConnectionPool) Close() {
|
|
redisPool := (*redis.Pool)(pool)
|
|
redisPool.Close()
|
|
}
|
|
|
|
/* --- List functions --- */
|
|
|
|
// Create a new list
|
|
func NewList(pool *ConnectionPool, id string) *List {
|
|
return &List{pool, id, 0}
|
|
}
|
|
|
|
// Select a different database
|
|
func (rl *List) SelectDatabase(dbindex int) {
|
|
rl.dbindex = dbindex
|
|
}
|
|
|
|
// Returns the element at index index in the list
|
|
func (rl *List) Get(index int64) (string, error) {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
result, err := conn.Do("LINDEX", rl.id, index)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.String(result, err)
|
|
}
|
|
|
|
// Get the size of the list
|
|
func (rl *List) Size() (int64, error) {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
size, err := conn.Do("LLEN", rl.id)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.Int64(size, err)
|
|
}
|
|
|
|
// Removes and returns the first element of the list
|
|
func (rl *List) PopFirst() (string, error) {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
result, err := conn.Do("LPOP", rl.id)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.String(result, err)
|
|
}
|
|
|
|
// Removes and returns the last element of the list
|
|
func (rl *List) PopLast() (string, error) {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
result, err := conn.Do("LPOP", rl.id)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.String(result, err)
|
|
}
|
|
|
|
// Add an element to the start of the list
|
|
func (rl *List) AddStart(value string) error {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
_, err := conn.Do("RPUSH", rl.id, value)
|
|
return err
|
|
}
|
|
|
|
// Add an element to the end of the list list
|
|
func (rl *List) AddEnd(value string) error {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
_, err := conn.Do("LPUSH", rl.id, value)
|
|
return err
|
|
}
|
|
|
|
// Default Add, aliased to List.AddStart
|
|
func (rl *List) Add(value string) error {
|
|
return rl.AddStart(value)
|
|
}
|
|
|
|
// Get all elements of a list
|
|
func (rl *List) All() ([]string, error) {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
result, err := redis.Values(conn.Do("LRANGE", rl.id, "0", "-1"))
|
|
strs := make([]string, len(result))
|
|
for i := 0; i < len(result); i++ {
|
|
strs[i] = getString(result, i)
|
|
}
|
|
return strs, err
|
|
}
|
|
|
|
// Deprecated
|
|
func (rl *List) GetAll() ([]string, error) {
|
|
return rl.All()
|
|
}
|
|
|
|
// Get the last element of a list
|
|
func (rl *List) Last() (string, error) {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
result, err := redis.Values(conn.Do("LRANGE", rl.id, "-1", "-1"))
|
|
if len(result) == 1 {
|
|
return getString(result, 0), err
|
|
}
|
|
return "", err
|
|
}
|
|
|
|
// Deprecated
|
|
func (rl *List) GetLast() (string, error) {
|
|
return rl.Last()
|
|
}
|
|
|
|
// Get the last N elements of a list
|
|
func (rl *List) LastN(n int) ([]string, error) {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
result, err := redis.Values(conn.Do("LRANGE", rl.id, "-"+strconv.Itoa(n), "-1"))
|
|
strs := make([]string, len(result))
|
|
for i := 0; i < len(result); i++ {
|
|
strs[i] = getString(result, i)
|
|
}
|
|
return strs, err
|
|
}
|
|
|
|
// Deprecated
|
|
func (rl *List) GetLastN(n int) ([]string, error) {
|
|
return rl.LastN(n)
|
|
}
|
|
|
|
// Remove the first occurrence of an element from the list
|
|
func (rl *List) RemoveElement(value string) error {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
_, err := conn.Do("LREM", rl.id, value)
|
|
return err
|
|
}
|
|
|
|
// Set element of list at index n to value
|
|
func (rl *List) Set(index int64, value string) error {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
_, err := conn.Do("LSET", rl.id, index, value)
|
|
return err
|
|
}
|
|
|
|
// Trim an existing list so that it will contain only the specified range of
|
|
// elements specified.
|
|
func (rl *List) Trim(start, stop int64) error {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
_, err := conn.Do("LTRIM", rl.id, start, stop)
|
|
return err
|
|
}
|
|
|
|
// Remove this list
|
|
func (rl *List) Remove() error {
|
|
conn := rl.pool.Get(rl.dbindex)
|
|
_, err := conn.Do("DEL", rl.id)
|
|
return err
|
|
}
|
|
|
|
// Clear the contents
|
|
func (rl *List) Clear() error {
|
|
return rl.Remove()
|
|
}
|
|
|
|
/* --- Set functions --- */
|
|
|
|
// Create a new set
|
|
func NewSet(pool *ConnectionPool, id string) *Set {
|
|
return &Set{pool, id, 0}
|
|
}
|
|
|
|
// Select a different database
|
|
func (rs *Set) SelectDatabase(dbindex int) {
|
|
rs.dbindex = dbindex
|
|
}
|
|
|
|
// Add an element to the set
|
|
func (rs *Set) Add(value string) error {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
_, err := conn.Do("SADD", rs.id, value)
|
|
return err
|
|
}
|
|
|
|
// Returns the set cardinality (number of elements) of the set
|
|
func (rs *Set) Size() (int64, error) {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
size, err := conn.Do("SCARD", rs.id)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.Int64(size, err)
|
|
}
|
|
|
|
// Check if a given value is in the set
|
|
func (rs *Set) Has(value string) (bool, error) {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
retval, err := conn.Do("SISMEMBER", rs.id, value)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.Bool(retval, err)
|
|
}
|
|
|
|
// Get all elements of the set
|
|
func (rs *Set) All() ([]string, error) {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
result, err := redis.Values(conn.Do("SMEMBERS", rs.id))
|
|
strs := make([]string, len(result))
|
|
for i := 0; i < len(result); i++ {
|
|
strs[i] = getString(result, i)
|
|
}
|
|
return strs, err
|
|
}
|
|
|
|
// Deprecated
|
|
func (rs *Set) GetAll() ([]string, error) {
|
|
return rs.All()
|
|
}
|
|
|
|
// Remove a random member from the set
|
|
func (rs *Set) Pop() (string, error) {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
result, err := conn.Do("SPOP", rs.id)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.String(result, err)
|
|
}
|
|
|
|
// Get a random member of the set
|
|
func (rs *Set) Random() (string, error) {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
result, err := conn.Do("SRANDMEMBER", rs.id)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.String(result, err)
|
|
}
|
|
|
|
// Remove an element from the set
|
|
func (rs *Set) Del(value string) error {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
_, err := conn.Do("SREM", rs.id, value)
|
|
return err
|
|
}
|
|
|
|
// Remove this set
|
|
func (rs *Set) Remove() error {
|
|
conn := rs.pool.Get(rs.dbindex)
|
|
_, err := conn.Do("DEL", rs.id)
|
|
return err
|
|
}
|
|
|
|
// Clear the contents
|
|
func (rs *Set) Clear() error {
|
|
return rs.Remove()
|
|
}
|
|
|
|
/* --- HashMap functions --- */
|
|
|
|
// Create a new hashmap
|
|
func NewHashMap(pool *ConnectionPool, id string) *HashMap {
|
|
return &HashMap{pool, id, 0}
|
|
}
|
|
|
|
// Select a different database
|
|
func (rh *HashMap) SelectDatabase(dbindex int) {
|
|
rh.dbindex = dbindex
|
|
}
|
|
|
|
// Set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
|
|
func (rh *HashMap) Set(elementid, key, value string) error {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
_, err := conn.Do("HSET", rh.id+":"+elementid, key, value)
|
|
return err
|
|
}
|
|
|
|
// Given an element id, set a key and a value together with an expiration time
|
|
func (rh *HashMap) SetExpire(elementid, key, value string, expire time.Duration) error {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
if _, err := conn.Do("HSET", rh.id+":"+elementid, key, value); err != nil {
|
|
return err
|
|
}
|
|
// No EXPIRE in Redis for hash keys, as far as I can tell from the documentation.
|
|
// This is the manual way.
|
|
go func() {
|
|
time.Sleep(expire)
|
|
rh.DelKey(elementid, key)
|
|
}()
|
|
// Set the elementid to expire in the given duration (as milliseconds)
|
|
//expireMilliseconds := expire.Nanoseconds() / 1000000
|
|
//if _, err := conn.Do("PEXPIRE", rh.id+":"+elementid, expireMilliseconds); err != nil {
|
|
// return err
|
|
//}
|
|
return nil
|
|
}
|
|
|
|
// Commented out because this would only return TTL for the elementid, not for the key
|
|
// TimeToLive returns how long a key has to live until it expires
|
|
// Returns a duration of 0 when the time has passed
|
|
//func (rh *HashMap) TimeToLive(elementid string) (time.Duration, error) {
|
|
// conn := rh.pool.Get(rh.dbindex)
|
|
// ttlSecondsInterface, err := conn.Do("TTL", rh.id+":"+elementid)
|
|
// if err != nil || ttlSecondsInterface.(int64) <= 0 {
|
|
// return time.Duration(0), err
|
|
// }
|
|
// ns := time.Duration(ttlSecondsInterface.(int64)) * time.Second
|
|
// return ns, nil
|
|
//}
|
|
|
|
// Get a value from a hashmap given the element id (for instance a user id) and the key (for instance "password")
|
|
func (rh *HashMap) Get(elementid, key string) (string, error) {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
result, err := redis.String(conn.Do("HGET", rh.id+":"+elementid, key))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// Check if a given elementid + key is in the hash map
|
|
func (rh *HashMap) Has(elementid, key string) (bool, error) {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
retval, err := conn.Do("HEXISTS", rh.id+":"+elementid, key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return redis.Bool(retval, err)
|
|
}
|
|
|
|
// Keys returns the keys of the given elementid.
|
|
func (rh *HashMap) Keys(elementid string) ([]string, error) {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
result, err := redis.Values(conn.Do("HKEYS", rh.id+":"+elementid))
|
|
strs := make([]string, len(result))
|
|
for i := 0; i < len(result); i++ {
|
|
strs[i] = getString(result, i)
|
|
}
|
|
return strs, err
|
|
}
|
|
|
|
// Check if a given elementid exists as a hash map at all
|
|
func (rh *HashMap) Exists(elementid string) (bool, error) {
|
|
// TODO: key is not meant to be a wildcard, check for "*"
|
|
return hasKey(rh.pool, rh.id+":"+elementid, rh.dbindex)
|
|
}
|
|
|
|
// Get all elementid's for all hash elements
|
|
func (rh *HashMap) All() ([]string, error) {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
result, err := redis.Values(conn.Do("KEYS", rh.id+":*"))
|
|
strs := make([]string, len(result))
|
|
idlen := len(rh.id)
|
|
for i := 0; i < len(result); i++ {
|
|
strs[i] = getString(result, i)[idlen+1:]
|
|
}
|
|
return strs, err
|
|
}
|
|
|
|
// Deprecated
|
|
func (rh *HashMap) GetAll() ([]string, error) {
|
|
return rh.All()
|
|
}
|
|
|
|
// Remove a key for an entry in a hashmap (for instance the email field for a user)
|
|
func (rh *HashMap) DelKey(elementid, key string) error {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
_, err := conn.Do("HDEL", rh.id+":"+elementid, key)
|
|
return err
|
|
}
|
|
|
|
// Remove an element (for instance a user)
|
|
func (rh *HashMap) Del(elementid string) error {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
_, err := conn.Do("DEL", rh.id+":"+elementid)
|
|
return err
|
|
}
|
|
|
|
// Remove this hashmap (all keys that starts with this hashmap id and a colon)
|
|
func (rh *HashMap) Remove() error {
|
|
conn := rh.pool.Get(rh.dbindex)
|
|
// Find all hashmap keys that starts with rh.id+":"
|
|
results, err := redis.Values(conn.Do("KEYS", rh.id+":*"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// For each key id
|
|
for i := 0; i < len(results); i++ {
|
|
// Delete this key
|
|
if _, err = conn.Do("DEL", getString(results, i)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Clear the contents
|
|
func (rh *HashMap) Clear() error {
|
|
return rh.Remove()
|
|
}
|
|
|
|
/* --- KeyValue functions --- */
|
|
|
|
// Create a new key/value
|
|
func NewKeyValue(pool *ConnectionPool, id string) *KeyValue {
|
|
return &KeyValue{pool, id, 0}
|
|
}
|
|
|
|
// Select a different database
|
|
func (rkv *KeyValue) SelectDatabase(dbindex int) {
|
|
rkv.dbindex = dbindex
|
|
}
|
|
|
|
// Set a key and value
|
|
func (rkv *KeyValue) Set(key, value string) error {
|
|
conn := rkv.pool.Get(rkv.dbindex)
|
|
_, err := conn.Do("SET", rkv.id+":"+key, value)
|
|
return err
|
|
}
|
|
|
|
// Set a key and value, with expiry
|
|
func (rkv *KeyValue) SetExpire(key, value string, expire time.Duration) error {
|
|
conn := rkv.pool.Get(rkv.dbindex)
|
|
// Convert from nanoseconds to milliseconds
|
|
expireMilliseconds := expire.Nanoseconds() / 1000000
|
|
// Set the value, together with an expiry time, given in milliseconds
|
|
_, err := conn.Do("SET", rkv.id+":"+key, value, "PX", expireMilliseconds)
|
|
return err
|
|
}
|
|
|
|
// TimeToLive returns how long a key has to live until it expires
|
|
// Returns a duration of 0 when the time has passed
|
|
func (rkv *KeyValue) TimeToLive(key string) (time.Duration, error) {
|
|
conn := rkv.pool.Get(rkv.dbindex)
|
|
ttlSecondsInterface, err := conn.Do("TTL", rkv.id+":"+key)
|
|
if err != nil || ttlSecondsInterface.(int64) <= 0 {
|
|
return time.Duration(0), err
|
|
}
|
|
ns := time.Duration(ttlSecondsInterface.(int64)) * time.Second
|
|
return ns, nil
|
|
}
|
|
|
|
// Get a value given a key
|
|
func (rkv *KeyValue) Get(key string) (string, error) {
|
|
conn := rkv.pool.Get(rkv.dbindex)
|
|
result, err := redis.String(conn.Do("GET", rkv.id+":"+key))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// Remove a key
|
|
func (rkv *KeyValue) Del(key string) error {
|
|
conn := rkv.pool.Get(rkv.dbindex)
|
|
_, err := conn.Do("DEL", rkv.id+":"+key)
|
|
return err
|
|
}
|
|
|
|
// Increase the value of a key, returns the new value
|
|
// Returns an empty string if there were errors,
|
|
// or "0" if the key does not already exist.
|
|
func (rkv *KeyValue) Inc(key string) (string, error) {
|
|
conn := rkv.pool.Get(rkv.dbindex)
|
|
result, err := redis.Int64(conn.Do("INCR", rkv.id+":"+key))
|
|
if err != nil {
|
|
return "0", err
|
|
}
|
|
return strconv.FormatInt(result, 10), nil
|
|
}
|
|
|
|
// Remove this key/value
|
|
func (rkv *KeyValue) Remove() error {
|
|
conn := rkv.pool.Get(rkv.dbindex)
|
|
// Find all keys that starts with rkv.id+":"
|
|
results, err := redis.Values(conn.Do("KEYS", rkv.id+":*"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// For each key id
|
|
for i := 0; i < len(results); i++ {
|
|
// Delete this key
|
|
if _, err = conn.Do("DEL", getString(results, i)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Clear the contents
|
|
func (rkv *KeyValue) Clear() error {
|
|
return rkv.Remove()
|
|
}
|
|
|
|
// --- Generic redis functions ---
|
|
|
|
// Check if a key exists. The key can be a wildcard (ie. "user*").
|
|
func hasKey(pool *ConnectionPool, wildcard string, dbindex int) (bool, error) {
|
|
conn := pool.Get(dbindex)
|
|
result, err := redis.Values(conn.Do("KEYS", wildcard))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return len(result) > 0, nil
|
|
}
|
|
|
|
// --- Related to setting and retrieving timeout values
|
|
|
|
// SetConnectTimeout sets the connect timeout for new connections
|
|
func SetConnectTimeout(t time.Duration) {
|
|
connectTimeout = t
|
|
}
|
|
|
|
// SetReadTimeout sets the read timeout for new connections
|
|
func SetReadTimeout(t time.Duration) {
|
|
readTimeout = t
|
|
}
|
|
|
|
// SetWriteTimeout sets the write timeout for new connections
|
|
func SetWriteTimeout(t time.Duration) {
|
|
writeTimeout = t
|
|
}
|
|
|
|
// SetIdleTimeout sets the idle timeout for new connections
|
|
func SetIdleTimeout(t time.Duration) {
|
|
idleTimeout = t
|
|
}
|
|
|
|
// ConnectTimeout returns the current connect timeout for new connections
|
|
func ConnectTimeout() time.Duration {
|
|
return connectTimeout
|
|
}
|
|
|
|
// ReadTimeout returns the current read timeout for new connections
|
|
func ReadTimeout() time.Duration {
|
|
return readTimeout
|
|
}
|
|
|
|
// WriteTimeout returns the current write timeout for new connections
|
|
func WriteTimeout() time.Duration {
|
|
return writeTimeout
|
|
}
|
|
|
|
// IdleTimeout returns the current idle timeout for new connections
|
|
func IdleTimeout() time.Duration {
|
|
return idleTimeout
|
|
}
|