You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
10 KiB
415 lines
10 KiB
|
1 year ago
|
package redis
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"crypto/tls"
|
||
|
|
"encoding/json"
|
||
|
|
"errors"
|
||
|
|
"reflect"
|
||
|
|
"server/common"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/go-redis/redis/v8"
|
||
|
|
"github.com/liangdas/mqant/log"
|
||
|
|
"github.com/mitchellh/mapstructure"
|
||
|
|
)
|
||
|
|
|
||
|
|
// RedisClient redis连接对象
|
||
|
|
type RedisClient struct {
|
||
|
|
client redis.Cmdable
|
||
|
|
}
|
||
|
|
|
||
|
|
// InitRedisCilent 连接redis
|
||
|
|
func InitRedisCilent(host, name, pwd string, db int, isTls, cluster bool) (*RedisClient, error) {
|
||
|
|
if !cluster {
|
||
|
|
opt := &redis.Options{
|
||
|
|
Addr: host,
|
||
|
|
Username: name,
|
||
|
|
Password: pwd,
|
||
|
|
DB: db,
|
||
|
|
}
|
||
|
|
if isTls {
|
||
|
|
opt.TLSConfig = &tls.Config{}
|
||
|
|
}
|
||
|
|
cli := redis.NewClient(opt)
|
||
|
|
|
||
|
|
err := cli.Ping(context.Background()).Err()
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
return &RedisClient{client: cli}, nil
|
||
|
|
}
|
||
|
|
opt := &redis.ClusterOptions{
|
||
|
|
Addrs: []string{host},
|
||
|
|
Username: name,
|
||
|
|
Password: pwd,
|
||
|
|
}
|
||
|
|
if isTls {
|
||
|
|
opt.TLSConfig = &tls.Config{}
|
||
|
|
}
|
||
|
|
cli := redis.NewClusterClient(opt)
|
||
|
|
|
||
|
|
err := cli.Ping(context.Background()).Err()
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
return &RedisClient{client: cli}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// LRange 读取一组数据,ret必须实现MarshalBinary和UnmarshalBinary方法
|
||
|
|
func (r *RedisClient) LRange(key string, ret interface{}) error {
|
||
|
|
err := r.client.LRange(context.Background(), key, 0, -1).ScanSlice(ret)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// LPushJsonSlice 插入数组(data 必须是切片类型,元素转换成json存储)
|
||
|
|
func (r *RedisClient) LPush(key string, data interface{}) error {
|
||
|
|
err := r.client.LPush(context.Background(), key, data).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// RPop pop出一个数据
|
||
|
|
func (r *RedisClient) RPop(key string) error {
|
||
|
|
err := r.client.RPop(context.Background(), key).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) GetRedis() redis.Cmdable {
|
||
|
|
return r.client
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetJsonData 通用设置json数据
|
||
|
|
func (r *RedisClient) SetJsonData(key string, data interface{}, ex ...time.Duration) (err error) {
|
||
|
|
ret, err := json.Marshal(data)
|
||
|
|
if err != nil && err != redis.Nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(ex) > 0 {
|
||
|
|
err = r.client.Set(context.Background(), key, ret, ex[0]).Err()
|
||
|
|
} else {
|
||
|
|
err = r.client.Set(context.Background(), key, ret, 0).Err()
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetJsonData 通用获取json数据
|
||
|
|
func (r *RedisClient) GetJsonData(key string, kind interface{}) (err error) {
|
||
|
|
ret, err := r.client.Get(context.Background(), key).Bytes()
|
||
|
|
if err != nil && err != redis.Nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
err = json.Unmarshal(ret, kind)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetMapData 存入一组数据
|
||
|
|
func (r *RedisClient) HSet(key string, data ...interface{}) error {
|
||
|
|
tmp := reflect.ValueOf(data[0])
|
||
|
|
if tmp.Kind() == reflect.Ptr {
|
||
|
|
tmp = reflect.ValueOf(data[0]).Elem()
|
||
|
|
}
|
||
|
|
if tmp.Kind() == reflect.Struct {
|
||
|
|
out := map[string]interface{}{}
|
||
|
|
if err := mapstructure.Decode(data[0], &out); err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return r.GetRedis().HSet(context.Background(), key, out).Err()
|
||
|
|
}
|
||
|
|
return r.GetRedis().HSet(context.Background(), key, data).Err()
|
||
|
|
}
|
||
|
|
|
||
|
|
// HGetJson 获取hash,以json存储
|
||
|
|
func (r *RedisClient) HGetJson(key, field string, ret interface{}) error {
|
||
|
|
res, err := r.GetRedis().HGet(context.Background(), key, field).Result()
|
||
|
|
if err != nil {
|
||
|
|
if err != redis.Nil {
|
||
|
|
log.Error("key:%v,field:%v,err:%v", key, field, err)
|
||
|
|
}
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if err := json.Unmarshal([]byte(res), ret); err != nil {
|
||
|
|
log.Error("key:%v,field:%v,err:%v", key, field, err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// HSetJson set hash,以json存储
|
||
|
|
func (r *RedisClient) HSetJson(key, field string, ret interface{}) error {
|
||
|
|
data, err := json.Marshal(ret)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
_, err = r.GetRedis().HSet(context.Background(), key, field, data).Result()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// HDel 删除hash
|
||
|
|
func (r *RedisClient) HDel(key, field string) error {
|
||
|
|
err := r.GetRedis().HDel(context.Background(), key, field).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("key:%v,field:%v,err:%v", key, field, err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// HGetAll 获得某个key的所有field
|
||
|
|
func (r *RedisClient) HGetAll(key string, ret interface{}) error {
|
||
|
|
err := r.GetRedis().HGetAll(context.Background(), key).Scan(ret)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("HGetAll fail:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// LPushJsonSlice 插入数组(data 必须是切片类型,元素转换成json存储)
|
||
|
|
func (r *RedisClient) LPushJsonSlice(key string, data interface{}) error {
|
||
|
|
val := reflect.ValueOf(data)
|
||
|
|
if val.Kind() != reflect.Slice {
|
||
|
|
return errors.New("unknown type")
|
||
|
|
}
|
||
|
|
for i := 0; i < val.Len(); i++ {
|
||
|
|
value, _ := json.Marshal(val.Index(i).Interface())
|
||
|
|
err := r.client.LPush(context.Background(), key, string(value)).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// RPushJsonSlice 插入数组(data 必须是切片类型,元素转换成json存储)
|
||
|
|
func (r *RedisClient) RPushJsonSlice(key string, data interface{}) error {
|
||
|
|
val := reflect.ValueOf(data)
|
||
|
|
if val.Kind() != reflect.Slice {
|
||
|
|
return errors.New("unknown type")
|
||
|
|
}
|
||
|
|
for i := 0; i < val.Len(); i++ {
|
||
|
|
value, _ := json.Marshal(val.Index(i).Interface())
|
||
|
|
err := r.client.RPush(context.Background(), key, string(value)).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetRankData 以score为参数倒序取set
|
||
|
|
func (r *RedisClient) GetRankData(key string) ([]redis.Z, error) {
|
||
|
|
return r.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, -1).Result()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Lock redis锁
|
||
|
|
func (r *RedisClient) Lock(key string, ex ...time.Duration) bool {
|
||
|
|
if len(ex) > 0 {
|
||
|
|
return r.client.SetNX(context.Background(), key, 0, ex[0]).Val()
|
||
|
|
}
|
||
|
|
return r.client.SetNX(context.Background(), key, 1, common.RedisExpireLock).Val()
|
||
|
|
}
|
||
|
|
|
||
|
|
// UnLock redis 解锁
|
||
|
|
func (r *RedisClient) UnLock(key string, ex ...time.Duration) int64 {
|
||
|
|
return r.client.Del(context.Background(), key).Val()
|
||
|
|
}
|
||
|
|
|
||
|
|
// WaitForLock redis等待解锁
|
||
|
|
func (r *RedisClient) WaitForLock(key string, ex ...time.Duration) {
|
||
|
|
for {
|
||
|
|
ok := r.Lock(key, ex...)
|
||
|
|
if ok {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
// t, _ := r.GetRedis().TTL(context.Background(), key).Result()
|
||
|
|
time.Sleep(500 * time.Millisecond)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetData 通用设置key value
|
||
|
|
func (r *RedisClient) SetData(key string, data interface{}, ex ...time.Duration) error {
|
||
|
|
if len(ex) > 0 {
|
||
|
|
return r.GetRedis().Set(context.Background(), key, data, ex[0]).Err()
|
||
|
|
}
|
||
|
|
return r.GetRedis().Set(context.Background(), key, data, 0).Err()
|
||
|
|
}
|
||
|
|
|
||
|
|
func (u *RedisClient) GetInt(key string) (data int, err error) {
|
||
|
|
data, err = u.client.Get(context.Background(), key).Int()
|
||
|
|
if err != nil && err != redis.Nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
func (u *RedisClient) GetInt64(key string) int64 {
|
||
|
|
data, err := u.client.Get(context.Background(), key).Int64()
|
||
|
|
if err != nil && err != redis.Nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
}
|
||
|
|
return data
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetString 通用获取string
|
||
|
|
func (r *RedisClient) GetString(key string) (string, error) {
|
||
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||
|
|
defer cancel()
|
||
|
|
ret, err := r.GetRedis().Get(ctx, key).Result()
|
||
|
|
return ret, err
|
||
|
|
}
|
||
|
|
|
||
|
|
func (u *RedisClient) Delkey(key string) int64 {
|
||
|
|
res := u.client.Del(context.Background(), key)
|
||
|
|
if err := res.Err(); err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
}
|
||
|
|
count, _ := res.Result()
|
||
|
|
return count
|
||
|
|
}
|
||
|
|
|
||
|
|
func (u *RedisClient) Exist(key string) bool {
|
||
|
|
ret, err := u.client.Exists(context.Background(), key).Result()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
if ret == 1 {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetData 通用设置key value
|
||
|
|
func (r *RedisClient) SetNX(key string, data interface{}, ex ...time.Duration) bool {
|
||
|
|
if len(ex) > 0 {
|
||
|
|
return r.GetRedis().SetNX(context.Background(), key, data, ex[0]).Val()
|
||
|
|
}
|
||
|
|
return r.GetRedis().SetNX(context.Background(), key, data, 0).Val()
|
||
|
|
}
|
||
|
|
|
||
|
|
func (u *RedisClient) Incr(key string, value int64) (int64, error) {
|
||
|
|
return u.client.IncrBy(context.Background(), key, value).Result()
|
||
|
|
// if err != nil {
|
||
|
|
// log.Error("err:%v", err)
|
||
|
|
// return false
|
||
|
|
// }
|
||
|
|
// if ret == 1 {
|
||
|
|
// return true
|
||
|
|
// }
|
||
|
|
// return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新玩家字段
|
||
|
|
func (u *RedisClient) HIncrBy(key, field string, inc int64) (err error) {
|
||
|
|
if exists, _ := u.client.Exists(context.Background(), key).Result(); exists == 0 {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
err = u.client.HIncrBy(context.Background(), key, field, inc).Err()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置超时
|
||
|
|
func (u *RedisClient) Expire(key string, ex time.Duration) (err error) {
|
||
|
|
err = u.client.Expire(context.Background(), key, ex).Err()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取超时
|
||
|
|
func (u *RedisClient) TTL(key string) (t time.Duration, err error) {
|
||
|
|
return u.client.TTL(context.Background(), key).Result()
|
||
|
|
}
|
||
|
|
|
||
|
|
// HGetInt 获得某个key的制定field的int
|
||
|
|
func (r *RedisClient) HGetInt(key, field string) int {
|
||
|
|
data, err := r.GetRedis().HGet(context.Background(), key, field).Int()
|
||
|
|
if err != nil && err != redis.Nil {
|
||
|
|
log.Error("HGetAll fail:%v", err)
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
return data
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) ZAdd(key string, score int64, member interface{}) error {
|
||
|
|
err := r.GetRedis().ZAdd(context.Background(), key, &redis.Z{Score: float64(score), Member: member}).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("ZAdd fail:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) ZIncr(key string, score int64, member interface{}) error {
|
||
|
|
err := r.GetRedis().ZIncr(context.Background(), key, &redis.Z{Score: float64(score), Member: member}).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("ZIncr fail:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) ZRange(key string) []redis.Z {
|
||
|
|
ret := r.GetRedis().ZRevRangeWithScores(context.Background(), key, 0, -1)
|
||
|
|
if ret.Err() != nil {
|
||
|
|
log.Error("err:%v", ret.Err())
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return ret.Val()
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) ZRem(key string, member interface{}) error {
|
||
|
|
err := r.GetRedis().ZRem(context.Background(), key, member).Err()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) ZRangeRe(key string, start, end int) []redis.Z {
|
||
|
|
ret, err := r.GetRedis().ZRevRangeWithScores(context.Background(), key, int64(start), int64(end)).Result()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return ret
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) ZRevRank(key string, member string) int {
|
||
|
|
ret, err := r.GetRedis().ZRevRank(context.Background(), key, member).Result()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return -1
|
||
|
|
}
|
||
|
|
return int(ret)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *RedisClient) ZScore(key string, member string) int {
|
||
|
|
ret, err := r.GetRedis().ZScore(context.Background(), key, member).Result()
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return -1
|
||
|
|
}
|
||
|
|
return int(ret)
|
||
|
|
}
|