Files
public/myredis/rediscon.go
2021-04-16 19:59:56 +08:00

373 lines
7.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package myredis
import (
"context"
"fmt"
"strconv"
"strings"
"time"
"github.com/gomodule/redigo/redis"
"github.com/xxjwxc/public/dev"
"github.com/xxjwxc/public/mylog"
"github.com/xxjwxc/public/tools"
)
type base struct {
*MyRedis
}
func (mc *base) getCtx() context.Context {
return context.Background()
}
func (mc *base) getKey(key interface{}) string {
tmp := ""
if len(mc.conf.groupName) > 0 {
tmp = fmt.Sprintf("%v:", mc.conf.groupName)
}
switch t := key.(type) {
case []byte:
return fmt.Sprintf("%v%v", tmp, string(t))
case string:
return fmt.Sprintf("%v%v", tmp, t)
default:
return fmt.Sprintf("%v%v", tmp, tools.JSONDecode(key))
}
}
func (mc *base) encodeValue(value interface{}) interface{} {
switch t := value.(type) {
case int32, byte, string, bool, int, uint, int8, int16, int64, uint16, uint32, uint64, float32, float64: // 基础类型
return t
default:
return tools.JSONDecode(value)
// data, _ := serializing.Encode(value)
// return data
}
}
func (mc *base) decodeValue(in, out interface{}) (err error) {
if in == nil {
return fmt.Errorf("not fond")
}
var reply string
switch t := in.(type) {
case []byte:
reply = string(t)
default:
return fmt.Errorf("decodeValue err in type not find:%v", t)
}
switch o := out.(type) {
case *string: // string类型
*o = reply
return nil
case *int32:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int32(i64)
return err
case *bool:
b, err := strconv.ParseBool(string(reply))
*o = b
return err
case *int:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int(i64)
return err
case *int8:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int8(i64)
return err
case *int16:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int16(i64)
return err
case *int64:
i64, err := strconv.ParseInt(string(reply), 10, 64)
*o = int64(i64)
return err
case *uint:
i64, err := strconv.ParseUint(reply, 10, 0)
*o = uint(i64)
return err
case *uint8:
i64, err := strconv.ParseUint(reply, 10, 0)
*o = uint8(i64)
return err
case *uint16:
i64, err := strconv.ParseUint(reply, 10, 0)
*o = uint16(i64)
return err
case *uint32:
i64, err := strconv.ParseInt(string(reply), 10, 0)
*o = uint32(i64)
return err
case *uint64:
i64, err := strconv.ParseUint(reply, 10, 64)
*o = uint64(i64)
return err
case *float32:
f64, err := strconv.ParseFloat(string(reply), 32)
*o = float32(f64)
return err
case *float64: // 基础类型
f64, err := strconv.ParseFloat(string(reply), 64)
*o = float64(f64)
return err
default:
tools.JSONEncode(reply, out) // 复杂类型
return nil
//return serializing.Decode(t, out)
}
// return fmt.Errorf("decodeValue err not match:%v %v", in, out)
}
func (mc *base) ping(con redis.Conn) bool {
if con == nil {
return false
}
_, err := con.Do("PING")
if err != nil {
mylog.Errorf("ping redis error: %s", err)
return false
}
return true
}
// Dial 获取一个链接
func (mc *base) build() (con redis.Conn, err error) {
err = fmt.Errorf("not fond ")
index := mc.conf.addrIdex
len := len(mc.conf.addrs)
b := false
for i := 0; i < len; i++ {
index = (mc.conf.addrIdex + i) % len
con, err = redis.Dial("tcp", mc.conf.addrs[index], redis.DialClientName(mc.conf.clientName),
redis.DialConnectTimeout(mc.conf.timeout), redis.DialDatabase(mc.conf.db),
redis.DialPassword(mc.conf.pwd), redis.DialReadTimeout(mc.conf.readTimeout), redis.DialWriteTimeout(mc.conf.writeTimeout),
)
if err != nil {
mylog.Error(err)
}
if mc.ping(con) {
b = true
}
}
if b {
mc.conf.addrIdex = (index + 1) % len
}
return
}
// Dial 获取一个链接
func (mc *base) Dial() (redis.Conn, error) {
mc.mtx.Lock()
defer mc.mtx.Unlock()
return mc.build() // 创建连接
}
func (mc *base) Do(con redis.Conn, commandName string, args ...interface{}) (reply interface{}, err error) {
if dev.IsDev() {
cmd := commandName
for _, v := range args {
cmd += fmt.Sprintf(" %v", v)
}
mylog.Infof("redis req :%v", cmd)
}
if con != nil {
reply, err = con.Do(commandName, args...)
// show log
if dev.IsDev() {
tmp := ""
switch reply := reply.(type) {
case []byte:
tmp = string(reply)
case string:
tmp = reply
case int64:
tmp = fmt.Sprintf("%v", reply)
}
mylog.Infof("redis resp:%v,%v", tmp, err)
}
return
}
return nil, fmt.Errorf("con is nil")
}
func (mc *base) fixKeyGroupName(key string) string {
tmp := ""
if len(mc.conf.groupName) > 0 {
tmp = fmt.Sprintf("%v:", mc.conf.groupName)
}
return strings.TrimPrefix(key, tmp)
}
type redisConOlny struct {
base
con redis.Conn
}
// Destory 析构
func (mc *redisConOlny) Destory() {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.con != nil {
err := mc.con.Close()
if err != nil {
mylog.Error(err)
}
mc.con = nil
}
}
// GetRedisClient ...
func (mc *redisConOlny) GetRedisClient() redis.Conn {
if mc.con == nil {
con, _ := mc.Dial()
mc.con = con
}
return mc.con
}
// Ping 判断是否能ping通
func (mc *redisConOlny) Ping() bool {
return mc.ping(mc.GetRedisClient())
}
// 判断是否能ping通
// Add 添加一个缓存 lifeSpan:缓存时间0表示永不超时
func (mc *redisConOlny) Add(key interface{}, value interface{}, lifeSpan time.Duration) error {
var args []interface{}
args = append(args, mc.getKey(key), mc.encodeValue(value))
if lifeSpan > 0 {
if usePrecise(lifeSpan) {
args = append(args, "px", formatMs(lifeSpan))
} else {
args = append(args, "ex", formatSec(lifeSpan))
}
} else if lifeSpan == keepTTL {
args = append(args, "keepttl")
}
_, err := mc.Do(mc.GetRedisClient(), "SET", args...)
if err != nil {
mylog.Error(err)
}
return err
}
// Value 查找一个cache
func (mc *redisConOlny) Value(key interface{}, value interface{}) (err error) {
repy, err := mc.Do(mc.GetRedisClient(), "GET", mc.getKey(key))
if err != nil {
mylog.Error(err)
return err
}
return mc.decodeValue(repy, value)
}
// IsExist 判断key是否存在
func (mc *redisConOlny) IsExist(key interface{}) bool {
repy, err := mc.Do(mc.GetRedisClient(), "EXISTS", mc.getKey(key))
if err != nil {
mylog.Error(err)
return false
}
exist, err := redis.Bool(repy, err) // 转化bool格式
if err != nil {
mylog.Error(err)
return false
}
return exist
}
// Delete 删除一个cache
func (mc *redisConOlny) Delete(key interface{}) error {
_, err := mc.Do(mc.GetRedisClient(), "del", mc.getKey(key))
if err != nil {
mylog.Error(err)
return err
}
return err
}
// Clear 清空表內容
func (mc *redisConOlny) Clear() error {
out, err := mc.GetKeyS("*")
if err != nil {
return err
}
for _, v := range out {
err = mc.Delete(v)
if err != nil {
return err
}
}
return err
}
// GetKeyS 查询所有key
func (mc *redisConOlny) GetKeyS(key interface{}) ([]string, error) {
var keys []string
repy, err := mc.Do(mc.GetRedisClient(), "keys", mc.getKey(key))
if err != nil {
mylog.Error(err)
return keys, err
}
switch t := repy.(type) {
case []interface{}:
for _, v := range t {
out, err := redis.String(v, nil)
if err != nil {
mylog.Error(err)
}
keys = append(keys, mc.fixKeyGroupName(out))
}
default:
return keys, fmt.Errorf("decodeValue err in type not find:%v", t)
}
return keys, err
}
// Close 关闭一个连接
func (mc *redisConOlny) Close() (err error) {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.con != nil {
err = mc.con.Close()
mc.con = nil
}
return
}
func usePrecise(dur time.Duration) bool {
return dur < time.Second || dur%time.Second != 0
}
func formatMs(dur time.Duration) int64 {
if dur > 0 && dur < time.Millisecond {
return 1
}
return int64(dur / time.Millisecond)
}
func formatSec(dur time.Duration) int64 {
if dur > 0 && dur < time.Second {
return 1
}
return int64(dur / time.Second)
}