|
- package cache
-
- import (
- "encoding/json"
- "errors"
- "log"
- "strings"
- "time"
-
- redigo "github.com/gomodule/redigo/redis"
- )
-
- // configuration
- type Config struct {
- Server string
- Password string
- MaxIdle int // Maximum number of idle connections in the pool.
-
- // Maximum number of connections allocated by the pool at a given time.
- // When zero, there is no limit on the number of connections in the pool.
- MaxActive int
-
- // Close connections after remaining idle for this duration. If the value
- // is zero, then idle connections are not closed. Applications should set
- // the timeout to a value less than the server's timeout.
- IdleTimeout time.Duration
-
- // If Wait is true and the pool is at the MaxActive limit, then Get() waits
- // for a connection to be returned to the pool before returning.
- Wait bool
- KeyPrefix string // prefix to all keys; example is "dev environment name"
- KeyDelimiter string // delimiter to be used while appending keys; example is ":"
- KeyPlaceholder string // placeholder to be parsed using given arguments to obtain a final key; example is "?"
- }
-
- var pool *redigo.Pool
- var redisConn redigo.Conn
- var conf *Config
-
- func NewRedis(addr string) {
- if addr == "" {
- panic("\nredis connect string cannot be empty\n")
- }
- pool = &redigo.Pool{
- MaxIdle: redisMaxIdleConn,
- IdleTimeout: redisIdleTTL,
- MaxActive: redisMaxActive,
- // MaxConnLifetime: redisDialTTL,
- Wait: true,
- Dial: func() (redigo.Conn, error) {
- c, err := redigo.Dial("tcp", addr,
- redigo.DialConnectTimeout(redisDialTTL),
- redigo.DialReadTimeout(redisReadTTL),
- redigo.DialWriteTimeout(redisWriteTTL),
- )
- if err != nil {
- log.Println("Redis Dial failed: ", err)
- return nil, err
- }
- return c, err
- },
- TestOnBorrow: func(c redigo.Conn, t time.Time) error {
- _, err := c.Do("PING")
- if err != nil {
- log.Println("Unable to ping to redis server:", err)
- }
- return err
- },
- }
- conn := pool.Get()
- defer conn.Close()
- if conn.Err() != nil {
- println("\nredis connect " + addr + " error: " + conn.Err().Error())
- } else {
- println("\nredis connect " + addr + " success!\n")
- }
- }
-
- func NewRedisConn(conn redigo.Conn) {
- redisConn = conn
- }
-
- //
- //func Do(cmd string, args ...interface{}) (reply interface{}, err error) {
- // conn := pool.Get()
- // defer conn.Close()
- // return conn.Do(cmd, args...)
- //}
-
- func Do(cmd string, args ...interface{}) (reply interface{}, err error) {
- var conn = redisConn
- if redisConn == nil {
- conn = pool.Get()
- defer conn.Close()
- }
- return conn.Do(cmd, args...)
- }
-
- func GetPool() *redigo.Pool {
- return pool
- }
-
- func ParseKey(key string, vars []string) (string, error) {
- arr := strings.Split(key, conf.KeyPlaceholder)
- actualKey := ""
- if len(arr) != len(vars)+1 {
- return "", errors.New("redis/connection.go: Insufficient arguments to parse key")
- } else {
- for index, val := range arr {
- if index == 0 {
- actualKey = arr[index]
- } else {
- actualKey += vars[index-1] + val
- }
- }
- }
- return getPrefixedKey(actualKey), nil
- }
-
- func getPrefixedKey(key string) string {
- return conf.KeyPrefix + conf.KeyDelimiter + key
- }
- func StripEnvKey(key string) string {
- return strings.TrimLeft(key, conf.KeyPrefix+conf.KeyDelimiter)
- }
- func SplitKey(key string) []string {
- return strings.Split(key, conf.KeyDelimiter)
- }
- func Expire(key string, ttl int) (interface{}, error) {
- return Do("EXPIRE", key, ttl)
- }
- func Persist(key string) (interface{}, error) {
- return Do("PERSIST", key)
- }
-
- func Del(key string) (interface{}, error) {
- return Do("DEL", key)
- }
- func Set(key string, data interface{}) (interface{}, error) {
- // set
- return Do("SET", key, data)
- }
- func SetNX(key string, data interface{}) (interface{}, error) {
- return Do("SETNX", key, data)
- }
- func SetEx(key string, data interface{}, ttl int) (interface{}, error) {
- return Do("SETEX", key, ttl, data)
- }
-
- func SetJson(key string, data interface{}, ttl int) bool {
- c, err := json.Marshal(data)
- if err != nil {
- return false
- }
- if ttl < 1 {
- _, err = Set(key, c)
- } else {
- _, err = SetEx(key, c, ttl)
- }
- if err != nil {
- return false
- }
- return true
- }
-
- func GetJson(key string, dst interface{}) error {
- b, err := GetBytes(key)
- if err != nil {
- return err
- }
- if err = json.Unmarshal(b, dst); err != nil {
- return err
- }
- return nil
- }
-
- func Get(key string) (interface{}, error) {
- // get
- return Do("GET", key)
- }
- func GetTTL(key string) (time.Duration, error) {
- ttl, err := redigo.Int64(Do("TTL", key))
- return time.Duration(ttl) * time.Second, err
- }
- func GetBytes(key string) ([]byte, error) {
- return redigo.Bytes(Do("GET", key))
- }
- func GetString(key string) (string, error) {
- return redigo.String(Do("GET", key))
- }
- func GetStringMap(key string) (map[string]string, error) {
- return redigo.StringMap(Do("GET", key))
- }
- func GetInt(key string) (int, error) {
- return redigo.Int(Do("GET", key))
- }
- func GetInt64(key string) (int64, error) {
- return redigo.Int64(Do("GET", key))
- }
- func GetStringLength(key string) (int, error) {
- return redigo.Int(Do("STRLEN", key))
- }
- func ZAdd(key string, score float64, data interface{}) (interface{}, error) {
- return Do("ZADD", key, score, data)
- }
- func ZAddNX(key string, score float64, data interface{}) (interface{}, error) {
- return Do("ZADD", key, "NX", score, data)
- }
- func ZRem(key string, data interface{}) (interface{}, error) {
- return Do("ZREM", key, data)
- }
- func ZRange(key string, start int, end int, withScores bool) ([]interface{}, error) {
- if withScores {
- return redigo.Values(Do("ZRANGE", key, start, end, "WITHSCORES"))
- }
- return redigo.Values(Do("ZRANGE", key, start, end))
- }
- func ZRemRangeByScore(key string, start int64, end int64) ([]interface{}, error) {
- return redigo.Values(Do("ZREMRANGEBYSCORE", key, start, end))
- }
- func ZCard(setName string) (int64, error) {
- return redigo.Int64(Do("ZCARD", setName))
- }
- func ZScan(setName string) (int64, error) {
- return redigo.Int64(Do("ZCARD", setName))
- }
- func SAdd(setName string, data interface{}) (interface{}, error) {
- return Do("SADD", setName, data)
- }
- func SCard(setName string) (int64, error) {
- return redigo.Int64(Do("SCARD", setName))
- }
- func SIsMember(setName string, data interface{}) (bool, error) {
- return redigo.Bool(Do("SISMEMBER", setName, data))
- }
- func SMembers(setName string) ([]string, error) {
- return redigo.Strings(Do("SMEMBERS", setName))
- }
- func SRem(setName string, data interface{}) (interface{}, error) {
- return Do("SREM", setName, data)
- }
- func HSet(key string, HKey string, data interface{}) (interface{}, error) {
- return Do("HSET", key, HKey, data)
- }
-
- func HGet(key string, HKey string) (interface{}, error) {
- return Do("HGET", key, HKey)
- }
-
- func HMGet(key string, hashKeys ...string) ([]interface{}, error) {
- ret, err := Do("HMGET", key, hashKeys)
- if err != nil {
- return nil, err
- }
- reta, ok := ret.([]interface{})
- if !ok {
- return nil, errors.New("result not an array")
- }
- return reta, nil
- }
-
- func HMSet(key string, hashKeys []string, vals []interface{}) (interface{}, error) {
- if len(hashKeys) == 0 || len(hashKeys) != len(vals) {
- var ret interface{}
- return ret, errors.New("bad length")
- }
- input := []interface{}{key}
- for i, v := range hashKeys {
- input = append(input, v, vals[i])
- }
- return Do("HMSET", input...)
- }
-
- func HGetString(key string, HKey string) (string, error) {
- return redigo.String(Do("HGET", key, HKey))
- }
- func HGetFloat(key string, HKey string) (float64, error) {
- f, err := redigo.Float64(Do("HGET", key, HKey))
- return f, err
- }
- func HGetInt(key string, HKey string) (int, error) {
- return redigo.Int(Do("HGET", key, HKey))
- }
- func HGetInt64(key string, HKey string) (int64, error) {
- return redigo.Int64(Do("HGET", key, HKey))
- }
- func HGetBool(key string, HKey string) (bool, error) {
- return redigo.Bool(Do("HGET", key, HKey))
- }
- func HDel(key string, HKey string) (interface{}, error) {
- return Do("HDEL", key, HKey)
- }
-
- func HGetAll(key string) (map[string]interface{}, error) {
- vals, err := redigo.Values(Do("HGETALL", key))
- if err != nil {
- return nil, err
- }
- num := len(vals) / 2
- result := make(map[string]interface{}, num)
- for i := 0; i < num; i++ {
- key, _ := redigo.String(vals[2*i], nil)
- result[key] = vals[2*i+1]
- }
- return result, nil
- }
-
- func FlushAll() bool {
- res, _ := redigo.String(Do("FLUSHALL"))
- if res == "" {
- return false
- }
- return true
- }
-
- // NOTE: Use this in production environment with extreme care.
- // Read more here:https://redigo.io/commands/keys
- func Keys(pattern string) ([]string, error) {
- return redigo.Strings(Do("KEYS", pattern))
- }
-
- func HKeys(key string) ([]string, error) {
- return redigo.Strings(Do("HKEYS", key))
- }
-
- func Exists(key string) bool {
- count, err := redigo.Int(Do("EXISTS", key))
- if count == 0 || err != nil {
- return false
- }
- return true
- }
-
- func Incr(key string) (int64, error) {
- return redigo.Int64(Do("INCR", key))
- }
-
- func Decr(key string) (int64, error) {
- return redigo.Int64(Do("DECR", key))
- }
-
- func IncrBy(key string, incBy int64) (int64, error) {
- return redigo.Int64(Do("INCRBY", key, incBy))
- }
-
- func DecrBy(key string, decrBy int64) (int64, error) {
- return redigo.Int64(Do("DECRBY", key))
- }
-
- func IncrByFloat(key string, incBy float64) (float64, error) {
- return redigo.Float64(Do("INCRBYFLOAT", key, incBy))
- }
-
- func DecrByFloat(key string, decrBy float64) (float64, error) {
- return redigo.Float64(Do("DECRBYFLOAT", key, decrBy))
- }
-
- // use for message queue
- func LPush(key string, data interface{}) (interface{}, error) {
- // set
- return Do("LPUSH", key, data)
- }
-
- func LPop(key string) (interface{}, error) {
- return Do("LPOP", key)
- }
-
- func LPopString(key string) (string, error) {
- return redigo.String(Do("LPOP", key))
- }
- func LPopFloat(key string) (float64, error) {
- f, err := redigo.Float64(Do("LPOP", key))
- return f, err
- }
- func LPopInt(key string) (int, error) {
- return redigo.Int(Do("LPOP", key))
- }
- func LPopInt64(key string) (int64, error) {
- return redigo.Int64(Do("LPOP", key))
- }
-
- func RPush(key string, data interface{}) (interface{}, error) {
- // set
- return Do("RPUSH", key, data)
- }
-
- func RPop(key string) (interface{}, error) {
- return Do("RPOP", key)
- }
-
- func RPopString(key string) (string, error) {
- return redigo.String(Do("RPOP", key))
- }
- func RPopFloat(key string) (float64, error) {
- f, err := redigo.Float64(Do("RPOP", key))
- return f, err
- }
- func RPopInt(key string) (int, error) {
- return redigo.Int(Do("RPOP", key))
- }
- func RPopInt64(key string) (int64, error) {
- return redigo.Int64(Do("RPOP", key))
- }
-
- func Scan(cursor int64, pattern string, count int64) (int64, []string, error) {
- var items []string
- var newCursor int64
-
- values, err := redigo.Values(Do("SCAN", cursor, "MATCH", pattern, "COUNT", count))
- if err != nil {
- return 0, nil, err
- }
- values, err = redigo.Scan(values, &newCursor, &items)
- if err != nil {
- return 0, nil, err
- }
- return newCursor, items, nil
- }
-
- func LPushMax(key string, data ...interface{}) (interface{}, error) {
- // set
- return Do("LPUSH", key, data)
- }
-
- func SelectDb(db int) (interface{}, error) {
- return Do("SELECT", db)
- }
|