github.com/15mga/kiwi@v0.0.2-0.20240324021231-b95d5c3ac751/util/rds/redis.go (about)

     1  package rds
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  
     7  	"github.com/15mga/kiwi/util"
     8  	"github.com/go-redsync/redsync/v4"
     9  	"github.com/gomodule/redigo/redis"
    10  )
    11  
    12  const (
    13  	DEL      = "DEL"      // DEL 用于在key存在时删除key
    14  	DUMP     = "DUMP"     // DUMP 返回指定key序列化的值
    15  	EXIST    = "EXIST"    // EXIST key是否存在
    16  	EXPIRE   = "EXPIRE"   // EXPIRE 设置秒为单位的过期时间
    17  	EXPIREAT = "EXPIREAT" // EXPIREAT 设置时间戳为过期时间
    18  	PEXPIRE  = "PEXPIRE"  // PEXPIRE 设置毫秒为单位的过期时间
    19  	KEYS     = "KEYS"     // KEYS 获取所有符合模式的键
    20  	MOVE     = "MOVE"     // MOVE 将当前数据库的键值对移动到指定数据库
    21  	PERSIST  = "PERSIST"  // PERSIST 移除key的过期时间
    22  	PTTL     = "PTTL"     // PTTL 返回key以毫秒为单位的过期时间
    23  	TTL      = "TTL"      // TTL 返回key以秒为单位的过期时间
    24  	RENAME   = "RENAME"   // RENAME 修改key名称
    25  	RENAMENX = "RENAMENX" // RENAMENX 将key修改为不存在的新key
    26  	TYPE     = "TYPE"     // TYPE 返回key对应值的类型
    27  	SCAN     = "SCAN"     // SCAN 迭代数据库中的数据库键
    28  	MATCH    = "MATCH"    // MATCH 匹配
    29  
    30  	SET         = "SET"         // SET 设置健值
    31  	GET         = "GET"         // GET 获取指定key的值
    32  	GETRANGE    = "GETRANGE"    // GETRANGE 返回指定key的值的子字符串
    33  	GETSET      = "GETSET"      // GETSET 将给定key的值设为value,并返回key的旧值
    34  	GETBIT      = "GETBIT"      // GETBIT 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
    35  	MGET        = "MGET"        // MGET 获取所有(一个或多个)给定 key 的值。
    36  	SETBIT      = "SETBIT"      // SETBIT 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)
    37  	SETEX       = "SETEX"       // SETEX 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。
    38  	SETNX       = "SETNX "      // SETNX 只有在 key 不存在时设置 key 的值
    39  	SETRANGE    = "SETRANGE"    // SETRANGE 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始
    40  	STRLEN      = "STRLEN"      // STRLEN 返回 key 所储存的字符串值的长度
    41  	MSET        = "MSET"        // MSET 同时设置一个或多个 key-value 对
    42  	MSETNX      = "MSETNX"      // MSETNX 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
    43  	PSETEX      = "PSETEX"      // PSETEX 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位
    44  	INCR        = "INCR"        // INCR 将 key 中储存的数字值增一
    45  	INCRBY      = "INCRBY"      // INCRBY 将 key 所储存的值加上给定的增量值(increment)
    46  	INCRBYFLOAT = "INCRBYFLOAT" // INCRBYFLOAT 将 key 所储存的值加上给定的浮点增量值(increment)
    47  	DECR        = "DECR"        // DECR 将 key 中储存的数字值减一
    48  	DECRBY      = "DECRBY"      // DECRBY key 所储存的值减去给定的减量值(decrement)
    49  	APPEND      = "APPEND"      // APPEND 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾
    50  
    51  	HDEL         = "HDEL"         // HDEL 删除一个或多个哈希表字段
    52  	HEXISTS      = "HEXISTS"      // HEXISTS 查看哈希表 key 中,指定的字段是否存在
    53  	HGET         = "HGET"         // HGET 获取存储在哈希表中指定字段的值
    54  	HGETALL      = "HGETALL"      // HGETALL 获取在哈希表中指定 key 的所有字段和值
    55  	HINCRBY      = "HINCRBY"      // HINCRBY 为哈希表 key 中的指定字段的整数值加上增量 increment
    56  	HINCRBYFLOAT = "HINCRBYFLOAT" // HINCRBYFLOAT 为哈希表 key 中的指定字段的浮点数值加上增量 increment
    57  	HKEYS        = "HKEYS"        // HKEYS 获取所有哈希表中的字段
    58  	HLEN         = "HLEN"         // HLEN 获取哈希表中字段的数量
    59  	HMGET        = "HMGET"        // HMGET 获取所有给定字段的值
    60  	HMSET        = "HMSET"        // HMSET 同时将多个 field-value (域-值)对设置到哈希表 key 中
    61  	HSET         = "HSET"         // HSET 将哈希表 key 中的字段 field 的值设为 value
    62  	HSETNX       = "HSETNX"       // HSETNX 只有在字段 field 不存在时,设置哈希表字段的值
    63  	HVALS        = "HVALS"        // HVALS 获取哈希表中所有值
    64  	HSCAN        = "HSCAN"        // HSCAN 迭代哈希表中的键值对
    65  
    66  	BLPOP      = "BLPOP"      // 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
    67  	BRPOP      = "BRPOP"      // 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
    68  	BRPOPLPUSH = "BRPOPLPUSH" // 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
    69  	LINDEX     = "LINDEX"     // 通过索引获取列表中的元素
    70  	LINSERT    = "LINSERT"    // 在列表的元素前或者后插入元素
    71  	BEFORE     = "BEFORE"
    72  	AFTER      = "AFTER"
    73  	LLEN       = "LLEN"      // 获取列表长度
    74  	LPOP       = "LPOP"      // 移出并获取列表的第一个元素
    75  	LPUSH      = "LPUSH"     // 将一个或多个值插入到列表头部
    76  	LPUSHX     = "LPUSHX"    // 将一个值插入到已存在的列表头部
    77  	LRANGE     = "LRANGE"    // 获取列表指定范围内的元素
    78  	LREM       = "LREM"      // 移除列表元素
    79  	LSET       = "LSET"      // 通过索引设置列表元素的值
    80  	LTRIM      = "LTRIM"     // 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
    81  	RPOP       = "RPOP"      // 移除列表的最后一个元素,返回值为移除的元素
    82  	RPOPLPUSH  = "RPOPLPUSH" // 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
    83  	RPUSH      = "RPUSH"     // 在列表中添加一个或多个值
    84  	RPUSHX     = "RPUSHX"    // 为已存在的列表添加值
    85  
    86  	SADD        = "SADD"        // SADD 向集合添加一个或多个成员
    87  	SCARD       = "SCARD"       // SCARD 获取集合的成员数
    88  	SDIFF       = "SDIFF"       // SDIFF 返回第一个集合与其他集合之间的差异
    89  	SDIFFSTORE  = "SDIFFSTORE"  // SDIFFSTORE 返回给定所有集合的差集并存储在 destination 中
    90  	SINTER      = "SINTER"      // SINTER 返回给定所有集合的交集
    91  	SINTERSTORE = "SINTERSTORE" // SINTERSTORE 返回给定所有集合的交集并存储在 destination 中
    92  	SISMEMBER   = "SISMEMBER"   // SISMEMBER 判断 member 元素是否是集合 key 的成员
    93  	SMEMBERS    = "SMEMBERS"    // SMEMBERS 返回集合中的所有成员
    94  	SMOVE       = "SMOVE"       // SMOVE 将 member 元素从 source 集合移动到 destination 集合
    95  	SPOP        = "SPOP"        // SPOP 移除并返回集合中的一个随机元素
    96  	SRANDMEMBER = "SRANDMEMBER" // SRANDMEMBER 返回集合中一个或多个随机数
    97  	SREM        = "SREM"        // SREM 移除集合中一个或多个成员
    98  	SUNION      = "SUNION"      // SUNION 返回所有给定集合的并集
    99  	SUNIONSTORE = "SUNIONSTORE" // SUNIONSTORE 所有给定集合的并集存储在 destination 集合中
   100  	SSCAN       = "SSCAN"       // SSCAN 迭代集合中的元素
   101  
   102  	ZADD             = "ZADD"             // ZADD 向有序集合添加一个或多个成员,或者更新已存在成员的分数
   103  	ZCARD            = "ZCARD"            // ZCARD 获取有序集合的成员数
   104  	ZCOUNT           = "ZCOUNT"           // ZCOUNT 计算在有序集合中指定区间分数的成员数
   105  	ZINCRBY          = "ZINCRBY"          // ZINCRBY 有序集合中对指定成员的分数加上增量 increment
   106  	ZINTERSTOR       = "ZINTERSTOR"       // ZINTERSTOR 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中
   107  	ZLEXCOUNT        = "ZLEXCOUNT"        // ZLEXCOUNT 在有序集合中计算指定字典区间内成员数量
   108  	ZRANGE           = "ZRANGE"           // ZRANGE 通过索引区间返回有序集合指定区间内的成员
   109  	ZRANGEBYLEX      = "ZRANGEBYLEX"      // ZRANGEBYLEX 通过字典区间返回有序集合的成员
   110  	ZRANGEBYSCORE    = "ZRANGEBYSCORE"    // ZRANGEBYSCORE 通过分数返回有序集合指定区间内的成员
   111  	ZRANK            = "ZRANK"            // ZRANK 返回有序集合中指定成员的索引
   112  	ZREM             = "ZREM"             // ZREM 移除有序集合中的一个或多个成员
   113  	ZREMRANGEBYLEX   = "ZREMRANGEBYLEX"   // ZREMRANGEBYLEX 移除有序集合中给定的字典区间的所有成员
   114  	ZREMRANGEBYRANK  = "ZREMRANGEBYRANK"  // ZREMRANGEBYRANK 移除有序集合中给定的排名区间的所有成员
   115  	ZREMRANGEBYSCORE = "ZREMRANGEBYSCORE" // ZREMRANGEBYSCORE 移除有序集合中给定的分数区间的所有成员
   116  	ZREVRANGE        = "ZREVRANGE"        // ZREVRANGE 返回有序集中指定区间内的成员,通过索引,分数从高到低
   117  	ZREVRANGEBYSCORE = "ZREVRANGEBYSCORE" // ZREVRANGEBYSCORE 返回有序集中指定分数区间内的成员,分数从高到低排序
   118  	ZREVRANK         = "ZREVRANK"         // ZREVRANK 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
   119  	ZSCORE           = "ZSCORE"           // ZSCORE 返回有序集中,成员的分数值
   120  	ZUNIONSTORE      = "ZUNIONSTORE"      // ZUNIONSTORE 计算给定的一个或多个有序集的并集,并存储在新的 key 中
   121  	ZSCAN            = "ZSCAN"            // ZSCAN 迭代有序集合中的元素(包括元素成员和元素分值)
   122  
   123  	PFADD   = "PFADD"   // PFADD 添加指定元素到 HyperLogLog 中
   124  	PFCOUNT = "PFCOUNT" // PFCOUNT 返回给定 HyperLogLog 的基数估算值
   125  	PFMERGE = "PFMERGE" // PFMERGE 将多个 HyperLogLog 合并为一个 HyperLogLog
   126  
   127  	PSUBSCRIBE   = "PSUBSCRIBE"   // PSUBSCRIBE 订阅一个或多个符合给定模式的频道
   128  	PUBSUB       = "PUBSUB"       // PUBSUB 查看订阅与发布系统状态
   129  	PUBLISH      = "PUBLISH"      // PUBLISH 将信息发送到指定的频道
   130  	PUNSUBSCRIBE = "PUNSUBSCRIBE" // PUNSUBSCRIBE 退订所有给定模式的频道
   131  	SUBSCRIBE    = "SUBSCRIBE"    // SUBSCRIBE 订阅给定的一个或多个频道的信息
   132  	UNSUBSCRIBE  = "UNSUBSCRIBE"  // UNSUBSCRIBE 指退订给定的频道
   133  
   134  	DISCARD = "DISCARD" // DISCARD 取消事务,放弃执行事务块内的所有命令
   135  	EXEC    = "EXEC"    // EXEC 执行所有事务块内的命令
   136  	MULTI   = "MULTI"   // MULTI 标记一个事务块的开始
   137  	UNWATCH = "UNWATCH" // UNWATCH 取消 WATCH 命令对所有 key 的监视
   138  	WATCH   = "WATCH"   // 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
   139  
   140  	EVAL          = "EVAL"          // EVAL 执行 Lua 脚本
   141  	EVALSHA       = "EVALSHA"       // EVALSHA 执行 Lua 脚本
   142  	SCRIPT_EXISTS = "SCRIPT EXISTS" // SCRIPT_EXISTS 查看指定的脚本是否已经被保存在缓存当中
   143  	SCRIPT_FLUSH  = "SCRIPT FLUSH"  // SCRIPT_FLUSH 从脚本缓存中移除所有脚本
   144  	SCRIPT_KILL   = "SCRIPT KILL"   // SCRIPT_KILL 杀死当前正在运行的 Lua 脚本
   145  	SCRIPT_LOAD   = "SCRIPT LOAD"   // SCRIPT_LOAD 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本
   146  
   147  	AUTH   = "AUTH"   // AUTH 验证密码是否正确
   148  	ECHO   = "ECHO"   // ECHO 打印字符串
   149  	PING   = "PING"   // PING 查看服务是否运行
   150  	QUIT   = "QUIT"   // QUIT 关闭当前连接
   151  	SELECT = "SELECT" // SELECT 切换到指定的数据库
   152  
   153  	BGREWRITEAOF     = "BGREWRITEAOF"     // BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作
   154  	BGSAVE           = "BGSAVE"           // BGSAVE 在后台异步保存当前数据库的数据到磁盘
   155  	CLIENT_KILL      = "CLIENT KILL"      // CLIENT_KILL 关闭客户端连接
   156  	CLIENT_LIST      = "CLIENT LIST"      // CLIENT_LIST 获取连接到服务器的客户端连接列表
   157  	CLIENT_GETNAME   = "CLIENT GETNAME"   // CLIENT_GETNAME 获取连接的名称
   158  	CLIENT_PAUSE     = "CLIENT PAUSE"     // CLIENT_PAUSE 在指定时间内终止运行来自客户端的命令
   159  	CLIENT_SETNAME   = "CLIENT SETNAME"   // CLIENT_SETNAME 设置当前连接的名称
   160  	CLUSTER_SLOTS    = "CLUSTER SLOTS"    // CLUSTER_SLOTS 获取集群节点的映射数组
   161  	COMMAND          = "COMMAND"          // COMMAND 获取 Redis 命令详情数组
   162  	COMMAND_COUNT    = "COMMAND COUNT"    // COMMAND_COUNT 获取 Redis 命令总数
   163  	COMMAND_GETKEYS  = "COMMAND GETKEYS"  // COMMAND_GETKEYS 获取给定命令的所有键
   164  	TIME             = "TIME"             // TIME 返回当前服务器时间
   165  	COMMAND_INFO     = "COMMAND INFO"     // COMMAND_INFO 获取指定 Redis 命令描述的数组
   166  	CONFIG_GET       = "CONFIG GET"       // CONFIG_GET 获取指定配置参数的值
   167  	CONFIG_REWRITE   = "CONFIG REWRITE"   // CONFIG_REWRITE 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写
   168  	CONFIG_SET       = "CONFIG SET"       // CONFIG_SET 修改 redis 配置参数,无需重启
   169  	CONFIG_RESETSTAT = "CONFIG RESETSTAT" // CONFIG_RESETSTAT 重置 INFO 命令中的某些统计数据
   170  	DBSIZE           = "DBSIZE"           // DBSIZE 返回当前数据库的 key 的数量
   171  	DEBUG_OBJECT     = "DEBUG OBJECT"     // DEBUG_OBJECT 获取 key 的调试信息
   172  	DEBUG_SEGFAULT   = "DEBUG SEGFAULT"   // DEBUG_SEGFAULT 让 Redis 服务崩溃
   173  	FLUSHALL         = "FLUSHALL"         // FLUSHALL 删除所有数据库的所有key
   174  	FLUSHDB          = "FLUSHDB"          // FLUSHDB 删除当前数据库的所有key
   175  	INFO             = "INFO"             // INFO 获取 Redis 服务器的各种信息和统计数值
   176  	LASTSAVE         = "LASTSAVE"         // LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示
   177  	MONITOR          = "MONITOR"          // MONITOR 实时打印出 Redis 服务器接收到的命令,调试用
   178  	ROLE             = "ROLE"             // ROLE 返回主从实例所属的角色
   179  	SAVE             = "SAVE"             // SAVE 同步保存数据到硬盘
   180  	SHUTDOWN         = "SHUTDOWN"         // SHUTDOWN 异步保存数据到硬盘,并关闭服务器
   181  	SLAVEOF          = "SLAVEOF"          // SLAVEOF 将当前服务器转变为指定服务器的从属服务器(slave server)
   182  	SLOWLOG          = "SLOWLOG"          // SLOWLOG 管理 redis 的慢日志
   183  	SYNC             = "SYNC"             // SYNC 用于复制功能(replication)的内部命令
   184  
   185  	GEOADD            = "GEOADD"            // GEOADD 存储指定的地理空间位置
   186  	GEOPOS            = "GEOPOS "           // GEOPOS 获取key的地理位置
   187  	GEODIST           = "GEODIST"           // GEODIST 返回2个点之间的距离
   188  	GEORADIUS         = "GEORADIUS"         // GEORADIUS 返回以指定经纬中心范围内的的地理位置
   189  	GEORADIUSBYMEMBER = "GEORADIUSBYMEMBER" // GEORADIUSBYMEMBER 返回以指定位置中心范围内的的地理位置
   190  	GEOHASH           = "GEOHASH"           // GEOHASH 使用 geohash 来保存地理位置的坐标
   191  
   192  	XADD               = "XADD"               // XADD 添加消息到末尾
   193  	XTRIM              = "XTRIM"              // XTRIM 对流进行修剪,限制长度
   194  	XDEL               = "XDEL"               // XDEL 删除消息
   195  	XLEN               = "XLEN"               // XLEN 获取流包含的元素数量,即消息长度
   196  	XRANGE             = "XRANGE"             // XRANGE 获取消息列表,会自动过滤已经删除的消息
   197  	XREVRANGE          = "XREVRANGE"          // XREVRANGE 反向获取消息列表,ID 从大到小
   198  	XREAD              = "XREAD"              // XREAD 以阻塞或非阻塞方式获取消息列表
   199  	STREAMS            = "STREAMS"            // STREAMS 流
   200  	COUNT              = "COUNT"              // COUNT 数量
   201  	XGROUP             = "XGROUP"             // XGROUP 消费者组
   202  	GROUP              = "GROUP"              // GROUP 消费者组
   203  	CREATE             = "CREATE"             // CREATE 创建
   204  	CREATECONSUMER     = "CREATECONSUMER"     // CREATECONSUMER 创建消费者
   205  	XREADGROUP         = "XREADGROUP"         // XREADGROUP 读取消费者组中的消息
   206  	XACK               = "XACK"               // XACK 将消息标记为已处理
   207  	XGROUP_SETID       = "XGROUP SETID"       // XGROUP_SETID 为消费者组设置新的最后递送消息ID
   208  	XGROUP_DELCONSUMER = "XGROUP DELCONSUMER" // XGROUP_DELCONSUMER 删除消费者
   209  	XGROUP_DESTROY     = "XGROUP DESTROY"     // XGROUP_DESTROY 删除消费者组
   210  	XPENDING           = "XPENDING"           // XPENDING 显示待处理消息的相关信息
   211  	XCLAIM             = "XCLAIM"             // XCLAIM 转移消息的归属权
   212  	XINFO              = "XINFO"              // XINFO 查看流和消费者组的相关信息
   213  	XINFO_GROUPS       = "XINFO GROUPS"       // XINFO_GROUPS 打印消费者组的信息
   214  	XINFO_STREAM       = "XINFO STREAM"       // XINFO_STREAM 打印流信息
   215  
   216  	Json              = "$"
   217  	JSON_ARR_APPEND   = "JSON.ARRAPPEND"    //json数组添加元素
   218  	JSON_ARR_INDEX    = "JSON.ARRINDEX"     //
   219  	JSON_ARR_INSERT   = "JSON.ARRINSERT"    //
   220  	JSON_ARR_LEN      = "JSON.ARRLEN"       //
   221  	JSON_ARR_POP      = "JSON.ARRPOP"       //
   222  	JSON_ARR_TRIM     = "JSON.ARRTRIM"      //
   223  	JSON_CLEAR        = "JSON.CLEAR"        //
   224  	JSON_DEBUG        = "JSON.DEBUG"        //
   225  	JSON_DEBUG_MEMORY = "JSON.DEBUG MEMORY" //
   226  	JSON_DEL          = "JSON.DEL"          //
   227  	JSON_FORGET       = "JSON.FORGET"       //
   228  	JSON_GET          = "JSON.GET"          //
   229  	JSON_MGET         = "JSON.MGET"         //
   230  	JSON_NUM_INCRBY   = "JSON.NUMINCRBY"    //
   231  	JSON_NUM_MULTBY   = "JSON.NUMMULTBY"    //
   232  	JSON_OBJ_KEYS     = "JSON.OBJKEYS"      //
   233  	JSON_OBJLEN       = "JSON.OBJLEN"       //
   234  	JSON_RESP         = "JSON.RESP"         //
   235  	JSON_SET          = "JSON.SET"          //
   236  	JSON_STR_APPEND   = "JSON.STRAPPEND"    //
   237  	JSON_STR_LEN      = "JSON.STRLEN"       //
   238  	JSON_TOGGLE       = "JSON.TOGGLE"       //
   239  	JSON_TYPE         = "JSON.TYPE"         //
   240  )
   241  
   242  type (
   243  	ToRedisConn      func() redis.Conn
   244  	ToRedisConnError func() (redis.Conn, error)
   245  	ToRedisConnErr   func() (redis.Conn, *util.Err)
   246  	ConnToErr        func(redis.Conn) *util.Err
   247  	redisRedisOption struct {
   248  		connFac  ToRedisConnError
   249  		connPool *redis.Pool
   250  	}
   251  	RedisOption func(*redisRedisOption)
   252  )
   253  
   254  func ConnFac(fac ToRedisConnError) RedisOption {
   255  	return func(opt *redisRedisOption) {
   256  		opt.connFac = fac
   257  	}
   258  }
   259  
   260  func ConnPool(pool *redis.Pool) RedisOption {
   261  	return func(opt *redisRedisOption) {
   262  		opt.connPool = pool
   263  	}
   264  }
   265  
   266  func InitRedis(opts ...RedisOption) {
   267  	_Redis = NewRedis(opts...)
   268  }
   269  
   270  func NewRedis(opts ...RedisOption) *Redis {
   271  	opt := &redisRedisOption{}
   272  	for _, o := range opts {
   273  		o(opt)
   274  	}
   275  	return &Redis{
   276  		redisRedisOption: opt,
   277  	}
   278  }
   279  
   280  type Redis struct {
   281  	redisRedisOption *redisRedisOption
   282  	locker           *redsync.Redsync
   283  }
   284  
   285  func (r *Redis) GetConn() (redis.Conn, *util.Err) {
   286  	conn, err := r.redisRedisOption.connFac()
   287  	return conn, util.WrapErr(util.EcRedisErr, err)
   288  }
   289  
   290  func (r *Redis) SpawnConn() redis.Conn {
   291  	return r.redisRedisOption.connPool.Get()
   292  }
   293  
   294  func (r *Redis) Lock(key string, fn func(), opts ...redsync.Option) *util.Err {
   295  	if fn == nil {
   296  		return nil
   297  	}
   298  	m := r.locker.NewMutex(key, opts...)
   299  	e := m.Lock()
   300  	if e != nil {
   301  		return util.WrapErr(util.EcRedisErr, e)
   302  	}
   303  	fn()
   304  	_, e = m.Unlock()
   305  	return util.WrapErr(util.EcRedisErr, e)
   306  }
   307  
   308  var (
   309  	_Redis *Redis
   310  )
   311  
   312  func GetConn() (redis.Conn, *util.Err) {
   313  	return _Redis.GetConn()
   314  }
   315  
   316  func SpawnConn() redis.Conn {
   317  	return _Redis.SpawnConn()
   318  }
   319  
   320  func FnSpawnConn(fn ConnToErr) (err *util.Err) {
   321  	conn := _Redis.SpawnConn()
   322  	err = fn(conn)
   323  	_ = conn.Close()
   324  	return
   325  }
   326  
   327  func Lock(key string, fn func(), opts ...redsync.Option) *util.Err {
   328  	return _Redis.Lock(key, fn, opts...)
   329  }
   330  
   331  func JsonSet(conn redis.Conn, key string, obj any, fields ...string) *util.Err {
   332  	str, _ := util.JsonMarshal(obj)
   333  	f := mergeJsonFields(fields...)
   334  	_, e := conn.Do(JSON_SET, key, f, str)
   335  	if e != nil {
   336  		return util.NewErr(util.EcRedisErr, util.M{
   337  			"error":  "empty or more than one",
   338  			"key":    key,
   339  			"obj":    obj,
   340  			"fields": fields,
   341  		})
   342  	}
   343  	return nil
   344  }
   345  
   346  func JsonSetStr(conn redis.Conn, key string, str string, fields ...string) *util.Err {
   347  	f := mergeJsonFields(fields...)
   348  	_, e := conn.Do(JSON_SET, key, f, str)
   349  	if e != nil {
   350  		return util.NewErr(util.EcRedisErr, util.M{
   351  			"error":  e.Error(),
   352  			"key":    key,
   353  			"str":    str,
   354  			"fields": fields,
   355  		})
   356  	}
   357  	return nil
   358  }
   359  
   360  func JsonGet[T any](conn redis.Conn, key string, v *T, fields ...string) *util.Err {
   361  	var values []T
   362  	err := JsonGetSlice[T](conn, key, &values, fields...)
   363  	if err != nil {
   364  		return err
   365  	}
   366  	if len(values) != 1 {
   367  		return util.NewErr(util.EcRedisErr, util.M{
   368  			"error":  "empty or more than one",
   369  			"key":    key,
   370  			"fields": fields,
   371  		})
   372  	}
   373  	*v = values[0]
   374  	return nil
   375  }
   376  
   377  func mergeJsonFields(fields ...string) string {
   378  	f := Json
   379  	if len(fields) > 0 {
   380  		f += "." + strings.Join(fields, ".")
   381  	}
   382  	return f
   383  }
   384  
   385  func JsonGetSlice[T any](conn redis.Conn, key string, v *[]T, fields ...string) *util.Err {
   386  	f := mergeJsonFields(fields...)
   387  	reply, e := redis.Bytes(conn.Do(JSON_GET, key, f))
   388  	if e != nil {
   389  		return util.NewErr(util.EcRedisErr, util.M{
   390  			"error":  e.Error(),
   391  			"key":    key,
   392  			"fields": fields,
   393  		})
   394  	}
   395  	err := util.JsonUnmarshal(reply, v)
   396  	if err != nil {
   397  		return util.NewErr(util.EcRedisErr, util.M{
   398  			"error":  err.Error(),
   399  			"key":    key,
   400  			"fields": fields,
   401  		})
   402  	}
   403  	return nil
   404  }
   405  
   406  func Scan(conn redis.Conn, match string, step int, fn util.FnStrSlc) *util.Err {
   407  	cursor := 0
   408  	for {
   409  		slc, e := redis.Values(conn.Do(SCAN, cursor, MATCH, match, COUNT, step))
   410  		if e != nil {
   411  			return util.WrapErr(util.EcRedisErr, e)
   412  		}
   413  		items := slc[1].([]any)
   414  		keys := make([]string, len(items))
   415  		for i, item := range items {
   416  			keys[i] = string(item.([]byte))
   417  		}
   418  		fn(keys)
   419  		idxStr := string(slc[0].([]byte))
   420  		cursor, e = strconv.Atoi(idxStr)
   421  		if e != nil {
   422  			return util.NewErr(util.EcRedisErr, util.M{
   423  				"error": e.Error(),
   424  				"match": match,
   425  				"step":  step,
   426  			})
   427  		}
   428  		if cursor == 0 {
   429  			return nil
   430  		}
   431  	}
   432  }