2013-09-29 12:06:49 +04:00
|
|
|
package redis
|
|
|
|
|
|
|
|
import (
|
2020-03-11 17:26:42 +03:00
|
|
|
"context"
|
2013-09-29 12:06:49 +04:00
|
|
|
"fmt"
|
2018-08-02 14:48:46 +03:00
|
|
|
"net"
|
2013-09-29 12:06:49 +04:00
|
|
|
"strconv"
|
|
|
|
"time"
|
2016-03-12 11:52:13 +03:00
|
|
|
|
2023-01-23 09:48:54 +03:00
|
|
|
"github.com/redis/go-redis/v9/internal"
|
|
|
|
"github.com/redis/go-redis/v9/internal/hscan"
|
|
|
|
"github.com/redis/go-redis/v9/internal/proto"
|
|
|
|
"github.com/redis/go-redis/v9/internal/util"
|
2013-09-29 12:06:49 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
type Cmder interface {
|
2017-05-09 12:44:36 +03:00
|
|
|
Name() string
|
2020-05-09 17:34:50 +03:00
|
|
|
FullName() string
|
2017-09-26 11:29:22 +03:00
|
|
|
Args() []interface{}
|
2020-02-14 15:30:07 +03:00
|
|
|
String() string
|
2017-09-26 11:29:22 +03:00
|
|
|
stringArg(int) string
|
2020-09-23 10:29:13 +03:00
|
|
|
firstKeyPos() int8
|
2022-01-11 09:47:55 +03:00
|
|
|
SetFirstKeyPos(int8)
|
2016-06-17 15:09:38 +03:00
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
readTimeout() *time.Duration
|
2019-08-24 11:55:13 +03:00
|
|
|
readReply(rd *proto.Reader) error
|
2013-09-29 12:06:49 +04:00
|
|
|
|
2020-02-03 12:53:47 +03:00
|
|
|
SetErr(error)
|
2013-09-29 12:06:49 +04:00
|
|
|
Err() error
|
|
|
|
}
|
|
|
|
|
2013-09-29 13:41:04 +04:00
|
|
|
func setCmdsErr(cmds []Cmder, e error) {
|
|
|
|
for _, cmd := range cmds {
|
2017-08-31 15:22:47 +03:00
|
|
|
if cmd.Err() == nil {
|
2020-02-03 12:53:47 +03:00
|
|
|
cmd.SetErr(e)
|
2017-08-31 15:22:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-12 11:11:01 +03:00
|
|
|
func cmdsFirstErr(cmds []Cmder) error {
|
2017-08-31 15:22:47 +03:00
|
|
|
for _, cmd := range cmds {
|
|
|
|
if err := cmd.Err(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2013-09-29 13:41:04 +04:00
|
|
|
}
|
2017-08-31 15:22:47 +03:00
|
|
|
return nil
|
2013-09-29 13:41:04 +04:00
|
|
|
}
|
|
|
|
|
2020-02-14 13:44:03 +03:00
|
|
|
func writeCmds(wr *proto.Writer, cmds []Cmder) error {
|
2016-03-12 11:52:13 +03:00
|
|
|
for _, cmd := range cmds {
|
2020-02-14 13:44:03 +03:00
|
|
|
if err := writeCmd(wr, cmd); err != nil {
|
2016-03-12 11:52:13 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-08-15 11:53:15 +03:00
|
|
|
return nil
|
2016-03-12 11:52:13 +03:00
|
|
|
}
|
|
|
|
|
2020-02-14 13:44:03 +03:00
|
|
|
func writeCmd(wr *proto.Writer, cmd Cmder) error {
|
|
|
|
return wr.WriteArgs(cmd.Args())
|
|
|
|
}
|
|
|
|
|
2016-10-09 13:30:45 +03:00
|
|
|
func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
|
2020-09-23 10:29:13 +03:00
|
|
|
if pos := cmd.firstKeyPos(); pos != 0 {
|
|
|
|
return int(pos)
|
|
|
|
}
|
|
|
|
|
2017-05-09 12:44:36 +03:00
|
|
|
switch cmd.Name() {
|
2022-09-24 06:28:14 +03:00
|
|
|
case "eval", "evalsha", "eval_ro", "evalsha_ro":
|
2017-09-26 11:29:22 +03:00
|
|
|
if cmd.stringArg(2) != "0" {
|
2016-10-09 13:30:45 +03:00
|
|
|
return 3
|
|
|
|
}
|
2018-01-24 21:38:47 +03:00
|
|
|
|
|
|
|
return 0
|
2017-04-12 13:00:20 +03:00
|
|
|
case "publish":
|
|
|
|
return 1
|
2020-07-09 10:25:06 +03:00
|
|
|
case "memory":
|
2020-07-09 11:55:32 +03:00
|
|
|
// https://github.com/redis/redis/issues/7493
|
|
|
|
if cmd.stringArg(1) == "usage" {
|
|
|
|
return 2
|
|
|
|
}
|
2016-10-09 13:30:45 +03:00
|
|
|
}
|
2020-07-09 10:25:06 +03:00
|
|
|
|
2020-09-23 10:29:13 +03:00
|
|
|
if info != nil {
|
|
|
|
return int(info.FirstKeyPos)
|
2016-10-09 13:30:45 +03:00
|
|
|
}
|
2022-06-04 16:07:28 +03:00
|
|
|
return 1
|
2016-10-09 13:30:45 +03:00
|
|
|
}
|
|
|
|
|
2020-05-09 17:30:16 +03:00
|
|
|
func cmdString(cmd Cmder, val interface{}) string {
|
2020-06-09 16:29:53 +03:00
|
|
|
b := make([]byte, 0, 64)
|
2020-05-09 17:30:16 +03:00
|
|
|
|
|
|
|
for i, arg := range cmd.Args() {
|
|
|
|
if i > 0 {
|
|
|
|
b = append(b, ' ')
|
|
|
|
}
|
2020-06-09 16:29:53 +03:00
|
|
|
b = internal.AppendArg(b, arg)
|
2020-05-09 17:30:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := cmd.Err(); err != nil {
|
|
|
|
b = append(b, ": "...)
|
|
|
|
b = append(b, err.Error()...)
|
|
|
|
} else if val != nil {
|
|
|
|
b = append(b, ": "...)
|
2020-06-09 16:29:53 +03:00
|
|
|
b = internal.AppendArg(b, val)
|
2020-05-09 17:30:16 +03:00
|
|
|
}
|
|
|
|
|
2022-08-01 19:05:40 +03:00
|
|
|
return util.BytesToString(b)
|
2020-05-09 17:30:16 +03:00
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type baseCmd struct {
|
2020-09-23 10:29:13 +03:00
|
|
|
ctx context.Context
|
|
|
|
args []interface{}
|
|
|
|
err error
|
|
|
|
keyPos int8
|
2013-09-29 12:06:49 +04:00
|
|
|
|
2016-03-08 18:18:52 +03:00
|
|
|
_readTimeout *time.Duration
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*Cmd)(nil)
|
|
|
|
|
2019-05-31 16:36:57 +03:00
|
|
|
func (cmd *baseCmd) Name() string {
|
2019-08-24 11:55:13 +03:00
|
|
|
if len(cmd.args) == 0 {
|
2019-08-12 14:53:00 +03:00
|
|
|
return ""
|
2019-05-31 16:36:57 +03:00
|
|
|
}
|
2019-08-12 14:53:00 +03:00
|
|
|
// Cmd name must be lower cased.
|
|
|
|
return internal.ToLower(cmd.stringArg(0))
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2020-05-09 17:34:50 +03:00
|
|
|
func (cmd *baseCmd) FullName() string {
|
|
|
|
switch name := cmd.Name(); name {
|
|
|
|
case "cluster", "command":
|
|
|
|
if len(cmd.args) == 1 {
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
if s2, ok := cmd.args[1].(string); ok {
|
|
|
|
return name + " " + s2
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
default:
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
func (cmd *baseCmd) Args() []interface{} {
|
2019-08-24 11:55:13 +03:00
|
|
|
return cmd.args
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
func (cmd *baseCmd) stringArg(pos int) string {
|
2019-08-24 11:55:13 +03:00
|
|
|
if pos < 0 || pos >= len(cmd.args) {
|
2016-10-09 13:30:45 +03:00
|
|
|
return ""
|
2016-05-06 21:12:31 +03:00
|
|
|
}
|
2022-02-18 06:36:04 +03:00
|
|
|
arg := cmd.args[pos]
|
|
|
|
switch v := arg.(type) {
|
|
|
|
case string:
|
|
|
|
return v
|
|
|
|
default:
|
2022-02-18 10:45:35 +03:00
|
|
|
// TODO: consider using appendArg
|
|
|
|
return fmt.Sprint(v)
|
2022-02-18 06:36:04 +03:00
|
|
|
}
|
2016-05-06 21:12:31 +03:00
|
|
|
}
|
|
|
|
|
2020-09-23 10:29:13 +03:00
|
|
|
func (cmd *baseCmd) firstKeyPos() int8 {
|
2020-09-23 10:22:11 +03:00
|
|
|
return cmd.keyPos
|
|
|
|
}
|
|
|
|
|
2022-01-11 09:47:55 +03:00
|
|
|
func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) {
|
2020-09-23 10:29:13 +03:00
|
|
|
cmd.keyPos = keyPos
|
2020-09-23 10:22:11 +03:00
|
|
|
}
|
|
|
|
|
2020-02-03 12:53:47 +03:00
|
|
|
func (cmd *baseCmd) SetErr(e error) {
|
2019-08-08 16:54:38 +03:00
|
|
|
cmd.err = e
|
|
|
|
}
|
|
|
|
|
2019-05-31 16:36:57 +03:00
|
|
|
func (cmd *baseCmd) Err() error {
|
|
|
|
return cmd.err
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
func (cmd *baseCmd) readTimeout() *time.Duration {
|
|
|
|
return cmd._readTimeout
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *baseCmd) setReadTimeout(d time.Duration) {
|
|
|
|
cmd._readTimeout = &d
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type Cmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val interface{}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
|
2016-06-17 15:09:38 +03:00
|
|
|
return &Cmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2016-06-17 15:09:38 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:30:07 +03:00
|
|
|
func (cmd *Cmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *Cmd) SetVal(val interface{}) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
func (cmd *Cmd) Val() interface{} {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *Cmd) Result() (interface{}, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:30:07 +03:00
|
|
|
func (cmd *Cmd) Text() (string, error) {
|
2018-08-12 11:11:01 +03:00
|
|
|
if cmd.err != nil {
|
|
|
|
return "", cmd.err
|
|
|
|
}
|
2021-09-27 11:11:05 +03:00
|
|
|
return toString(cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toString(val interface{}) (string, error) {
|
|
|
|
switch val := val.(type) {
|
2018-08-12 11:11:01 +03:00
|
|
|
case string:
|
|
|
|
return val, nil
|
|
|
|
default:
|
|
|
|
err := fmt.Errorf("redis: unexpected type=%T for String", val)
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-21 14:11:19 +03:00
|
|
|
func (cmd *Cmd) Int() (int, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
|
|
|
switch val := cmd.val.(type) {
|
|
|
|
case int64:
|
|
|
|
return int(val), nil
|
|
|
|
case string:
|
|
|
|
return strconv.Atoi(val)
|
|
|
|
default:
|
2018-08-27 08:29:25 +03:00
|
|
|
err := fmt.Errorf("redis: unexpected type=%T for Int", val)
|
2018-08-21 14:11:19 +03:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-12 11:11:01 +03:00
|
|
|
func (cmd *Cmd) Int64() (int64, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
2021-09-27 11:11:05 +03:00
|
|
|
return toInt64(cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toInt64(val interface{}) (int64, error) {
|
|
|
|
switch val := val.(type) {
|
2018-08-12 11:11:01 +03:00
|
|
|
case int64:
|
|
|
|
return val, nil
|
|
|
|
case string:
|
|
|
|
return strconv.ParseInt(val, 10, 64)
|
|
|
|
default:
|
|
|
|
err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *Cmd) Uint64() (uint64, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
2021-09-27 11:11:05 +03:00
|
|
|
return toUint64(cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toUint64(val interface{}) (uint64, error) {
|
|
|
|
switch val := val.(type) {
|
2018-08-12 11:11:01 +03:00
|
|
|
case int64:
|
|
|
|
return uint64(val), nil
|
|
|
|
case string:
|
|
|
|
return strconv.ParseUint(val, 10, 64)
|
|
|
|
default:
|
|
|
|
err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-10 15:27:06 +03:00
|
|
|
func (cmd *Cmd) Float32() (float32, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
2021-09-27 11:11:05 +03:00
|
|
|
return toFloat32(cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toFloat32(val interface{}) (float32, error) {
|
|
|
|
switch val := val.(type) {
|
2019-04-10 15:27:06 +03:00
|
|
|
case int64:
|
|
|
|
return float32(val), nil
|
|
|
|
case string:
|
|
|
|
f, err := strconv.ParseFloat(val, 32)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return float32(f), nil
|
|
|
|
default:
|
|
|
|
err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-12 11:11:01 +03:00
|
|
|
func (cmd *Cmd) Float64() (float64, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
2021-09-27 11:11:05 +03:00
|
|
|
return toFloat64(cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toFloat64(val interface{}) (float64, error) {
|
|
|
|
switch val := val.(type) {
|
2018-08-12 11:11:01 +03:00
|
|
|
case int64:
|
|
|
|
return float64(val), nil
|
|
|
|
case string:
|
|
|
|
return strconv.ParseFloat(val, 64)
|
|
|
|
default:
|
|
|
|
err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *Cmd) Bool() (bool, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return false, cmd.err
|
|
|
|
}
|
2021-09-27 11:11:05 +03:00
|
|
|
return toBool(cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func toBool(val interface{}) (bool, error) {
|
|
|
|
switch val := val.(type) {
|
2018-08-12 11:11:01 +03:00
|
|
|
case int64:
|
|
|
|
return val != 0, nil
|
|
|
|
case string:
|
|
|
|
return strconv.ParseBool(val)
|
|
|
|
default:
|
|
|
|
err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
|
|
|
|
return false, err
|
|
|
|
}
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2021-08-13 10:37:54 +03:00
|
|
|
func (cmd *Cmd) Slice() ([]interface{}, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return nil, cmd.err
|
|
|
|
}
|
|
|
|
switch val := cmd.val.(type) {
|
|
|
|
case []interface{}:
|
|
|
|
return val, nil
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("redis: unexpected type=%T for Slice", val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-27 11:11:05 +03:00
|
|
|
func (cmd *Cmd) StringSlice() ([]string, error) {
|
|
|
|
slice, err := cmd.Slice()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ss := make([]string, len(slice))
|
|
|
|
for i, iface := range slice {
|
|
|
|
val, err := toString(iface)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
ss[i] = val
|
|
|
|
}
|
|
|
|
return ss, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *Cmd) Int64Slice() ([]int64, error) {
|
|
|
|
slice, err := cmd.Slice()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nums := make([]int64, len(slice))
|
|
|
|
for i, iface := range slice {
|
|
|
|
val, err := toInt64(iface)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
nums[i] = val
|
|
|
|
}
|
|
|
|
return nums, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *Cmd) Uint64Slice() ([]uint64, error) {
|
|
|
|
slice, err := cmd.Slice()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
nums := make([]uint64, len(slice))
|
|
|
|
for i, iface := range slice {
|
|
|
|
val, err := toUint64(iface)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
nums[i] = val
|
|
|
|
}
|
|
|
|
return nums, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *Cmd) Float32Slice() ([]float32, error) {
|
|
|
|
slice, err := cmd.Slice()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
floats := make([]float32, len(slice))
|
|
|
|
for i, iface := range slice {
|
|
|
|
val, err := toFloat32(iface)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
floats[i] = val
|
|
|
|
}
|
|
|
|
return floats, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *Cmd) Float64Slice() ([]float64, error) {
|
|
|
|
slice, err := cmd.Slice()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
floats := make([]float64, len(slice))
|
|
|
|
for i, iface := range slice {
|
|
|
|
val, err := toFloat64(iface)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
floats[i] = val
|
|
|
|
}
|
|
|
|
return floats, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *Cmd) BoolSlice() ([]bool, error) {
|
|
|
|
slice, err := cmd.Slice()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
bools := make([]bool, len(slice))
|
|
|
|
for i, iface := range slice {
|
|
|
|
val, err := toBool(iface)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
bools[i] = val
|
|
|
|
}
|
|
|
|
return bools, nil
|
|
|
|
}
|
|
|
|
|
2020-09-17 12:27:16 +03:00
|
|
|
func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val, err = rd.ReadReply()
|
2020-09-17 12:27:16 +03:00
|
|
|
return err
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type SliceCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val []interface{}
|
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*SliceCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &SliceCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *SliceCmd) SetVal(val []interface{}) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *SliceCmd) Val() []interface{} {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *SliceCmd) Result() ([]interface{}, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *SliceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2021-02-02 13:58:10 +03:00
|
|
|
// Scan scans the results from the map into a destination struct. The map keys
|
|
|
|
// are matched in the Redis struct fields by the `redis:"field"` tag.
|
2021-02-03 13:45:02 +03:00
|
|
|
func (cmd *SliceCmd) Scan(dst interface{}) error {
|
2021-02-03 11:07:27 +03:00
|
|
|
if cmd.err != nil {
|
|
|
|
return cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass the list of keys and values.
|
|
|
|
// Skip the first two args for: HMGET key
|
|
|
|
var args []interface{}
|
|
|
|
if cmd.args[0] == "hmget" {
|
|
|
|
args = cmd.args[2:]
|
|
|
|
} else {
|
|
|
|
// Otherwise, it's: MGET field field ...
|
|
|
|
args = cmd.args[1:]
|
|
|
|
}
|
|
|
|
|
2021-02-03 13:45:02 +03:00
|
|
|
return hscan.Scan(dst, args, cmd.val)
|
2021-02-02 10:34:52 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *SliceCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
cmd.val, err = rd.ReadSlice()
|
|
|
|
return err
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type StatusCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val string
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*StatusCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &StatusCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2015-01-24 15:12:48 +03:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *StatusCmd) SetVal(val string) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
func (cmd *StatusCmd) Val() string {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *StatusCmd) Result() (string, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *StatusCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2020-09-17 12:27:16 +03:00
|
|
|
func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
cmd.val, err = rd.ReadString()
|
|
|
|
return err
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type IntCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val int64
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*IntCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &IntCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *IntCmd) SetVal(val int64) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
func (cmd *IntCmd) Val() int64 {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *IntCmd) Result() (int64, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2019-09-27 14:38:55 +03:00
|
|
|
func (cmd *IntCmd) Uint64() (uint64, error) {
|
|
|
|
return uint64(cmd.val), cmd.err
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *IntCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2020-09-17 12:27:16 +03:00
|
|
|
func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val, err = rd.ReadInt()
|
2020-09-17 12:27:16 +03:00
|
|
|
return err
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2019-06-26 14:45:38 +03:00
|
|
|
type IntSliceCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []int64
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*IntSliceCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd {
|
2019-06-26 14:45:38 +03:00
|
|
|
return &IntSliceCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *IntSliceCmd) SetVal(val []int64) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2019-06-26 14:45:38 +03:00
|
|
|
func (cmd *IntSliceCmd) Val() []int64 {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *IntSliceCmd) Result() ([]int64, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *IntSliceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]int64, n)
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if cmd.val[i], err = rd.ReadInt(); err != nil {
|
|
|
|
return err
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
|
|
|
return nil
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2013-10-15 17:47:12 +04:00
|
|
|
type DurationCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val time.Duration
|
2013-10-15 17:47:12 +04:00
|
|
|
precision time.Duration
|
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*DurationCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd {
|
2013-10-15 17:47:12 +04:00
|
|
|
return &DurationCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2013-10-15 17:47:12 +04:00
|
|
|
precision: precision,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *DurationCmd) SetVal(val time.Duration) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *DurationCmd) Val() time.Duration {
|
|
|
|
return cmd.val
|
2013-10-15 17:47:12 +04:00
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *DurationCmd) Result() (time.Duration, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *DurationCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadInt()
|
2020-09-17 12:27:16 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2013-10-15 17:47:12 +04:00
|
|
|
}
|
2019-05-31 13:16:10 +03:00
|
|
|
switch n {
|
|
|
|
// -2 if the key does not exist
|
|
|
|
// -1 if the key exists but has no associated expire
|
|
|
|
case -2, -1:
|
|
|
|
cmd.val = time.Duration(n)
|
|
|
|
default:
|
|
|
|
cmd.val = time.Duration(n) * cmd.precision
|
|
|
|
}
|
2014-01-09 12:17:38 +04:00
|
|
|
return nil
|
2013-10-15 17:47:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2016-10-14 14:39:02 +03:00
|
|
|
type TimeCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val time.Time
|
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*TimeCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
|
2016-10-14 14:39:02 +03:00
|
|
|
return &TimeCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2016-10-14 14:39:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *TimeCmd) SetVal(val time.Time) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2016-10-14 14:39:02 +03:00
|
|
|
func (cmd *TimeCmd) Val() time.Time {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *TimeCmd) Result() (time.Time, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *TimeCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
if err := rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
second, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
microsecond, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = time.Unix(second, microsecond*1000)
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2016-10-14 14:39:02 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
type BoolCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val bool
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*BoolCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &BoolCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *BoolCmd) SetVal(val bool) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *BoolCmd) Val() bool {
|
|
|
|
return cmd.val
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *BoolCmd) Result() (bool, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *BoolCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *BoolCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
cmd.val, err = rd.ReadBool()
|
|
|
|
|
2015-10-07 17:56:49 +03:00
|
|
|
// `SET key value NX` returns nil when key already exists. But
|
|
|
|
// `SETNX key value` returns bool (0/1). So convert nil to bool.
|
2020-09-17 12:27:16 +03:00
|
|
|
if err == Nil {
|
2015-01-31 12:08:56 +03:00
|
|
|
cmd.val = false
|
2021-04-27 10:04:46 +03:00
|
|
|
err = nil
|
2015-01-31 12:08:56 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type StringCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
2018-08-16 13:25:19 +03:00
|
|
|
val string
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*StringCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &StringCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *StringCmd) SetVal(val string) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
func (cmd *StringCmd) Val() string {
|
2018-08-16 13:25:19 +03:00
|
|
|
return cmd.val
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *StringCmd) Result() (string, error) {
|
2015-05-28 15:51:19 +03:00
|
|
|
return cmd.Val(), cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *StringCmd) Bytes() ([]byte, error) {
|
2019-07-27 16:40:31 +03:00
|
|
|
return util.StringToBytes(cmd.val), cmd.err
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2021-03-17 10:50:02 +03:00
|
|
|
func (cmd *StringCmd) Bool() (bool, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return false, cmd.err
|
|
|
|
}
|
|
|
|
return strconv.ParseBool(cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-21 14:11:19 +03:00
|
|
|
func (cmd *StringCmd) Int() (int, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
|
|
|
return strconv.Atoi(cmd.Val())
|
|
|
|
}
|
|
|
|
|
2014-07-31 16:18:23 +04:00
|
|
|
func (cmd *StringCmd) Int64() (int64, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
2015-05-28 15:51:19 +03:00
|
|
|
return strconv.ParseInt(cmd.Val(), 10, 64)
|
2014-07-31 16:18:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *StringCmd) Uint64() (uint64, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
2015-05-28 15:51:19 +03:00
|
|
|
return strconv.ParseUint(cmd.Val(), 10, 64)
|
2014-07-31 16:18:23 +04:00
|
|
|
}
|
|
|
|
|
2019-04-10 15:27:06 +03:00
|
|
|
func (cmd *StringCmd) Float32() (float32, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
|
|
|
f, err := strconv.ParseFloat(cmd.Val(), 32)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return float32(f), nil
|
|
|
|
}
|
|
|
|
|
2014-07-31 16:18:23 +04:00
|
|
|
func (cmd *StringCmd) Float64() (float64, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return 0, cmd.err
|
|
|
|
}
|
2015-05-28 15:51:19 +03:00
|
|
|
return strconv.ParseFloat(cmd.Val(), 64)
|
|
|
|
}
|
|
|
|
|
2019-07-25 12:21:12 +03:00
|
|
|
func (cmd *StringCmd) Time() (time.Time, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return time.Time{}, cmd.err
|
|
|
|
}
|
2020-03-12 18:33:50 +03:00
|
|
|
return time.Parse(time.RFC3339Nano, cmd.Val())
|
2019-07-25 12:21:12 +03:00
|
|
|
}
|
|
|
|
|
2015-05-28 15:51:19 +03:00
|
|
|
func (cmd *StringCmd) Scan(val interface{}) error {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return cmd.err
|
|
|
|
}
|
2018-08-16 13:25:19 +03:00
|
|
|
return proto.Scan([]byte(cmd.val), val)
|
2014-07-31 16:18:23 +04:00
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *StringCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2020-09-17 12:27:16 +03:00
|
|
|
func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
cmd.val, err = rd.ReadString()
|
|
|
|
return err
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type FloatCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val float64
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*FloatCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &FloatCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *FloatCmd) SetVal(val float64) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
func (cmd *FloatCmd) Val() float64 {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmd.val
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2015-08-29 13:08:27 +03:00
|
|
|
func (cmd *FloatCmd) Result() (float64, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *FloatCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2020-09-17 12:27:16 +03:00
|
|
|
func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val, err = rd.ReadFloat()
|
2020-09-17 12:27:16 +03:00
|
|
|
return err
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2021-03-05 21:02:53 +03:00
|
|
|
type FloatSliceCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []float64
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*FloatSliceCmd)(nil)
|
|
|
|
|
|
|
|
func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSliceCmd {
|
|
|
|
return &FloatSliceCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *FloatSliceCmd) SetVal(val []float64) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2021-03-05 21:02:53 +03:00
|
|
|
func (cmd *FloatSliceCmd) Val() []float64 {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FloatSliceCmd) Result() ([]float64, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FloatSliceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = make([]float64, n)
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
switch num, err := rd.ReadFloat(); {
|
|
|
|
case err == Nil:
|
|
|
|
cmd.val[i] = 0
|
|
|
|
case err != nil:
|
|
|
|
return err
|
|
|
|
default:
|
|
|
|
cmd.val[i] = num
|
2021-03-05 21:02:53 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
|
|
|
return nil
|
2021-03-05 21:02:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
type StringSliceCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val []string
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*StringSliceCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &StringSliceCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *StringSliceCmd) SetVal(val []string) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *StringSliceCmd) Val() []string {
|
|
|
|
return cmd.val
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2014-01-09 12:31:43 +04:00
|
|
|
func (cmd *StringSliceCmd) Result() ([]string, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *StringSliceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2017-02-01 11:36:33 +03:00
|
|
|
func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
|
|
|
|
return proto.ScanSlice(cmd.Val(), container)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]string, n)
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
switch s, err := rd.ReadString(); {
|
|
|
|
case err == Nil:
|
|
|
|
cmd.val[i] = ""
|
|
|
|
case err != nil:
|
|
|
|
return err
|
|
|
|
default:
|
|
|
|
cmd.val[i] = s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type KeyValue struct {
|
|
|
|
Key string
|
|
|
|
Value string
|
|
|
|
}
|
|
|
|
|
|
|
|
type KeyValueSliceCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []KeyValue
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*KeyValueSliceCmd)(nil)
|
|
|
|
|
|
|
|
func NewKeyValueSliceCmd(ctx context.Context, args ...interface{}) *KeyValueSliceCmd {
|
|
|
|
return &KeyValueSliceCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 07:06:04 +03:00
|
|
|
func (cmd *KeyValueSliceCmd) SetVal(val []KeyValue) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *KeyValueSliceCmd) Val() []KeyValue {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *KeyValueSliceCmd) Result() ([]KeyValue, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *KeyValueSliceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Many commands will respond to two formats:
|
2023-01-07 11:30:56 +03:00
|
|
|
// 1. 1) "one"
|
|
|
|
// 2. (double) 1
|
|
|
|
// 2. 1) "two"
|
|
|
|
// 2. (double) 2
|
|
|
|
//
|
2021-04-27 10:04:46 +03:00
|
|
|
// OR:
|
2023-01-07 11:30:56 +03:00
|
|
|
// 1. "two"
|
|
|
|
// 2. (double) 2
|
|
|
|
// 3. "one"
|
|
|
|
// 4. (double) 1
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *KeyValueSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the n is 0, can't continue reading.
|
|
|
|
if n == 0 {
|
|
|
|
cmd.val = make([]KeyValue, 0)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
typ, err := rd.PeekReplyType()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
array := typ == proto.RespArray
|
|
|
|
|
|
|
|
if array {
|
|
|
|
cmd.val = make([]KeyValue, n)
|
|
|
|
} else {
|
|
|
|
cmd.val = make([]KeyValue, n/2)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if array {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
|
|
|
|
if cmd.val[i].Key, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cmd.val[i].Value, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type BoolSliceCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val []bool
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*BoolSliceCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &BoolSliceCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *BoolSliceCmd) SetVal(val []bool) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *BoolSliceCmd) Val() []bool {
|
|
|
|
return cmd.val
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
func (cmd *BoolSliceCmd) Result() ([]bool, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *BoolSliceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]bool, n)
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if cmd.val[i], err = rd.ReadBool(); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
type MapStringStringCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
|
|
|
val map[string]string
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
var _ Cmder = (*MapStringStringCmd)(nil)
|
2017-09-26 11:29:22 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func NewMapStringStringCmd(ctx context.Context, args ...interface{}) *MapStringStringCmd {
|
|
|
|
return &MapStringStringCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *MapStringStringCmd) Val() map[string]string {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmd.val
|
2021-09-25 18:12:26 +03:00
|
|
|
}
|
|
|
|
|
chore: sync master (#2051)
* Upgrade redis-server version (#1833)
* Upgrade redis-server version
Signed-off-by: monkey <golang@88.com>
* XAutoClaim changed the return value
Signed-off-by: monkey <golang@88.com>
* add cmd: geosearch, geosearchstore (#1836)
* add cmd: geosearch, geosearchstore
Signed-off-by: monkey92t <golang@88.com>
* GeoSearchQuery and GeoSearchLocationQuery changed to pointer passing
Signed-off-by: monkey92t <golang@88.com>
* Added missing method XInfoStreamFull to Cmdable interface
* Run go mod tidy in redisotel
Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
* Revert "ConnPool check fd for bad conns (#1824)" (#1849)
This reverts commit 346bfafddd36dd52d51b064033048de5552ee91e.
* Automate release process (#1852)
* Bump github.com/onsi/gomega from 1.10.5 to 1.14.0 (#1832)
* Bump github.com/onsi/gomega from 1.10.5 to 1.14.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.10.5 to 1.14.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.10.5...v1.14.0)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* Upgrade gomega to v1.15.0
Signed-off-by: monkey92t <golang@88.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: monkey92t <golang@88.com>
* Add version.go
* Fix otel example
* Fix package name in release script
* More fixes for otel example
* And more
* Fix release.sh
* Release v8.11.3 (release.sh)
* Create an annotated tag to give release.yml chance to run
* Tweak tag.sh
* Add Cmd.Slice helper to cast to []interface{} (#1859)
* after the connection pool is closed, no new connections should be added (#1863)
* after the connection pool is closed, no new connections should be added
Signed-off-by: monkey92t <golang@88.com>
* remove runGoroutine
Signed-off-by: monkey92t <golang@88.com>
* pool.popIdle add p.closed check
Signed-off-by: monkey92t <golang@88.com>
* upgrade golangci-lint v1.42.0
Signed-off-by: monkey92t <golang@88.com>
* Bump github.com/onsi/gomega from 1.15.0 to 1.16.0 (#1865)
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.15.0...v1.16.0)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add go 1.17 to the build matrix
* Remove go 1.15 from build matrix
* Add scan struct example (#1870)
* Replace release job
* Bump github.com/cespare/xxhash/v2 from 2.1.1 to 2.1.2 (#1872)
Bumps [github.com/cespare/xxhash/v2](https://github.com/cespare/xxhash) from 2.1.1 to 2.1.2.
- [Release notes](https://github.com/cespare/xxhash/releases)
- [Commits](https://github.com/cespare/xxhash/compare/v2.1.1...v2.1.2)
---
updated-dependencies:
- dependency-name: github.com/cespare/xxhash/v2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Fix tag script to push tag by tag
* Fix releasing.md
* Fix/pubsub ping mutex (#1878)
* Fix PubSub.Ping to hold the lock
* Fix PubSub.Ping to hold the lock
* add write cmd data-race test
Signed-off-by: monkey92t <golang@88.com>
Co-authored-by: monkey92t <golang@88.com>
* chore: cleanup OpenTelemetry example
* chore: gofmt all code
* Refactor TestParseURL
This is in preparation for supporting query parameters
in ParseURL:
- use an expected *Options instance to execute assertions on
- extract assertions into helper function
- enable parallel testing
- condense test table
* Add query parameter parsing to ParseURL()
Before this change, ParseURL would only accept a very restricted
set of URLs (it returned an error, if it encountered any parameter).
This commit introduces the ability to process URLs like
redis://localhost/1?dial_timeout=10s
and similar.
Go programs which were providing a configuration tunable (e.g.
CLI flag, config entry or environment variable) to configure
the Redis connection now don't need to perform this task
themselves.
* chore: add links to readme
* chore: fix discussions link
* empty hooks.withContext removed
* chore: gofmt
* chore: use conventional commits and auto-generate changelog
* feat: add acl auth support for sentinels
* chore: swap to acl auth at the test-level
* Add support for BLMove command
* chore: update dependencies
* chore: update link
* feat: add SetVal method for each command
* feat: add Cmd.{String,Int,Float,Bool}Slice helpers and an example
* chore: tweak GH actions to run all jobs
* chore: add Lua scripting example
* Fix Redis Cluster issue during roll outs of new nodes with same addr (#1914)
* fix: recycle connections in some Redis Cluster scenarios
This issue was surfaced in a Cloud Provider solution that used for
rolling out new nodes using the same address (hostname) of the nodes
that will be replaced in a Redis Cluster, while the former ones once
depromoted as Slaves would continue in service during some mintues
for redirecting traffic.
The solution basically identifies when the connection could be stale
since a MOVED response will be returned using the same address (hostname)
that is being used by the connection. At that moment we consider the
connection as no longer usable forcing to recycle the connection.
* chore: lazy reload when moved or ask
* chore: use conv commit message
* chore: release v8.11.4 (release.sh)
* fix: add whitespace for avoid unlikely colisions
* fix: format
* chore: fix links
* chore: use ctx parameter in cmdInfo
* Bump github.com/onsi/ginkgo from 1.16.4 to 1.16.5 (#1925)
Bumps [github.com/onsi/ginkgo](https://github.com/onsi/ginkgo) from 1.16.4 to 1.16.5.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v1.16.4...v1.16.5)
---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat: add support for time.Duration write and scan
* test: add test case for setting and scanning durations
* chore: fix linter
* fix(extra/redisotel): set span.kind attribute to client
According to the opentelemetry specification this should always be set to client for database client
libraries.
I've also removed the SetAttributes call and instead set the attributes during creation of the span.
This is what the library SHOULD be doing according to the opentelemetry api specification.
* chore: update otel example
* fix: update some argument counts in pre-allocs
In some cases number of pre-allocated places in
argument array is missing 1 or 2 elements,
which results in re-allocation of twice as large array
* chore: add example how to delete keys without a ttl
* chore: don't enable all lints
* chore(deps): bump github.com/onsi/gomega from 1.16.0 to 1.17.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.16.0...v1.17.0)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* feat: Add redis v7's NX, XX, GT, LT expire variants
* chore: add missing readme
* chore: tweak feature links
* chore: remove Discord
* fix: set timeout for WAIT command. Fixes #1963
* build: update `go` directive in `go.mod` to 1.17
This commit enables support for module graph pruning and lazy module
loading for projects that are at Go 1.17 or higher.
Reference: https://go.dev/ref/mod#go-mod-file-go
Reference: https://go.dev/ref/mod#graph-pruning
Reference: https://go.dev/ref/mod#lazy-loading
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
* chore: update link
* chore: export cmder.SetFirstKeyPos to support build module commands
* feat(redisotel): ability to override TracerProvider (#1998)
* fix: add missing Expire methods to Cmdable
This is a followup to https://github.com/go-redis/redis/pull/1928
* chore(deps): bump github.com/onsi/gomega from 1.17.0 to 1.18.1
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.17.0 to 1.18.1.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.17.0...v1.18.1)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* Update README.md (#2011)
chore: add fmt library in example code
* chore: instrumentation name and version (#2012)
* fix: invalid type assert in stringArg
* chore: cleanup
* fix: example/otel compile error (#2028)
* fix: rename Golang to Go (#2030)
https://go.dev/doc/faq#go_or_golang
* feat: add support for passing extra attributes added to spans
* feat: set net.peer.name and net.peer.port in otel example
* chore: tweak Uptrace copy
* feat: add support for COPY command (#2016)
* feat: add support for acl sentinel auth in universal client
* chore(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
* chore: add hll example
* chore: tweak release script
* chore: release v8.11.5 (release.sh)
* chore: add discord back
Co-authored-by: Eugene Ponizovsky <ponizovsky@gmail.com>
Co-authored-by: Bogdan Drutu <bogdandrutu@gmail.com>
Co-authored-by: Vladimir Mihailenco <vladimir.webdev@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kishan B <kishancs46@gmail.com>
Co-authored-by: Dominik Menke <dom@digineo.de>
Co-authored-by: Gökhan Özeloğlu <gozeloglu@gmail.com>
Co-authored-by: Justin Sievenpiper <justin@sievenpiper.co>
Co-authored-by: Алексей Романовский <aromanovsky@epiphan.com>
Co-authored-by: Stavros Panakakakis <stavrospanakakis@gmail.com>
Co-authored-by: Pau Freixes <pfreixes@gmail.com>
Co-authored-by: Ethan Hur <ethan0311@gmail.com>
Co-authored-by: Jackie <18378976+Pyrodash@users.noreply.github.com>
Co-authored-by: Kristinn Björgvin Árdal <kristinnardalsecondary@gmail.com>
Co-authored-by: ffenix113 <razerer@bigmir.net>
Co-authored-by: Bastien Penavayre <bastienPenava@gmail.com>
Co-authored-by: James3 Li(李麒傑) <james3_li@asus.com>
Co-authored-by: Eng Zer Jun <engzerjun@gmail.com>
Co-authored-by: gzjiangtao2014 <gzjiangtao2014@corp.netease.com>
Co-authored-by: Nelz <nelz9999@users.noreply.github.com>
Co-authored-by: Daniel Richter <Nexyz9@gmail.com>
Co-authored-by: Seyed Ali Ghaffari <ali.ghaffari@outlook.com>
Co-authored-by: lintanghui <lintanghui@bilibili.com>
Co-authored-by: hidu <duv123+github@gmail.com>
Co-authored-by: Jonas Lergell <jonas.lergell@volvocars.com>
Co-authored-by: Alex Kahn <alexanderkahn@gmail.com>
2022-03-19 07:40:31 +03:00
|
|
|
func (cmd *MapStringStringCmd) SetVal(val map[string]string) {
|
|
|
|
cmd.val = val
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *MapStringStringCmd) Result() (map[string]string, error) {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *MapStringStringCmd) String() string {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2021-02-02 13:58:10 +03:00
|
|
|
// Scan scans the results from the map into a destination struct. The map keys
|
|
|
|
// are matched in the Redis struct fields by the `redis:"field"` tag.
|
chore: sync master (#2051)
* Upgrade redis-server version (#1833)
* Upgrade redis-server version
Signed-off-by: monkey <golang@88.com>
* XAutoClaim changed the return value
Signed-off-by: monkey <golang@88.com>
* add cmd: geosearch, geosearchstore (#1836)
* add cmd: geosearch, geosearchstore
Signed-off-by: monkey92t <golang@88.com>
* GeoSearchQuery and GeoSearchLocationQuery changed to pointer passing
Signed-off-by: monkey92t <golang@88.com>
* Added missing method XInfoStreamFull to Cmdable interface
* Run go mod tidy in redisotel
Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
* Revert "ConnPool check fd for bad conns (#1824)" (#1849)
This reverts commit 346bfafddd36dd52d51b064033048de5552ee91e.
* Automate release process (#1852)
* Bump github.com/onsi/gomega from 1.10.5 to 1.14.0 (#1832)
* Bump github.com/onsi/gomega from 1.10.5 to 1.14.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.10.5 to 1.14.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.10.5...v1.14.0)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* Upgrade gomega to v1.15.0
Signed-off-by: monkey92t <golang@88.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: monkey92t <golang@88.com>
* Add version.go
* Fix otel example
* Fix package name in release script
* More fixes for otel example
* And more
* Fix release.sh
* Release v8.11.3 (release.sh)
* Create an annotated tag to give release.yml chance to run
* Tweak tag.sh
* Add Cmd.Slice helper to cast to []interface{} (#1859)
* after the connection pool is closed, no new connections should be added (#1863)
* after the connection pool is closed, no new connections should be added
Signed-off-by: monkey92t <golang@88.com>
* remove runGoroutine
Signed-off-by: monkey92t <golang@88.com>
* pool.popIdle add p.closed check
Signed-off-by: monkey92t <golang@88.com>
* upgrade golangci-lint v1.42.0
Signed-off-by: monkey92t <golang@88.com>
* Bump github.com/onsi/gomega from 1.15.0 to 1.16.0 (#1865)
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.15.0...v1.16.0)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add go 1.17 to the build matrix
* Remove go 1.15 from build matrix
* Add scan struct example (#1870)
* Replace release job
* Bump github.com/cespare/xxhash/v2 from 2.1.1 to 2.1.2 (#1872)
Bumps [github.com/cespare/xxhash/v2](https://github.com/cespare/xxhash) from 2.1.1 to 2.1.2.
- [Release notes](https://github.com/cespare/xxhash/releases)
- [Commits](https://github.com/cespare/xxhash/compare/v2.1.1...v2.1.2)
---
updated-dependencies:
- dependency-name: github.com/cespare/xxhash/v2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Fix tag script to push tag by tag
* Fix releasing.md
* Fix/pubsub ping mutex (#1878)
* Fix PubSub.Ping to hold the lock
* Fix PubSub.Ping to hold the lock
* add write cmd data-race test
Signed-off-by: monkey92t <golang@88.com>
Co-authored-by: monkey92t <golang@88.com>
* chore: cleanup OpenTelemetry example
* chore: gofmt all code
* Refactor TestParseURL
This is in preparation for supporting query parameters
in ParseURL:
- use an expected *Options instance to execute assertions on
- extract assertions into helper function
- enable parallel testing
- condense test table
* Add query parameter parsing to ParseURL()
Before this change, ParseURL would only accept a very restricted
set of URLs (it returned an error, if it encountered any parameter).
This commit introduces the ability to process URLs like
redis://localhost/1?dial_timeout=10s
and similar.
Go programs which were providing a configuration tunable (e.g.
CLI flag, config entry or environment variable) to configure
the Redis connection now don't need to perform this task
themselves.
* chore: add links to readme
* chore: fix discussions link
* empty hooks.withContext removed
* chore: gofmt
* chore: use conventional commits and auto-generate changelog
* feat: add acl auth support for sentinels
* chore: swap to acl auth at the test-level
* Add support for BLMove command
* chore: update dependencies
* chore: update link
* feat: add SetVal method for each command
* feat: add Cmd.{String,Int,Float,Bool}Slice helpers and an example
* chore: tweak GH actions to run all jobs
* chore: add Lua scripting example
* Fix Redis Cluster issue during roll outs of new nodes with same addr (#1914)
* fix: recycle connections in some Redis Cluster scenarios
This issue was surfaced in a Cloud Provider solution that used for
rolling out new nodes using the same address (hostname) of the nodes
that will be replaced in a Redis Cluster, while the former ones once
depromoted as Slaves would continue in service during some mintues
for redirecting traffic.
The solution basically identifies when the connection could be stale
since a MOVED response will be returned using the same address (hostname)
that is being used by the connection. At that moment we consider the
connection as no longer usable forcing to recycle the connection.
* chore: lazy reload when moved or ask
* chore: use conv commit message
* chore: release v8.11.4 (release.sh)
* fix: add whitespace for avoid unlikely colisions
* fix: format
* chore: fix links
* chore: use ctx parameter in cmdInfo
* Bump github.com/onsi/ginkgo from 1.16.4 to 1.16.5 (#1925)
Bumps [github.com/onsi/ginkgo](https://github.com/onsi/ginkgo) from 1.16.4 to 1.16.5.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v1.16.4...v1.16.5)
---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat: add support for time.Duration write and scan
* test: add test case for setting and scanning durations
* chore: fix linter
* fix(extra/redisotel): set span.kind attribute to client
According to the opentelemetry specification this should always be set to client for database client
libraries.
I've also removed the SetAttributes call and instead set the attributes during creation of the span.
This is what the library SHOULD be doing according to the opentelemetry api specification.
* chore: update otel example
* fix: update some argument counts in pre-allocs
In some cases number of pre-allocated places in
argument array is missing 1 or 2 elements,
which results in re-allocation of twice as large array
* chore: add example how to delete keys without a ttl
* chore: don't enable all lints
* chore(deps): bump github.com/onsi/gomega from 1.16.0 to 1.17.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.16.0...v1.17.0)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* feat: Add redis v7's NX, XX, GT, LT expire variants
* chore: add missing readme
* chore: tweak feature links
* chore: remove Discord
* fix: set timeout for WAIT command. Fixes #1963
* build: update `go` directive in `go.mod` to 1.17
This commit enables support for module graph pruning and lazy module
loading for projects that are at Go 1.17 or higher.
Reference: https://go.dev/ref/mod#go-mod-file-go
Reference: https://go.dev/ref/mod#graph-pruning
Reference: https://go.dev/ref/mod#lazy-loading
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
* chore: update link
* chore: export cmder.SetFirstKeyPos to support build module commands
* feat(redisotel): ability to override TracerProvider (#1998)
* fix: add missing Expire methods to Cmdable
This is a followup to https://github.com/go-redis/redis/pull/1928
* chore(deps): bump github.com/onsi/gomega from 1.17.0 to 1.18.1
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.17.0 to 1.18.1.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.17.0...v1.18.1)
---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* Update README.md (#2011)
chore: add fmt library in example code
* chore: instrumentation name and version (#2012)
* fix: invalid type assert in stringArg
* chore: cleanup
* fix: example/otel compile error (#2028)
* fix: rename Golang to Go (#2030)
https://go.dev/doc/faq#go_or_golang
* feat: add support for passing extra attributes added to spans
* feat: set net.peer.name and net.peer.port in otel example
* chore: tweak Uptrace copy
* feat: add support for COPY command (#2016)
* feat: add support for acl sentinel auth in universal client
* chore(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
* chore: add hll example
* chore: tweak release script
* chore: release v8.11.5 (release.sh)
* chore: add discord back
Co-authored-by: Eugene Ponizovsky <ponizovsky@gmail.com>
Co-authored-by: Bogdan Drutu <bogdandrutu@gmail.com>
Co-authored-by: Vladimir Mihailenco <vladimir.webdev@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kishan B <kishancs46@gmail.com>
Co-authored-by: Dominik Menke <dom@digineo.de>
Co-authored-by: Gökhan Özeloğlu <gozeloglu@gmail.com>
Co-authored-by: Justin Sievenpiper <justin@sievenpiper.co>
Co-authored-by: Алексей Романовский <aromanovsky@epiphan.com>
Co-authored-by: Stavros Panakakakis <stavrospanakakis@gmail.com>
Co-authored-by: Pau Freixes <pfreixes@gmail.com>
Co-authored-by: Ethan Hur <ethan0311@gmail.com>
Co-authored-by: Jackie <18378976+Pyrodash@users.noreply.github.com>
Co-authored-by: Kristinn Björgvin Árdal <kristinnardalsecondary@gmail.com>
Co-authored-by: ffenix113 <razerer@bigmir.net>
Co-authored-by: Bastien Penavayre <bastienPenava@gmail.com>
Co-authored-by: James3 Li(李麒傑) <james3_li@asus.com>
Co-authored-by: Eng Zer Jun <engzerjun@gmail.com>
Co-authored-by: gzjiangtao2014 <gzjiangtao2014@corp.netease.com>
Co-authored-by: Nelz <nelz9999@users.noreply.github.com>
Co-authored-by: Daniel Richter <Nexyz9@gmail.com>
Co-authored-by: Seyed Ali Ghaffari <ali.ghaffari@outlook.com>
Co-authored-by: lintanghui <lintanghui@bilibili.com>
Co-authored-by: hidu <duv123+github@gmail.com>
Co-authored-by: Jonas Lergell <jonas.lergell@volvocars.com>
Co-authored-by: Alex Kahn <alexanderkahn@gmail.com>
2022-03-19 07:40:31 +03:00
|
|
|
func (cmd *MapStringStringCmd) Scan(dest interface{}) error {
|
2021-02-03 11:07:27 +03:00
|
|
|
if cmd.err != nil {
|
|
|
|
return cmd.err
|
|
|
|
}
|
|
|
|
|
2021-08-29 19:37:17 +03:00
|
|
|
strct, err := hscan.Struct(dest)
|
2021-02-03 13:45:02 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-02 13:58:10 +03:00
|
|
|
for k, v := range cmd.val {
|
2021-02-03 13:45:02 +03:00
|
|
|
if err := strct.Scan(k, v); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-02 13:58:10 +03:00
|
|
|
}
|
|
|
|
|
2021-02-03 13:45:02 +03:00
|
|
|
return nil
|
2021-02-02 13:58:10 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *MapStringStringCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val = make(map[string]string, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
value, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
|
|
|
|
cmd.val[key] = value
|
|
|
|
}
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2013-09-29 12:06:49 +04:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
type MapStringIntCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2015-01-25 15:05:19 +03:00
|
|
|
|
|
|
|
val map[string]int64
|
|
|
|
}
|
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
var _ Cmder = (*MapStringIntCmd)(nil)
|
2017-09-26 11:29:22 +03:00
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
func NewMapStringIntCmd(ctx context.Context, args ...interface{}) *MapStringIntCmd {
|
|
|
|
return &MapStringIntCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2015-01-25 15:05:19 +03:00
|
|
|
}
|
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
func (cmd *MapStringIntCmd) SetVal(val map[string]int64) {
|
2021-09-25 18:12:26 +03:00
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
func (cmd *MapStringIntCmd) Val() map[string]int64 {
|
2015-01-25 15:05:19 +03:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
func (cmd *MapStringIntCmd) Result() (map[string]int64, error) {
|
2015-01-25 15:05:19 +03:00
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
func (cmd *MapStringIntCmd) String() string {
|
2015-01-25 15:05:19 +03:00
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2022-08-08 10:28:46 +03:00
|
|
|
func (cmd *MapStringIntCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-01-25 15:05:19 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val = make(map[string]int64, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
nn, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val[key] = nn
|
|
|
|
}
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2015-01-25 15:05:19 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2017-11-19 19:36:23 +03:00
|
|
|
type StringStructMapCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val map[string]struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*StringStructMapCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd {
|
2017-11-19 19:36:23 +03:00
|
|
|
return &StringStructMapCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-11-19 19:36:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *StringStructMapCmd) SetVal(val map[string]struct{}) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2017-11-19 19:36:23 +03:00
|
|
|
func (cmd *StringStructMapCmd) Val() map[string]struct{} {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *StringStructMapCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = make(map[string]struct{}, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val[key] = struct{}{}
|
|
|
|
}
|
|
|
|
return nil
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2017-11-25 05:06:13 +03:00
|
|
|
type XMessage struct {
|
|
|
|
ID string
|
|
|
|
Values map[string]interface{}
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
type XMessageSliceCmd struct {
|
2017-11-25 05:06:13 +03:00
|
|
|
baseCmd
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
val []XMessage
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
var _ Cmder = (*XMessageSliceCmd)(nil)
|
2017-11-25 05:06:13 +03:00
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd {
|
2018-08-02 14:48:46 +03:00
|
|
|
return &XMessageSliceCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XMessageSliceCmd) SetVal(val []XMessage) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XMessageSliceCmd) Val() []XMessage {
|
2017-11-25 05:06:13 +03:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
|
2017-11-25 05:06:13 +03:00
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XMessageSliceCmd) String() string {
|
2017-11-25 05:06:13 +03:00
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) (err error) {
|
2020-09-24 09:06:17 +03:00
|
|
|
cmd.val, err = readXMessageSlice(rd)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
2020-09-17 12:27:16 +03:00
|
|
|
if err != nil {
|
2020-09-24 09:06:17 +03:00
|
|
|
return nil, err
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
2020-09-24 09:06:17 +03:00
|
|
|
|
|
|
|
msgs := make([]XMessage, n)
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < len(msgs); i++ {
|
|
|
|
if msgs[i], err = readXMessage(rd); err != nil {
|
2020-09-24 09:06:17 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return msgs, nil
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
|
2020-09-22 20:45:23 +03:00
|
|
|
func readXMessage(rd *proto.Reader) (XMessage, error) {
|
2021-04-27 10:04:46 +03:00
|
|
|
if err := rd.ReadFixedArrayLen(2); err != nil {
|
2020-09-22 20:45:23 +03:00
|
|
|
return XMessage{}, err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2020-09-22 20:45:23 +03:00
|
|
|
id, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return XMessage{}, err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
v, err := stringInterfaceMapParser(rd)
|
2020-09-22 20:45:23 +03:00
|
|
|
if err != nil {
|
|
|
|
if err != proto.Nil {
|
|
|
|
return XMessage{}, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return XMessage{
|
|
|
|
ID: id,
|
2021-04-27 10:04:46 +03:00
|
|
|
Values: v,
|
2020-09-22 20:45:23 +03:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func stringInterfaceMapParser(rd *proto.Reader) (map[string]interface{}, error) {
|
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
m := make(map[string]interface{}, n)
|
|
|
|
for i := 0; i < n; i++ {
|
2018-08-16 13:25:19 +03:00
|
|
|
key, err := rd.ReadString()
|
2018-08-02 14:48:46 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-11-25 05:06:13 +03:00
|
|
|
|
2018-08-16 13:25:19 +03:00
|
|
|
value, err := rd.ReadString()
|
2018-08-02 14:48:46 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-11-25 05:06:13 +03:00
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
m[key] = value
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
return m, nil
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
type XStream struct {
|
|
|
|
Stream string
|
|
|
|
Messages []XMessage
|
|
|
|
}
|
|
|
|
|
|
|
|
type XStreamSliceCmd struct {
|
2017-11-25 05:06:13 +03:00
|
|
|
baseCmd
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
val []XStream
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
var _ Cmder = (*XStreamSliceCmd)(nil)
|
2017-11-25 05:06:13 +03:00
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd {
|
2018-08-02 14:48:46 +03:00
|
|
|
return &XStreamSliceCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XStreamSliceCmd) SetVal(val []XStream) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XStreamSliceCmd) Val() []XStream {
|
2017-11-25 05:06:13 +03:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
|
2017-11-25 05:06:13 +03:00
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XStreamSliceCmd) String() string {
|
2017-11-25 05:06:13 +03:00
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
typ, err := rd.PeekReplyType()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
var n int
|
|
|
|
if typ == proto.RespMap {
|
|
|
|
n, err = rd.ReadMapLen()
|
|
|
|
} else {
|
|
|
|
n, err = rd.ReadArrayLen()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]XStream, n)
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if typ != proto.RespMap {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val[i].Stream, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if cmd.val[i].Messages, err = readXMessageSlice(rd); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type XPending struct {
|
|
|
|
Count int64
|
|
|
|
Lower string
|
|
|
|
Higher string
|
|
|
|
Consumers map[string]int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type XPendingCmd struct {
|
|
|
|
baseCmd
|
|
|
|
val *XPending
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*XPendingCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd {
|
2018-08-02 14:48:46 +03:00
|
|
|
return &XPendingCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XPendingCmd) SetVal(val *XPending) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XPendingCmd) Val() *XPending {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XPendingCmd) Result() (*XPending, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XPendingCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
var err error
|
|
|
|
if err = rd.ReadFixedArrayLen(4); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = &XPending{}
|
2017-11-25 05:06:13 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val.Count, err = rd.ReadInt(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-11-25 05:06:13 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val.Lower, err = rd.ReadString(); err != nil && err != Nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val.Higher, err = rd.ReadString(); err != nil && err != Nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil && err != Nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val.Consumers = make(map[string]int64, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
consumerName, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
consumerPending, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val.Consumers[consumerName] = consumerPending
|
|
|
|
}
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type XPendingExt struct {
|
2019-05-16 16:27:19 +03:00
|
|
|
ID string
|
2018-08-02 14:48:46 +03:00
|
|
|
Consumer string
|
|
|
|
Idle time.Duration
|
|
|
|
RetryCount int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type XPendingExtCmd struct {
|
|
|
|
baseCmd
|
|
|
|
val []XPendingExt
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*XPendingExtCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd {
|
2018-08-02 14:48:46 +03:00
|
|
|
return &XPendingExtCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XPendingExtCmd) SetVal(val []XPendingExt) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2018-08-02 14:48:46 +03:00
|
|
|
func (cmd *XPendingExtCmd) Val() []XPendingExt {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XPendingExtCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]XPendingExt, n)
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if err = rd.ReadFixedArrayLen(4); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val[i].ID, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val[i].Consumer, err = rd.ReadString(); err != nil && err != Nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
idle, err := rd.ReadInt()
|
|
|
|
if err != nil && err != Nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val[i].Idle = time.Duration(idle) * time.Millisecond
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val[i].RetryCount, err = rd.ReadInt(); err != nil && err != Nil {
|
|
|
|
return err
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2017-11-25 05:06:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2021-06-04 18:04:36 +03:00
|
|
|
type XAutoClaimCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
start string
|
|
|
|
val []XMessage
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*XAutoClaimCmd)(nil)
|
|
|
|
|
|
|
|
func NewXAutoClaimCmd(ctx context.Context, args ...interface{}) *XAutoClaimCmd {
|
|
|
|
return &XAutoClaimCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XAutoClaimCmd) SetVal(val []XMessage, start string) {
|
|
|
|
cmd.val = val
|
|
|
|
cmd.start = start
|
|
|
|
}
|
|
|
|
|
2021-06-04 18:04:36 +03:00
|
|
|
func (cmd *XAutoClaimCmd) Val() (messages []XMessage, start string) {
|
|
|
|
return cmd.val, cmd.start
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XAutoClaimCmd) Result() (messages []XMessage, start string, err error) {
|
|
|
|
return cmd.val, cmd.start, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XAutoClaimCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XAutoClaimCmd) readReply(rd *proto.Reader) error {
|
2022-06-04 17:25:12 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
2021-06-28 12:40:38 +03:00
|
|
|
return err
|
|
|
|
}
|
2021-06-04 18:04:36 +03:00
|
|
|
|
2022-06-04 17:25:12 +03:00
|
|
|
switch n {
|
|
|
|
case 2, // Redis 6
|
|
|
|
3: // Redis 7:
|
|
|
|
// ok
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: got %d elements in XAutoClaim reply, wanted 2/3", n)
|
|
|
|
}
|
|
|
|
|
2021-06-28 12:40:38 +03:00
|
|
|
cmd.start, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-06-04 17:25:12 +03:00
|
|
|
|
2021-06-28 12:40:38 +03:00
|
|
|
cmd.val, err = readXMessageSlice(rd)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-06-04 17:25:12 +03:00
|
|
|
|
|
|
|
if n >= 3 {
|
|
|
|
if err := rd.DiscardNext(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 12:40:38 +03:00
|
|
|
return nil
|
2021-06-04 18:04:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type XAutoClaimJustIDCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
start string
|
|
|
|
val []string
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*XAutoClaimJustIDCmd)(nil)
|
|
|
|
|
|
|
|
func NewXAutoClaimJustIDCmd(ctx context.Context, args ...interface{}) *XAutoClaimJustIDCmd {
|
|
|
|
return &XAutoClaimJustIDCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XAutoClaimJustIDCmd) SetVal(val []string, start string) {
|
|
|
|
cmd.val = val
|
|
|
|
cmd.start = start
|
|
|
|
}
|
|
|
|
|
2021-06-04 18:04:36 +03:00
|
|
|
func (cmd *XAutoClaimJustIDCmd) Val() (ids []string, start string) {
|
|
|
|
return cmd.val, cmd.start
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XAutoClaimJustIDCmd) Result() (ids []string, start string, err error) {
|
|
|
|
return cmd.val, cmd.start, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XAutoClaimJustIDCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XAutoClaimJustIDCmd) readReply(rd *proto.Reader) error {
|
2022-06-04 17:25:12 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
2021-06-28 12:40:38 +03:00
|
|
|
return err
|
|
|
|
}
|
2021-06-04 18:04:36 +03:00
|
|
|
|
2022-06-04 17:25:12 +03:00
|
|
|
switch n {
|
|
|
|
case 2, // Redis 6
|
|
|
|
3: // Redis 7:
|
|
|
|
// ok
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: got %d elements in XAutoClaimJustID reply, wanted 2/3", n)
|
|
|
|
}
|
|
|
|
|
2021-06-28 12:40:38 +03:00
|
|
|
cmd.start, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-06-04 17:25:12 +03:00
|
|
|
|
|
|
|
nn, err := rd.ReadArrayLen()
|
2021-06-28 12:40:38 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-06-04 18:04:36 +03:00
|
|
|
|
2022-06-04 17:25:12 +03:00
|
|
|
cmd.val = make([]string, nn)
|
|
|
|
for i := 0; i < nn; i++ {
|
2021-06-28 12:40:38 +03:00
|
|
|
cmd.val[i], err = rd.ReadString()
|
2021-06-04 18:04:36 +03:00
|
|
|
if err != nil {
|
2021-06-28 12:40:38 +03:00
|
|
|
return err
|
2021-06-04 18:04:36 +03:00
|
|
|
}
|
2021-06-28 12:40:38 +03:00
|
|
|
}
|
2022-06-04 17:25:12 +03:00
|
|
|
|
|
|
|
if n >= 3 {
|
|
|
|
if err := rd.DiscardNext(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-28 12:40:38 +03:00
|
|
|
return nil
|
2021-06-04 18:04:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2021-02-09 15:46:26 +03:00
|
|
|
type XInfoConsumersCmd struct {
|
|
|
|
baseCmd
|
|
|
|
val []XInfoConsumer
|
|
|
|
}
|
|
|
|
|
|
|
|
type XInfoConsumer struct {
|
|
|
|
Name string
|
|
|
|
Pending int64
|
2022-03-19 13:22:12 +03:00
|
|
|
Idle time.Duration
|
2021-02-09 15:46:26 +03:00
|
|
|
}
|
|
|
|
|
2021-05-18 10:41:20 +03:00
|
|
|
var _ Cmder = (*XInfoConsumersCmd)(nil)
|
2021-02-09 15:46:26 +03:00
|
|
|
|
|
|
|
func NewXInfoConsumersCmd(ctx context.Context, stream string, group string) *XInfoConsumersCmd {
|
|
|
|
return &XInfoConsumersCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: []interface{}{"xinfo", "consumers", stream, group},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XInfoConsumersCmd) SetVal(val []XInfoConsumer) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2021-02-09 15:46:26 +03:00
|
|
|
func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoConsumersCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]XInfoConsumer, n)
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if err = rd.ReadFixedMapLen(3); err != nil {
|
2021-02-09 15:46:26 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
var key string
|
|
|
|
for f := 0; f < 3; f++ {
|
|
|
|
key, err = rd.ReadString()
|
2021-02-09 15:46:26 +03:00
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "name":
|
|
|
|
cmd.val[i].Name, err = rd.ReadString()
|
|
|
|
case "pending":
|
|
|
|
cmd.val[i].Pending, err = rd.ReadInt()
|
|
|
|
case "idle":
|
2022-03-19 15:54:27 +03:00
|
|
|
var idle int64
|
2022-03-19 13:22:12 +03:00
|
|
|
idle, err = rd.ReadInt()
|
2022-03-19 15:54:27 +03:00
|
|
|
cmd.val[i].Idle = time.Duration(idle) * time.Millisecond
|
2021-04-27 10:04:46 +03:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: unexpected content %s in XINFO CONSUMERS reply", key)
|
2021-02-09 15:46:26 +03:00
|
|
|
}
|
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2021-02-09 15:46:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
return nil
|
2021-02-09 15:46:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2019-10-08 12:48:24 +03:00
|
|
|
type XInfoGroupsCmd struct {
|
|
|
|
baseCmd
|
2020-09-23 11:00:34 +03:00
|
|
|
val []XInfoGroup
|
2019-10-08 12:48:24 +03:00
|
|
|
}
|
|
|
|
|
2020-09-23 11:00:34 +03:00
|
|
|
type XInfoGroup struct {
|
2019-10-08 12:48:24 +03:00
|
|
|
Name string
|
|
|
|
Consumers int64
|
|
|
|
Pending int64
|
|
|
|
LastDeliveredID string
|
2022-06-04 17:25:12 +03:00
|
|
|
EntriesRead int64
|
|
|
|
Lag int64
|
2019-10-08 12:48:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*XInfoGroupsCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd {
|
2019-10-08 12:48:24 +03:00
|
|
|
return &XInfoGroupsCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: []interface{}{"xinfo", "groups", stream},
|
|
|
|
},
|
2019-10-08 12:48:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XInfoGroupsCmd) SetVal(val []XInfoGroup) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2020-09-23 11:00:34 +03:00
|
|
|
func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
|
2019-10-08 12:48:24 +03:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2020-09-23 11:00:34 +03:00
|
|
|
func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
|
2019-10-08 12:48:24 +03:00
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoGroupsCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
|
2020-09-23 11:00:34 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]XInfoGroup, n)
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
2022-06-04 17:25:12 +03:00
|
|
|
group := &cmd.val[i]
|
|
|
|
|
|
|
|
nn, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
2020-09-23 11:00:34 +03:00
|
|
|
return err
|
2020-09-17 12:27:16 +03:00
|
|
|
}
|
2020-09-23 11:00:34 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
var key string
|
2022-06-04 17:25:12 +03:00
|
|
|
for j := 0; j < nn; j++ {
|
2021-04-27 10:04:46 +03:00
|
|
|
key, err = rd.ReadString()
|
2020-09-23 11:00:34 +03:00
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "name":
|
2022-06-04 17:25:12 +03:00
|
|
|
group.Name, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
case "consumers":
|
2022-06-04 17:25:12 +03:00
|
|
|
group.Consumers, err = rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
case "pending":
|
2022-06-04 17:25:12 +03:00
|
|
|
group.Pending, err = rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
case "last-delivered-id":
|
2022-06-04 17:25:12 +03:00
|
|
|
group.LastDeliveredID, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "entries-read":
|
|
|
|
group.EntriesRead, err = rd.ReadInt()
|
2022-06-25 15:11:46 +03:00
|
|
|
if err != nil && err != Nil {
|
2022-06-04 17:25:12 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "lag":
|
|
|
|
group.Lag, err = rd.ReadInt()
|
2023-02-24 15:21:12 +03:00
|
|
|
|
|
|
|
// lag: the number of entries in the stream that are still waiting to be delivered
|
|
|
|
// to the group's consumers, or a NULL(Nil) when that number can't be determined.
|
2023-02-17 16:05:44 +03:00
|
|
|
if err != nil && err != Nil {
|
2022-06-04 17:25:12 +03:00
|
|
|
return err
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
default:
|
2022-06-04 17:25:12 +03:00
|
|
|
return fmt.Errorf("redis: unexpected key %q in XINFO GROUPS reply", key)
|
2020-09-23 11:00:34 +03:00
|
|
|
}
|
2019-10-08 12:48:24 +03:00
|
|
|
}
|
|
|
|
}
|
2020-09-23 11:00:34 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
return nil
|
2019-10-08 12:48:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2020-09-22 20:45:23 +03:00
|
|
|
type XInfoStreamCmd struct {
|
|
|
|
baseCmd
|
|
|
|
val *XInfoStream
|
|
|
|
}
|
|
|
|
|
|
|
|
type XInfoStream struct {
|
2022-06-04 17:25:12 +03:00
|
|
|
Length int64
|
|
|
|
RadixTreeKeys int64
|
|
|
|
RadixTreeNodes int64
|
|
|
|
Groups int64
|
|
|
|
LastGeneratedID string
|
|
|
|
MaxDeletedEntryID string
|
|
|
|
EntriesAdded int64
|
|
|
|
FirstEntry XMessage
|
|
|
|
LastEntry XMessage
|
|
|
|
RecordedFirstEntryID string
|
2020-09-22 20:45:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*XInfoStreamCmd)(nil)
|
|
|
|
|
|
|
|
func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd {
|
|
|
|
return &XInfoStreamCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: []interface{}{"xinfo", "stream", stream},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XInfoStreamCmd) SetVal(val *XInfoStream) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2020-09-22 20:45:23 +03:00
|
|
|
func (cmd *XInfoStreamCmd) Val() *XInfoStream {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoStreamCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
|
2022-06-04 17:25:12 +03:00
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
2020-09-22 20:45:23 +03:00
|
|
|
return err
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val = &XInfoStream{}
|
2020-09-22 20:45:23 +03:00
|
|
|
|
2022-06-04 17:25:12 +03:00
|
|
|
for i := 0; i < n; i++ {
|
2020-09-22 20:45:23 +03:00
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2020-09-22 20:45:23 +03:00
|
|
|
}
|
|
|
|
switch key {
|
|
|
|
case "length":
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val.Length, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-22 20:45:23 +03:00
|
|
|
case "radix-tree-keys":
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val.RadixTreeKeys, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-22 20:45:23 +03:00
|
|
|
case "radix-tree-nodes":
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val.RadixTreeNodes, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-22 20:45:23 +03:00
|
|
|
case "groups":
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val.Groups, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-22 20:45:23 +03:00
|
|
|
case "last-generated-id":
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val.LastGeneratedID, err = rd.ReadString()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "max-deleted-entry-id":
|
|
|
|
cmd.val.MaxDeletedEntryID, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "entries-added":
|
|
|
|
cmd.val.EntriesAdded, err = rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-22 20:45:23 +03:00
|
|
|
case "first-entry":
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val.FirstEntry, err = readXMessage(rd)
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil && err != Nil {
|
|
|
|
return err
|
2021-05-19 11:52:13 +03:00
|
|
|
}
|
2020-09-22 20:45:23 +03:00
|
|
|
case "last-entry":
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val.LastEntry, err = readXMessage(rd)
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil && err != Nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "recorded-first-entry-id":
|
|
|
|
cmd.val.RecordedFirstEntryID, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2021-05-19 11:52:13 +03:00
|
|
|
}
|
2020-09-22 20:45:23 +03:00
|
|
|
default:
|
2022-06-04 17:25:12 +03:00
|
|
|
return fmt.Errorf("redis: unexpected key %q in XINFO STREAM reply", key)
|
2020-09-22 20:45:23 +03:00
|
|
|
}
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
return nil
|
2020-09-22 20:45:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2021-05-18 10:41:20 +03:00
|
|
|
type XInfoStreamFullCmd struct {
|
|
|
|
baseCmd
|
|
|
|
val *XInfoStreamFull
|
|
|
|
}
|
|
|
|
|
|
|
|
type XInfoStreamFull struct {
|
2022-06-04 17:25:12 +03:00
|
|
|
Length int64
|
|
|
|
RadixTreeKeys int64
|
|
|
|
RadixTreeNodes int64
|
|
|
|
LastGeneratedID string
|
|
|
|
MaxDeletedEntryID string
|
|
|
|
EntriesAdded int64
|
|
|
|
Entries []XMessage
|
|
|
|
Groups []XInfoStreamGroup
|
|
|
|
RecordedFirstEntryID string
|
2021-05-18 10:41:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type XInfoStreamGroup struct {
|
|
|
|
Name string
|
|
|
|
LastDeliveredID string
|
2022-06-04 17:25:12 +03:00
|
|
|
EntriesRead int64
|
|
|
|
Lag int64
|
2021-05-18 10:41:20 +03:00
|
|
|
PelCount int64
|
|
|
|
Pending []XInfoStreamGroupPending
|
|
|
|
Consumers []XInfoStreamConsumer
|
|
|
|
}
|
|
|
|
|
|
|
|
type XInfoStreamGroupPending struct {
|
|
|
|
ID string
|
|
|
|
Consumer string
|
|
|
|
DeliveryTime time.Time
|
|
|
|
DeliveryCount int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type XInfoStreamConsumer struct {
|
|
|
|
Name string
|
|
|
|
SeenTime time.Time
|
|
|
|
PelCount int64
|
|
|
|
Pending []XInfoStreamConsumerPending
|
|
|
|
}
|
|
|
|
|
|
|
|
type XInfoStreamConsumerPending struct {
|
|
|
|
ID string
|
|
|
|
DeliveryTime time.Time
|
|
|
|
DeliveryCount int64
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*XInfoStreamFullCmd)(nil)
|
|
|
|
|
|
|
|
func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XInfoStreamFullCmd {
|
|
|
|
return &XInfoStreamFullCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *XInfoStreamFullCmd) SetVal(val *XInfoStreamFull) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2021-05-18 10:41:20 +03:00
|
|
|
func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoStreamFullCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error {
|
2022-06-04 17:25:12 +03:00
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
2021-05-18 10:41:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = &XInfoStreamFull{}
|
|
|
|
|
2022-06-04 17:25:12 +03:00
|
|
|
for i := 0; i < n; i++ {
|
2021-05-18 10:41:20 +03:00
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "length":
|
2021-05-19 12:43:31 +03:00
|
|
|
cmd.val.Length, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
case "radix-tree-keys":
|
2021-05-19 12:43:31 +03:00
|
|
|
cmd.val.RadixTreeKeys, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
case "radix-tree-nodes":
|
2021-05-19 12:43:31 +03:00
|
|
|
cmd.val.RadixTreeNodes, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
case "last-generated-id":
|
|
|
|
cmd.val.LastGeneratedID, err = rd.ReadString()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "entries-added":
|
|
|
|
cmd.val.EntriesAdded, err = rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
case "entries":
|
|
|
|
cmd.val.Entries, err = readXMessageSlice(rd)
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
case "groups":
|
2021-05-18 11:05:17 +03:00
|
|
|
cmd.val.Groups, err = readStreamGroups(rd)
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "max-deleted-entry-id":
|
|
|
|
cmd.val.MaxDeletedEntryID, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "recorded-first-entry-id":
|
|
|
|
cmd.val.RecordedFirstEntryID, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
default:
|
2022-06-04 17:25:12 +03:00
|
|
|
return fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key)
|
2021-05-18 10:41:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
groups := make([]XInfoStreamGroup, 0, n)
|
2021-05-18 11:05:17 +03:00
|
|
|
for i := 0; i < n; i++ {
|
2022-06-04 17:25:12 +03:00
|
|
|
nn, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
2021-05-18 10:41:20 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
group := XInfoStreamGroup{}
|
|
|
|
|
2022-06-04 17:25:12 +03:00
|
|
|
for j := 0; j < nn; j++ {
|
2021-05-18 11:05:17 +03:00
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
switch key {
|
|
|
|
case "name":
|
|
|
|
group.Name, err = rd.ReadString()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 11:05:17 +03:00
|
|
|
case "last-delivered-id":
|
|
|
|
group.LastDeliveredID, err = rd.ReadString()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
case "entries-read":
|
|
|
|
group.EntriesRead, err = rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
case "lag":
|
2023-02-24 15:21:12 +03:00
|
|
|
// lag: the number of entries in the stream that are still waiting to be delivered
|
|
|
|
// to the group's consumers, or a NULL(Nil) when that number can't be determined.
|
2022-06-04 17:25:12 +03:00
|
|
|
group.Lag, err = rd.ReadInt()
|
2023-02-17 16:05:44 +03:00
|
|
|
if err != nil && err != Nil {
|
2022-06-04 17:25:12 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 11:05:17 +03:00
|
|
|
case "pel-count":
|
2021-05-19 12:43:31 +03:00
|
|
|
group.PelCount, err = rd.ReadInt()
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 11:05:17 +03:00
|
|
|
case "pending":
|
|
|
|
group.Pending, err = readXInfoStreamGroupPending(rd)
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 11:05:17 +03:00
|
|
|
case "consumers":
|
|
|
|
group.Consumers, err = readXInfoStreamConsumers(rd)
|
2022-06-04 17:25:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 11:05:17 +03:00
|
|
|
default:
|
2022-06-04 17:25:12 +03:00
|
|
|
return nil, fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key)
|
2021-05-18 11:05:17 +03:00
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
groups = append(groups, group)
|
|
|
|
}
|
|
|
|
|
|
|
|
return groups, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPending, error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
pending := make([]XInfoStreamGroupPending, 0, n)
|
|
|
|
|
|
|
|
for i := 0; i < n; i++ {
|
2021-05-19 12:43:31 +03:00
|
|
|
if err = rd.ReadFixedArrayLen(4); err != nil {
|
2021-05-18 10:41:20 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
p := XInfoStreamGroupPending{}
|
|
|
|
|
|
|
|
p.ID, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
p.Consumer, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-19 12:43:31 +03:00
|
|
|
delivery, err := rd.ReadInt()
|
2021-05-18 10:41:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
|
|
|
|
|
2021-05-19 12:43:31 +03:00
|
|
|
p.DeliveryCount, err = rd.ReadInt()
|
2021-05-18 10:41:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
pending = append(pending, p)
|
|
|
|
}
|
|
|
|
|
|
|
|
return pending, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
consumers := make([]XInfoStreamConsumer, 0, n)
|
|
|
|
|
|
|
|
for i := 0; i < n; i++ {
|
2021-05-19 12:43:31 +03:00
|
|
|
if err = rd.ReadFixedMapLen(4); err != nil {
|
2021-05-18 10:41:20 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
c := XInfoStreamConsumer{}
|
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
for f := 0; f < 4; f++ {
|
|
|
|
cKey, err := rd.ReadString()
|
2021-05-18 10:41:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
switch cKey {
|
|
|
|
case "name":
|
|
|
|
c.Name, err = rd.ReadString()
|
|
|
|
case "seen-time":
|
2021-05-19 12:43:31 +03:00
|
|
|
seen, err := rd.ReadInt()
|
2021-05-18 10:41:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 11:05:17 +03:00
|
|
|
c.SeenTime = time.Unix(seen/1000, seen%1000*int64(time.Millisecond))
|
|
|
|
case "pel-count":
|
2021-05-19 12:43:31 +03:00
|
|
|
c.PelCount, err = rd.ReadInt()
|
2021-05-18 11:05:17 +03:00
|
|
|
case "pending":
|
|
|
|
pendingNumber, err := rd.ReadArrayLen()
|
2021-05-18 10:41:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
c.Pending = make([]XInfoStreamConsumerPending, 0, pendingNumber)
|
2021-05-18 10:41:20 +03:00
|
|
|
|
2021-05-19 11:52:13 +03:00
|
|
|
for pn := 0; pn < pendingNumber; pn++ {
|
2021-05-19 12:43:31 +03:00
|
|
|
if err = rd.ReadFixedArrayLen(3); err != nil {
|
2021-05-18 11:05:17 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
p := XInfoStreamConsumerPending{}
|
2021-05-18 10:41:20 +03:00
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
p.ID, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-19 12:43:31 +03:00
|
|
|
delivery, err := rd.ReadInt()
|
2021-05-18 11:05:17 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
|
|
|
|
|
2021-05-19 12:43:31 +03:00
|
|
|
p.DeliveryCount, err = rd.ReadInt()
|
2021-05-18 11:05:17 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
|
2021-05-18 11:05:17 +03:00
|
|
|
c.Pending = append(c.Pending, p)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("redis: unexpected content %s "+
|
2021-05-19 12:43:31 +03:00
|
|
|
"in XINFO STREAM FULL reply", cKey)
|
2021-05-18 11:05:17 +03:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2021-05-18 10:41:20 +03:00
|
|
|
consumers = append(consumers, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
return consumers, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2014-07-05 14:46:27 +04:00
|
|
|
type ZSliceCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
2014-07-05 14:46:27 +04:00
|
|
|
val []Z
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*ZSliceCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &ZSliceCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *ZSliceCmd) SetVal(val []Z) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2014-07-05 14:46:27 +04:00
|
|
|
func (cmd *ZSliceCmd) Val() []Z {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2014-07-05 14:46:27 +04:00
|
|
|
func (cmd *ZSliceCmd) Result() ([]Z, error) {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2014-07-05 14:46:27 +04:00
|
|
|
func (cmd *ZSliceCmd) String() string {
|
2014-01-09 12:17:38 +04:00
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
// If the n is 0, can't continue reading.
|
|
|
|
if n == 0 {
|
|
|
|
cmd.val = make([]Z, 0)
|
|
|
|
return nil
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
typ, err := rd.PeekReplyType()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
array := typ == proto.RespArray
|
|
|
|
|
|
|
|
if array {
|
|
|
|
cmd.val = make([]Z, n)
|
|
|
|
} else {
|
2019-06-26 14:45:38 +03:00
|
|
|
cmd.val = make([]Z, n/2)
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if array {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val[i].Member, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
|
|
|
|
if cmd.val[i].Score, err = rd.ReadFloat(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2018-10-31 16:35:23 +03:00
|
|
|
type ZWithKeyCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
2019-05-16 16:27:19 +03:00
|
|
|
val *ZWithKey
|
2018-10-31 16:35:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*ZWithKeyCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd {
|
2018-10-31 16:35:23 +03:00
|
|
|
return &ZWithKeyCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2018-10-31 16:35:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *ZWithKeyCmd) SetVal(val *ZWithKey) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2019-05-16 16:27:19 +03:00
|
|
|
func (cmd *ZWithKeyCmd) Val() *ZWithKey {
|
2018-10-31 16:35:23 +03:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2019-05-16 16:27:19 +03:00
|
|
|
func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
|
2018-10-31 16:35:23 +03:00
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ZWithKeyCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
if err = rd.ReadFixedArrayLen(3); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = &ZWithKey{}
|
2019-05-16 16:27:19 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val.Key, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if cmd.val.Member, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if cmd.val.Score, err = rd.ReadFloat(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-06-26 14:45:38 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
return nil
|
2018-10-31 16:35:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2014-01-09 12:17:38 +04:00
|
|
|
type ScanCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
2014-01-09 12:17:38 +04:00
|
|
|
|
2016-04-13 11:52:47 +03:00
|
|
|
page []string
|
2016-04-09 13:07:42 +03:00
|
|
|
cursor uint64
|
2017-01-03 13:44:06 +03:00
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
process cmdable
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*ScanCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd {
|
2016-04-13 11:52:47 +03:00
|
|
|
return &ScanCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-03 13:44:06 +03:00
|
|
|
process: process,
|
2016-04-13 11:52:47 +03:00
|
|
|
}
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *ScanCmd) SetVal(page []string, cursor uint64) {
|
|
|
|
cmd.page = page
|
|
|
|
cmd.cursor = cursor
|
|
|
|
}
|
|
|
|
|
2016-04-09 13:07:42 +03:00
|
|
|
func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
|
|
|
|
return cmd.page, cmd.cursor
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2016-04-09 13:07:42 +03:00
|
|
|
func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
|
|
|
|
return cmd.page, cmd.cursor, cmd.err
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ScanCmd) String() string {
|
2016-04-13 11:52:47 +03:00
|
|
|
return cmdString(cmd, cmd.page)
|
2014-01-09 12:17:38 +04:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *ScanCmd) readReply(rd *proto.Reader) error {
|
|
|
|
if err := rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-01-20 14:09:00 +03:00
|
|
|
cursor, err := rd.ReadUint()
|
2021-04-27 10:04:46 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-01-20 14:09:00 +03:00
|
|
|
cmd.cursor = cursor
|
2021-04-27 10:04:46 +03:00
|
|
|
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.page = make([]string, n)
|
|
|
|
|
|
|
|
for i := 0; i < len(cmd.page); i++ {
|
|
|
|
if cmd.page[i], err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2013-09-29 12:06:49 +04:00
|
|
|
}
|
2015-01-24 15:12:48 +03:00
|
|
|
|
2017-01-03 13:44:06 +03:00
|
|
|
// Iterator creates a new ScanIterator.
|
|
|
|
func (cmd *ScanCmd) Iterator() *ScanIterator {
|
|
|
|
return &ScanIterator{
|
|
|
|
cmd: cmd,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-24 15:12:48 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2016-04-09 12:52:43 +03:00
|
|
|
type ClusterNode struct {
|
2022-06-04 13:24:32 +03:00
|
|
|
ID string
|
|
|
|
Addr string
|
|
|
|
NetworkingMetadata map[string]string
|
2016-04-09 12:52:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type ClusterSlot struct {
|
2015-10-07 17:09:20 +03:00
|
|
|
Start int
|
|
|
|
End int
|
2016-04-09 12:52:43 +03:00
|
|
|
Nodes []ClusterNode
|
2015-01-24 15:12:48 +03:00
|
|
|
}
|
|
|
|
|
2016-04-09 12:52:43 +03:00
|
|
|
type ClusterSlotsCmd struct {
|
2015-01-24 15:12:48 +03:00
|
|
|
baseCmd
|
|
|
|
|
2016-04-09 12:52:43 +03:00
|
|
|
val []ClusterSlot
|
2015-01-24 15:12:48 +03:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*ClusterSlotsCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &ClusterSlotsCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2015-01-24 15:12:48 +03:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *ClusterSlotsCmd) SetVal(val []ClusterSlot) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2016-04-09 12:52:43 +03:00
|
|
|
func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
|
2015-01-24 15:12:48 +03:00
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
2016-04-09 12:52:43 +03:00
|
|
|
func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
|
2015-01-24 15:12:48 +03:00
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
2016-04-09 12:52:43 +03:00
|
|
|
func (cmd *ClusterSlotsCmd) String() string {
|
2015-01-24 15:12:48 +03:00
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]ClusterSlot, n)
|
|
|
|
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
n, err = rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if n < 2 {
|
|
|
|
return fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
|
|
|
|
}
|
|
|
|
|
|
|
|
start, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
end, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// subtract start and end.
|
|
|
|
nodes := make([]ClusterNode, n-2)
|
2022-06-04 15:02:53 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for j := 0; j < len(nodes); j++ {
|
|
|
|
nn, err := rd.ReadArrayLen()
|
2018-08-02 14:48:46 +03:00
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2022-06-04 15:02:53 +03:00
|
|
|
if nn < 2 || nn > 4 {
|
|
|
|
return fmt.Errorf("got %d elements in cluster info address, expected 2, 3, or 4", n)
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
ip, err := rd.ReadString()
|
2018-08-02 14:48:46 +03:00
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
port, err := rd.ReadString()
|
2018-08-02 14:48:46 +03:00
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2018-08-16 13:25:19 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
nodes[j].Addr = net.JoinHostPort(ip, port)
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2022-06-04 15:02:53 +03:00
|
|
|
if nn >= 3 {
|
2021-04-27 10:04:46 +03:00
|
|
|
id, err := rd.ReadString()
|
2018-08-02 14:48:46 +03:00
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
nodes[j].ID = id
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
2022-06-04 15:02:53 +03:00
|
|
|
|
|
|
|
if nn >= 4 {
|
2022-06-04 17:25:12 +03:00
|
|
|
metadataLength, err := rd.ReadMapLen()
|
2022-06-04 15:02:53 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-07-29 14:28:22 +03:00
|
|
|
networkingMetadata := make(map[string]string, metadataLength)
|
2022-06-04 15:02:53 +03:00
|
|
|
|
2022-07-29 14:28:22 +03:00
|
|
|
for i := 0; i < metadataLength; i++ {
|
2022-06-04 15:02:53 +03:00
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
value, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
networkingMetadata[key] = value
|
|
|
|
}
|
|
|
|
|
|
|
|
nodes[j].NetworkingMetadata = networkingMetadata
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2022-06-04 15:02:53 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val[i] = ClusterSlot{
|
|
|
|
Start: int(start),
|
|
|
|
End: int(end),
|
|
|
|
Nodes: nodes,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2015-09-20 16:13:13 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2015-10-07 17:09:20 +03:00
|
|
|
// GeoLocation is used with GeoAdd to add geospatial location.
|
2015-09-20 16:13:13 +03:00
|
|
|
type GeoLocation struct {
|
2015-11-14 17:36:21 +03:00
|
|
|
Name string
|
|
|
|
Longitude, Latitude, Dist float64
|
|
|
|
GeoHash int64
|
2015-09-20 16:13:13 +03:00
|
|
|
}
|
|
|
|
|
2015-10-07 17:09:20 +03:00
|
|
|
// GeoRadiusQuery is used with GeoRadius to query geospatial index.
|
|
|
|
type GeoRadiusQuery struct {
|
2015-10-15 00:39:39 +03:00
|
|
|
Radius float64
|
2015-10-07 17:09:20 +03:00
|
|
|
// Can be m, km, ft, or mi. Default is km.
|
2015-10-15 00:39:39 +03:00
|
|
|
Unit string
|
|
|
|
WithCoord bool
|
|
|
|
WithDist bool
|
|
|
|
WithGeoHash bool
|
|
|
|
Count int
|
2015-10-07 17:09:20 +03:00
|
|
|
// Can be ASC or DESC. Default is no sort order.
|
2017-07-19 15:32:50 +03:00
|
|
|
Sort string
|
|
|
|
Store string
|
|
|
|
StoreDist string
|
2021-04-27 10:04:46 +03:00
|
|
|
|
|
|
|
// WithCoord+WithDist+WithGeoHash
|
|
|
|
withLen int
|
2015-10-07 17:09:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type GeoLocationCmd struct {
|
2015-09-20 16:13:13 +03:00
|
|
|
baseCmd
|
|
|
|
|
2015-11-14 17:36:21 +03:00
|
|
|
q *GeoRadiusQuery
|
2015-09-20 16:13:13 +03:00
|
|
|
locations []GeoLocation
|
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*GeoLocationCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
|
2019-08-09 15:04:56 +03:00
|
|
|
return &GeoLocationCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: geoLocationArgs(q, args...),
|
|
|
|
},
|
|
|
|
q: q,
|
2019-08-09 15:04:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} {
|
2015-11-14 17:36:21 +03:00
|
|
|
args = append(args, q.Radius)
|
|
|
|
if q.Unit != "" {
|
|
|
|
args = append(args, q.Unit)
|
|
|
|
} else {
|
|
|
|
args = append(args, "km")
|
|
|
|
}
|
|
|
|
if q.WithCoord {
|
2017-07-19 15:32:50 +03:00
|
|
|
args = append(args, "withcoord")
|
2021-04-27 10:04:46 +03:00
|
|
|
q.withLen++
|
2015-11-14 17:36:21 +03:00
|
|
|
}
|
|
|
|
if q.WithDist {
|
2017-07-19 15:32:50 +03:00
|
|
|
args = append(args, "withdist")
|
2021-04-27 10:04:46 +03:00
|
|
|
q.withLen++
|
2015-11-14 17:36:21 +03:00
|
|
|
}
|
|
|
|
if q.WithGeoHash {
|
2017-07-19 15:32:50 +03:00
|
|
|
args = append(args, "withhash")
|
2021-04-27 10:04:46 +03:00
|
|
|
q.withLen++
|
2015-11-14 17:36:21 +03:00
|
|
|
}
|
|
|
|
if q.Count > 0 {
|
2017-07-19 15:32:50 +03:00
|
|
|
args = append(args, "count", q.Count)
|
2015-11-14 17:36:21 +03:00
|
|
|
}
|
|
|
|
if q.Sort != "" {
|
|
|
|
args = append(args, q.Sort)
|
|
|
|
}
|
2017-07-19 15:32:50 +03:00
|
|
|
if q.Store != "" {
|
|
|
|
args = append(args, "store")
|
|
|
|
args = append(args, q.Store)
|
|
|
|
}
|
|
|
|
if q.StoreDist != "" {
|
|
|
|
args = append(args, "storedist")
|
|
|
|
args = append(args, q.StoreDist)
|
|
|
|
}
|
2019-08-09 15:04:56 +03:00
|
|
|
return args
|
2015-09-20 16:13:13 +03:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *GeoLocationCmd) SetVal(locations []GeoLocation) {
|
|
|
|
cmd.locations = locations
|
|
|
|
}
|
|
|
|
|
2015-10-07 17:09:20 +03:00
|
|
|
func (cmd *GeoLocationCmd) Val() []GeoLocation {
|
2015-09-20 16:13:13 +03:00
|
|
|
return cmd.locations
|
|
|
|
}
|
|
|
|
|
2015-10-07 17:09:20 +03:00
|
|
|
func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
|
2015-09-20 16:13:13 +03:00
|
|
|
return cmd.locations, cmd.err
|
|
|
|
}
|
|
|
|
|
2015-10-07 17:09:20 +03:00
|
|
|
func (cmd *GeoLocationCmd) String() string {
|
2015-09-20 16:13:13 +03:00
|
|
|
return cmdString(cmd, cmd.locations)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
2020-09-17 12:27:16 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2015-09-20 16:13:13 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.locations = make([]GeoLocation, n)
|
2016-05-06 21:12:31 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < len(cmd.locations); i++ {
|
|
|
|
// only name
|
|
|
|
if cmd.q.withLen == 0 {
|
|
|
|
if cmd.locations[i].Name, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
continue
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
// +name
|
|
|
|
if err = rd.ReadFixedArrayLen(cmd.q.withLen + 1); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.locations[i].Name, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.q.WithDist {
|
|
|
|
if cmd.locations[i].Dist, err = rd.ReadFloat(); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.q.WithGeoHash {
|
|
|
|
if cmd.locations[i].GeoHash, err = rd.ReadInt(); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.q.WithCoord {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.locations[i].Longitude, err = rd.ReadFloat(); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.locations[i].Latitude, err = rd.ReadFloat(); err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2016-08-22 12:39:22 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2021-07-28 09:38:14 +03:00
|
|
|
// GeoSearchQuery is used for GEOSearch/GEOSearchStore command query.
|
|
|
|
type GeoSearchQuery struct {
|
|
|
|
Member string
|
|
|
|
|
|
|
|
// Latitude and Longitude when using FromLonLat option.
|
|
|
|
Longitude float64
|
|
|
|
Latitude float64
|
|
|
|
|
|
|
|
// Distance and unit when using ByRadius option.
|
|
|
|
// Can use m, km, ft, or mi. Default is km.
|
|
|
|
Radius float64
|
|
|
|
RadiusUnit string
|
|
|
|
|
|
|
|
// Height, width and unit when using ByBox option.
|
|
|
|
// Can be m, km, ft, or mi. Default is km.
|
|
|
|
BoxWidth float64
|
|
|
|
BoxHeight float64
|
|
|
|
BoxUnit string
|
|
|
|
|
|
|
|
// Can be ASC or DESC. Default is no sort order.
|
|
|
|
Sort string
|
|
|
|
Count int
|
|
|
|
CountAny bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type GeoSearchLocationQuery struct {
|
|
|
|
GeoSearchQuery
|
|
|
|
|
|
|
|
WithCoord bool
|
|
|
|
WithDist bool
|
|
|
|
WithHash bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type GeoSearchStoreQuery struct {
|
|
|
|
GeoSearchQuery
|
|
|
|
|
|
|
|
// When using the StoreDist option, the command stores the items in a
|
|
|
|
// sorted set populated with their distance from the center of the circle or box,
|
|
|
|
// as a floating-point number, in the same unit specified for that shape.
|
|
|
|
StoreDist bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func geoSearchLocationArgs(q *GeoSearchLocationQuery, args []interface{}) []interface{} {
|
|
|
|
args = geoSearchArgs(&q.GeoSearchQuery, args)
|
|
|
|
|
|
|
|
if q.WithCoord {
|
|
|
|
args = append(args, "withcoord")
|
|
|
|
}
|
|
|
|
if q.WithDist {
|
|
|
|
args = append(args, "withdist")
|
|
|
|
}
|
|
|
|
if q.WithHash {
|
|
|
|
args = append(args, "withhash")
|
|
|
|
}
|
|
|
|
|
|
|
|
return args
|
|
|
|
}
|
|
|
|
|
|
|
|
func geoSearchArgs(q *GeoSearchQuery, args []interface{}) []interface{} {
|
|
|
|
if q.Member != "" {
|
|
|
|
args = append(args, "frommember", q.Member)
|
|
|
|
} else {
|
|
|
|
args = append(args, "fromlonlat", q.Longitude, q.Latitude)
|
|
|
|
}
|
|
|
|
|
|
|
|
if q.Radius > 0 {
|
|
|
|
if q.RadiusUnit == "" {
|
|
|
|
q.RadiusUnit = "km"
|
|
|
|
}
|
|
|
|
args = append(args, "byradius", q.Radius, q.RadiusUnit)
|
|
|
|
} else {
|
|
|
|
if q.BoxUnit == "" {
|
|
|
|
q.BoxUnit = "km"
|
|
|
|
}
|
|
|
|
args = append(args, "bybox", q.BoxWidth, q.BoxHeight, q.BoxUnit)
|
|
|
|
}
|
|
|
|
|
|
|
|
if q.Sort != "" {
|
|
|
|
args = append(args, q.Sort)
|
|
|
|
}
|
|
|
|
|
|
|
|
if q.Count > 0 {
|
|
|
|
args = append(args, "count", q.Count)
|
|
|
|
if q.CountAny {
|
|
|
|
args = append(args, "any")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return args
|
|
|
|
}
|
|
|
|
|
|
|
|
type GeoSearchLocationCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
opt *GeoSearchLocationQuery
|
|
|
|
val []GeoLocation
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*GeoSearchLocationCmd)(nil)
|
|
|
|
|
|
|
|
func NewGeoSearchLocationCmd(
|
|
|
|
ctx context.Context, opt *GeoSearchLocationQuery, args ...interface{},
|
|
|
|
) *GeoSearchLocationCmd {
|
|
|
|
return &GeoSearchLocationCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
opt: opt,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 07:06:04 +03:00
|
|
|
func (cmd *GeoSearchLocationCmd) SetVal(val []GeoLocation) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2021-07-28 09:38:14 +03:00
|
|
|
func (cmd *GeoSearchLocationCmd) Val() []GeoLocation {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *GeoSearchLocationCmd) Result() ([]GeoLocation, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *GeoSearchLocationCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *GeoSearchLocationCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = make([]GeoLocation, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
_, err = rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var loc GeoLocation
|
|
|
|
|
|
|
|
loc.Name, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if cmd.opt.WithDist {
|
2021-08-02 14:01:01 +03:00
|
|
|
loc.Dist, err = rd.ReadFloat()
|
2021-07-28 09:38:14 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if cmd.opt.WithHash {
|
2021-08-02 14:01:01 +03:00
|
|
|
loc.GeoHash, err = rd.ReadInt()
|
2021-07-28 09:38:14 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if cmd.opt.WithCoord {
|
2021-08-02 14:01:01 +03:00
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
2021-07-28 09:38:14 +03:00
|
|
|
return err
|
|
|
|
}
|
2021-08-02 14:01:01 +03:00
|
|
|
loc.Longitude, err = rd.ReadFloat()
|
2021-07-28 09:38:14 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-08-02 14:01:01 +03:00
|
|
|
loc.Latitude, err = rd.ReadFloat()
|
2021-07-28 09:38:14 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val[i] = loc
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2016-08-22 12:39:22 +03:00
|
|
|
type GeoPos struct {
|
|
|
|
Longitude, Latitude float64
|
|
|
|
}
|
|
|
|
|
2016-08-22 00:32:06 +03:00
|
|
|
type GeoPosCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
2019-06-26 14:45:38 +03:00
|
|
|
val []*GeoPos
|
2016-08-22 00:32:06 +03:00
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*GeoPosCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &GeoPosCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2016-08-22 00:32:06 +03:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *GeoPosCmd) SetVal(val []*GeoPos) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2016-08-22 12:39:22 +03:00
|
|
|
func (cmd *GeoPosCmd) Val() []*GeoPos {
|
2019-06-26 14:45:38 +03:00
|
|
|
return cmd.val
|
2016-08-22 00:32:06 +03:00
|
|
|
}
|
|
|
|
|
2016-08-22 12:39:22 +03:00
|
|
|
func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
|
2016-08-22 00:32:06 +03:00
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *GeoPosCmd) String() string {
|
2019-06-26 14:45:38 +03:00
|
|
|
return cmdString(cmd, cmd.val)
|
2016-08-22 00:32:06 +03:00
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]*GeoPos, n)
|
2019-05-16 16:27:19 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
err = rd.ReadFixedArrayLen(2)
|
|
|
|
if err != nil {
|
|
|
|
if err == Nil {
|
|
|
|
cmd.val[i] = nil
|
|
|
|
continue
|
2019-05-16 16:27:19 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
|
|
|
|
longitude, err := rd.ReadFloat()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
latitude, err := rd.ReadFloat()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val[i] = &GeoPos{
|
|
|
|
Longitude: longitude,
|
|
|
|
Latitude: latitude,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2016-05-06 21:12:31 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type CommandInfo struct {
|
|
|
|
Name string
|
|
|
|
Arity int8
|
|
|
|
Flags []string
|
2020-06-04 21:27:34 +03:00
|
|
|
ACLFlags []string
|
2016-05-06 21:12:31 +03:00
|
|
|
FirstKeyPos int8
|
|
|
|
LastKeyPos int8
|
|
|
|
StepCount int8
|
|
|
|
ReadOnly bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type CommandsInfoCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val map[string]*CommandInfo
|
|
|
|
}
|
|
|
|
|
2017-09-26 11:29:22 +03:00
|
|
|
var _ Cmder = (*CommandsInfoCmd)(nil)
|
|
|
|
|
2020-03-11 17:26:42 +03:00
|
|
|
func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd {
|
2017-01-13 14:39:59 +03:00
|
|
|
return &CommandsInfoCmd{
|
2020-03-11 17:26:42 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
2017-01-13 14:39:59 +03:00
|
|
|
}
|
2016-05-06 21:12:31 +03:00
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *CommandsInfoCmd) SetVal(val map[string]*CommandInfo) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2016-05-06 21:12:31 +03:00
|
|
|
func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *CommandsInfoCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2018-08-17 13:56:37 +03:00
|
|
|
func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
|
2020-06-05 09:11:12 +03:00
|
|
|
const numArgRedis5 = 6
|
|
|
|
const numArgRedis6 = 7
|
2022-06-04 16:07:28 +03:00
|
|
|
const numArgRedis7 = 10
|
2020-06-05 09:11:12 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val = make(map[string]*CommandInfo, n)
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
nn, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-06-04 16:07:28 +03:00
|
|
|
|
|
|
|
switch nn {
|
|
|
|
case numArgRedis5, numArgRedis6, numArgRedis7:
|
|
|
|
// ok
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 6/7/10", nn)
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
2019-06-26 14:45:38 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
cmdInfo := &CommandInfo{}
|
|
|
|
if cmdInfo.Name, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
arity, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmdInfo.Arity = int8(arity)
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
flagLen, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmdInfo.Flags = make([]string, flagLen)
|
|
|
|
for f := 0; f < len(cmdInfo.Flags); f++ {
|
2019-06-26 14:45:38 +03:00
|
|
|
switch s, err := rd.ReadString(); {
|
|
|
|
case err == Nil:
|
2021-04-27 10:04:46 +03:00
|
|
|
cmdInfo.Flags[f] = ""
|
2019-06-26 14:45:38 +03:00
|
|
|
case err != nil:
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2019-06-26 14:45:38 +03:00
|
|
|
default:
|
2021-04-27 10:04:46 +03:00
|
|
|
if !cmdInfo.ReadOnly && s == "readonly" {
|
|
|
|
cmdInfo.ReadOnly = true
|
|
|
|
}
|
|
|
|
cmdInfo.Flags[f] = s
|
2019-06-26 14:45:38 +03:00
|
|
|
}
|
|
|
|
}
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
firstKeyPos, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmdInfo.FirstKeyPos = int8(firstKeyPos)
|
2018-08-02 14:48:46 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
lastKeyPos, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-06-05 09:11:12 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
cmdInfo.LastKeyPos = int8(lastKeyPos)
|
2020-06-05 09:11:12 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
stepCount, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmdInfo.StepCount = int8(stepCount)
|
2020-06-05 09:11:12 +03:00
|
|
|
|
2022-06-04 16:07:28 +03:00
|
|
|
if nn >= numArgRedis6 {
|
2021-04-27 10:04:46 +03:00
|
|
|
aclFlagLen, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmdInfo.ACLFlags = make([]string, aclFlagLen)
|
|
|
|
for f := 0; f < len(cmdInfo.ACLFlags); f++ {
|
|
|
|
switch s, err := rd.ReadString(); {
|
|
|
|
case err == Nil:
|
|
|
|
cmdInfo.ACLFlags[f] = ""
|
|
|
|
case err != nil:
|
|
|
|
return err
|
|
|
|
default:
|
|
|
|
cmdInfo.ACLFlags[f] = s
|
|
|
|
}
|
2020-06-04 21:27:34 +03:00
|
|
|
}
|
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
|
2022-06-04 16:07:28 +03:00
|
|
|
if nn >= numArgRedis7 {
|
|
|
|
if err := rd.DiscardNext(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := rd.DiscardNext(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := rd.DiscardNext(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val[cmdInfo.Name] = cmdInfo
|
2020-06-04 21:27:34 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
return nil
|
2018-08-02 14:48:46 +03:00
|
|
|
}
|
|
|
|
|
2018-03-06 15:50:48 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type cmdsInfoCache struct {
|
2020-09-14 15:30:50 +03:00
|
|
|
fn func(ctx context.Context) (map[string]*CommandInfo, error)
|
2018-05-17 15:21:51 +03:00
|
|
|
|
2018-03-06 15:50:48 +03:00
|
|
|
once internal.Once
|
|
|
|
cmds map[string]*CommandInfo
|
|
|
|
}
|
|
|
|
|
2020-09-14 15:30:50 +03:00
|
|
|
func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache {
|
2018-05-17 15:21:51 +03:00
|
|
|
return &cmdsInfoCache{
|
|
|
|
fn: fn,
|
|
|
|
}
|
2018-03-06 15:50:48 +03:00
|
|
|
}
|
|
|
|
|
2020-09-14 15:30:50 +03:00
|
|
|
func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) {
|
2018-03-06 15:50:48 +03:00
|
|
|
err := c.once.Do(func() error {
|
2020-09-14 15:30:50 +03:00
|
|
|
cmds, err := c.fn(ctx)
|
2018-03-06 15:50:48 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-11-19 13:37:26 +03:00
|
|
|
|
|
|
|
// Extensions have cmd names in upper case. Convert them to lower case.
|
|
|
|
for k, v := range cmds {
|
|
|
|
lower := internal.ToLower(k)
|
|
|
|
if lower != k {
|
|
|
|
cmds[lower] = v
|
2019-11-12 10:08:59 +03:00
|
|
|
}
|
|
|
|
}
|
2019-11-19 13:37:26 +03:00
|
|
|
|
2018-03-06 15:50:48 +03:00
|
|
|
c.cmds = cmds
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return c.cmds, err
|
|
|
|
}
|
2020-06-11 10:24:04 +03:00
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type SlowLog struct {
|
2020-09-09 12:49:45 +03:00
|
|
|
ID int64
|
|
|
|
Time time.Time
|
|
|
|
Duration time.Duration
|
|
|
|
Args []string
|
|
|
|
// These are also optional fields emitted only by Redis 4.0 or greater:
|
|
|
|
// https://redis.io/commands/slowlog#output-format
|
|
|
|
ClientAddr string
|
|
|
|
ClientName string
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type SlowLogCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []SlowLog
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*SlowLogCmd)(nil)
|
|
|
|
|
|
|
|
func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
|
|
|
|
return &SlowLogCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-25 18:12:26 +03:00
|
|
|
func (cmd *SlowLogCmd) SetVal(val []SlowLog) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2020-06-11 10:24:04 +03:00
|
|
|
func (cmd *SlowLogCmd) Val() []SlowLog {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *SlowLogCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
|
2021-04-27 10:04:46 +03:00
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]SlowLog, n)
|
|
|
|
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
nn, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if nn < 4 {
|
|
|
|
return fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", nn)
|
|
|
|
}
|
2020-06-11 10:24:04 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if cmd.val[i].ID, err = rd.ReadInt(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
createdAt, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val[i].Time = time.Unix(createdAt, 0)
|
|
|
|
|
|
|
|
costs, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val[i].Duration = time.Duration(costs) * time.Microsecond
|
2020-06-11 10:24:04 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
cmdLen, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if cmdLen < 1 {
|
|
|
|
return fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val[i].Args = make([]string, cmdLen)
|
|
|
|
for f := 0; f < len(cmd.val[i].Args); f++ {
|
|
|
|
cmd.val[i].Args[f], err = rd.ReadString()
|
2020-06-11 10:24:04 +03:00
|
|
|
if err != nil {
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
2020-06-11 10:24:04 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if nn >= 5 {
|
|
|
|
if cmd.val[i].ClientAddr, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
2020-09-09 12:49:45 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
if nn >= 6 {
|
|
|
|
if cmd.val[i].ClientName, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
|
|
|
}
|
2020-09-09 12:49:45 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
|
|
|
|
type MapStringInterfaceCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val map[string]interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*MapStringInterfaceCmd)(nil)
|
|
|
|
|
|
|
|
func NewMapStringInterfaceCmd(ctx context.Context, args ...interface{}) *MapStringInterfaceCmd {
|
|
|
|
return &MapStringInterfaceCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 07:06:04 +03:00
|
|
|
func (cmd *MapStringInterfaceCmd) SetVal(val map[string]interface{}) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *MapStringInterfaceCmd) Val() map[string]interface{} {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *MapStringInterfaceCmd) Result() (map[string]interface{}, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *MapStringInterfaceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *MapStringInterfaceCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = make(map[string]interface{}, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
k, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
v, err := rd.ReadReply()
|
|
|
|
if err != nil {
|
|
|
|
if err == Nil {
|
|
|
|
cmd.val[k] = Nil
|
|
|
|
continue
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
if err, ok := err.(proto.RedisError); ok {
|
|
|
|
cmd.val[k] = err
|
|
|
|
continue
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val[k] = v
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-09-09 12:49:45 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
//-----------------------------------------------------------------------
|
2020-09-09 12:49:45 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
type MapStringStringSliceCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []map[string]string
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*MapStringStringSliceCmd)(nil)
|
|
|
|
|
|
|
|
func NewMapStringStringSliceCmd(ctx context.Context, args ...interface{}) *MapStringStringSliceCmd {
|
|
|
|
return &MapStringStringSliceCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 07:06:04 +03:00
|
|
|
func (cmd *MapStringStringSliceCmd) SetVal(val []map[string]string) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
func (cmd *MapStringStringSliceCmd) Val() []map[string]string {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *MapStringStringSliceCmd) Result() ([]map[string]string, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *MapStringStringSliceCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *MapStringStringSliceCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = make([]map[string]string, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
nn, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val[i] = make(map[string]string, nn)
|
|
|
|
for f := 0; f < nn; f++ {
|
|
|
|
k, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2020-09-09 12:49:45 +03:00
|
|
|
|
2021-04-27 10:04:46 +03:00
|
|
|
v, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
cmd.val[i][k] = v
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2021-04-27 10:04:46 +03:00
|
|
|
}
|
|
|
|
return nil
|
2020-06-11 10:24:04 +03:00
|
|
|
}
|
2023-02-13 18:02:14 +03:00
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
type KeyValuesCmd struct {
|
2023-02-13 18:02:14 +03:00
|
|
|
baseCmd
|
|
|
|
|
|
|
|
key string
|
|
|
|
val []string
|
|
|
|
}
|
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
var _ Cmder = (*KeyValuesCmd)(nil)
|
2023-02-13 18:02:14 +03:00
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
func NewKeyValuesCmd(ctx context.Context, args ...interface{}) *KeyValuesCmd {
|
|
|
|
return &KeyValuesCmd{
|
2023-02-13 18:02:14 +03:00
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
func (cmd *KeyValuesCmd) SetVal(key string, val []string) {
|
2023-02-13 18:02:14 +03:00
|
|
|
cmd.key = key
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
func (cmd *KeyValuesCmd) Val() (string, []string) {
|
2023-02-13 18:02:14 +03:00
|
|
|
return cmd.key, cmd.val
|
|
|
|
}
|
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
func (cmd *KeyValuesCmd) Result() (string, []string, error) {
|
2023-02-13 18:02:14 +03:00
|
|
|
return cmd.key, cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
func (cmd *KeyValuesCmd) String() string {
|
2023-02-13 18:02:14 +03:00
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
2023-02-14 16:52:56 +03:00
|
|
|
func (cmd *KeyValuesCmd) readReply(rd *proto.Reader) (err error) {
|
2023-02-13 18:02:14 +03:00
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.key, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]string, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
cmd.val[i], err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-02-22 20:38:51 +03:00
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type ZSliceWithKeyCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
key string
|
|
|
|
val []Z
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*ZSliceWithKeyCmd)(nil)
|
|
|
|
|
|
|
|
func NewZSliceWithKeyCmd(ctx context.Context, args ...interface{}) *ZSliceWithKeyCmd {
|
|
|
|
return &ZSliceWithKeyCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ZSliceWithKeyCmd) SetVal(key string, val []Z) {
|
|
|
|
cmd.key = key
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ZSliceWithKeyCmd) Val() (string, []Z) {
|
|
|
|
return cmd.key, cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ZSliceWithKeyCmd) Result() (string, []Z, error) {
|
|
|
|
return cmd.key, cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ZSliceWithKeyCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ZSliceWithKeyCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.key, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
typ, err := rd.PeekReplyType()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
array := typ == proto.RespArray
|
|
|
|
|
|
|
|
if array {
|
|
|
|
cmd.val = make([]Z, n)
|
|
|
|
} else {
|
|
|
|
cmd.val = make([]Z, n/2)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
if array {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if cmd.val[i].Member, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cmd.val[i].Score, err = rd.ReadFloat(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-03-09 18:01:37 +03:00
|
|
|
|
|
|
|
type Function struct {
|
|
|
|
Name string
|
|
|
|
Description string
|
|
|
|
Flags []string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Library struct {
|
|
|
|
Name string
|
|
|
|
Engine string
|
|
|
|
Functions []Function
|
|
|
|
Code string
|
|
|
|
}
|
|
|
|
|
|
|
|
type FunctionListCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []Library
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*FunctionListCmd)(nil)
|
|
|
|
|
|
|
|
func NewFunctionListCmd(ctx context.Context, args ...interface{}) *FunctionListCmd {
|
|
|
|
return &FunctionListCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionListCmd) SetVal(val []Library) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionListCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionListCmd) Val() []Library {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionListCmd) Result() ([]Library, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionListCmd) First() (*Library, error) {
|
|
|
|
if cmd.err != nil {
|
|
|
|
return nil, cmd.err
|
|
|
|
}
|
|
|
|
if len(cmd.val) > 0 {
|
|
|
|
return &cmd.val[0], nil
|
|
|
|
}
|
|
|
|
return nil, Nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionListCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
libraries := make([]Library, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
nn, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
library := Library{}
|
|
|
|
for f := 0; f < nn; f++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "library_name":
|
|
|
|
library.Name, err = rd.ReadString()
|
|
|
|
case "engine":
|
|
|
|
library.Engine, err = rd.ReadString()
|
|
|
|
case "functions":
|
|
|
|
library.Functions, err = cmd.readFunctions(rd)
|
|
|
|
case "library_code":
|
|
|
|
library.Code, err = rd.ReadString()
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: function list unexpected key %s", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
libraries[i] = library
|
|
|
|
}
|
|
|
|
cmd.val = libraries
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionListCmd) readFunctions(rd *proto.Reader) ([]Function, error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
functions := make([]Function, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
nn, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
function := Function{}
|
|
|
|
for f := 0; f < nn; f++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "name":
|
|
|
|
if function.Name, err = rd.ReadString(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
case "description":
|
|
|
|
if function.Description, err = rd.ReadString(); err != nil && err != Nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
case "flags":
|
|
|
|
// resp set
|
|
|
|
nx, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
function.Flags = make([]string, nx)
|
|
|
|
for j := 0; j < nx; j++ {
|
|
|
|
if function.Flags[j], err = rd.ReadString(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("redis: function list unexpected key %s", key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
functions[i] = function
|
|
|
|
}
|
|
|
|
return functions, nil
|
|
|
|
}
|
2023-03-19 13:20:42 +03:00
|
|
|
|
2023-03-30 16:52:06 +03:00
|
|
|
// FunctionStats contains information about the scripts currently executing on the server, and the available engines
|
|
|
|
// - Engines:
|
|
|
|
// Statistics about the engine like number of functions and number of libraries
|
|
|
|
// - RunningScript:
|
|
|
|
// The script currently running on the shard we're connecting to.
|
|
|
|
// For Redis Enterprise and Redis Cloud, this represents the
|
|
|
|
// function with the longest running time, across all the running functions, on all shards
|
|
|
|
// - RunningScripts
|
|
|
|
// All scripts currently running in a Redis Enterprise clustered database.
|
|
|
|
// Only available on Redis Enterprise
|
|
|
|
type FunctionStats struct {
|
|
|
|
Engines []Engine
|
|
|
|
isRunning bool
|
|
|
|
rs RunningScript
|
|
|
|
allrs []RunningScript
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fs *FunctionStats) Running() bool {
|
|
|
|
return fs.isRunning
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fs *FunctionStats) RunningScript() (RunningScript, bool) {
|
|
|
|
return fs.rs, fs.isRunning
|
|
|
|
}
|
|
|
|
|
|
|
|
// AllRunningScripts returns all scripts currently running in a Redis Enterprise clustered database.
|
|
|
|
// Only available on Redis Enterprise
|
|
|
|
func (fs *FunctionStats) AllRunningScripts() []RunningScript {
|
|
|
|
return fs.allrs
|
|
|
|
}
|
|
|
|
|
|
|
|
type RunningScript struct {
|
|
|
|
Name string
|
|
|
|
Command []string
|
|
|
|
Duration time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
type Engine struct {
|
|
|
|
Language string
|
|
|
|
LibrariesCount int64
|
|
|
|
FunctionsCount int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type FunctionStatsCmd struct {
|
|
|
|
baseCmd
|
|
|
|
val FunctionStats
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*FunctionStatsCmd)(nil)
|
|
|
|
|
|
|
|
func NewFunctionStatsCmd(ctx context.Context, args ...interface{}) *FunctionStatsCmd {
|
|
|
|
return &FunctionStatsCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) SetVal(val FunctionStats) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) Val() FunctionStats {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) Result() (FunctionStats, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var key string
|
|
|
|
var result FunctionStats
|
|
|
|
for f := 0; f < n; f++ {
|
|
|
|
key, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "running_script":
|
|
|
|
result.rs, result.isRunning, err = cmd.readRunningScript(rd)
|
|
|
|
case "engines":
|
|
|
|
result.Engines, err = cmd.readEngines(rd)
|
|
|
|
case "all_running_scripts": // Redis Enterprise only
|
|
|
|
result.allrs, result.isRunning, err = cmd.readRunningScripts(rd)
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: function stats unexpected key %s", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = result
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) readRunningScript(rd *proto.Reader) (RunningScript, bool, error) {
|
|
|
|
err := rd.ReadFixedMapLen(3)
|
|
|
|
if err != nil {
|
|
|
|
if err == Nil {
|
|
|
|
return RunningScript{}, false, nil
|
|
|
|
}
|
|
|
|
return RunningScript{}, false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var runningScript RunningScript
|
|
|
|
for i := 0; i < 3; i++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return RunningScript{}, false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "name":
|
|
|
|
runningScript.Name, err = rd.ReadString()
|
|
|
|
case "duration_ms":
|
|
|
|
runningScript.Duration, err = cmd.readDuration(rd)
|
|
|
|
case "command":
|
|
|
|
runningScript.Command, err = cmd.readCommand(rd)
|
|
|
|
default:
|
|
|
|
return RunningScript{}, false, fmt.Errorf("redis: function stats unexpected running_script key %s", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return RunningScript{}, false, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return runningScript, true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) readEngines(rd *proto.Reader) ([]Engine, error) {
|
|
|
|
n, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
engines := make([]Engine, 0, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
engine := Engine{}
|
|
|
|
engine.Language, err = rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = rd.ReadFixedMapLen(2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("redis: function stats unexpected %s engine map length", engine.Language)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
switch key {
|
|
|
|
case "libraries_count":
|
|
|
|
engine.LibrariesCount, err = rd.ReadInt()
|
|
|
|
case "functions_count":
|
|
|
|
engine.FunctionsCount, err = rd.ReadInt()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
engines = append(engines, engine)
|
|
|
|
}
|
|
|
|
return engines, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) readDuration(rd *proto.Reader) (time.Duration, error) {
|
|
|
|
t, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return time.Duration(0), err
|
|
|
|
}
|
|
|
|
return time.Duration(t) * time.Millisecond, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *FunctionStatsCmd) readCommand(rd *proto.Reader) ([]string, error) {
|
|
|
|
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
command := make([]string, 0, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
x, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
command = append(command, x)
|
|
|
|
}
|
|
|
|
|
|
|
|
return command, nil
|
|
|
|
}
|
|
|
|
func (cmd *FunctionStatsCmd) readRunningScripts(rd *proto.Reader) ([]RunningScript, bool, error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
runningScripts := make([]RunningScript, 0, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
rs, _, err := cmd.readRunningScript(rd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
runningScripts = append(runningScripts, rs)
|
|
|
|
}
|
|
|
|
|
|
|
|
return runningScripts, len(runningScripts) > 0, nil
|
|
|
|
}
|
|
|
|
|
2023-03-24 10:38:11 +03:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// LCSQuery is a parameter used for the LCS command
|
|
|
|
type LCSQuery struct {
|
|
|
|
Key1 string
|
|
|
|
Key2 string
|
|
|
|
Len bool
|
|
|
|
Idx bool
|
|
|
|
MinMatchLen int
|
|
|
|
WithMatchLen bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// LCSMatch is the result set of the LCS command.
|
|
|
|
type LCSMatch struct {
|
|
|
|
MatchString string
|
|
|
|
Matches []LCSMatchedPosition
|
|
|
|
Len int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type LCSMatchedPosition struct {
|
|
|
|
Key1 LCSPosition
|
|
|
|
Key2 LCSPosition
|
|
|
|
|
|
|
|
// only for withMatchLen is true
|
|
|
|
MatchLen int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type LCSPosition struct {
|
|
|
|
Start int64
|
|
|
|
End int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type LCSCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
// 1: match string
|
|
|
|
// 2: match len
|
|
|
|
// 3: match idx LCSMatch
|
|
|
|
readType uint8
|
|
|
|
val *LCSMatch
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewLCSCmd(ctx context.Context, q *LCSQuery) *LCSCmd {
|
|
|
|
args := make([]interface{}, 3, 7)
|
|
|
|
args[0] = "lcs"
|
|
|
|
args[1] = q.Key1
|
|
|
|
args[2] = q.Key2
|
|
|
|
|
|
|
|
cmd := &LCSCmd{readType: 1}
|
|
|
|
if q.Len {
|
|
|
|
cmd.readType = 2
|
|
|
|
args = append(args, "len")
|
|
|
|
} else if q.Idx {
|
|
|
|
cmd.readType = 3
|
|
|
|
args = append(args, "idx")
|
|
|
|
if q.MinMatchLen != 0 {
|
|
|
|
args = append(args, "minmatchlen", q.MinMatchLen)
|
|
|
|
}
|
|
|
|
if q.WithMatchLen {
|
|
|
|
args = append(args, "withmatchlen")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cmd.baseCmd = baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *LCSCmd) SetVal(val *LCSMatch) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *LCSCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *LCSCmd) Val() *LCSMatch {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *LCSCmd) Result() (*LCSMatch, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *LCSCmd) readReply(rd *proto.Reader) (err error) {
|
|
|
|
lcs := &LCSMatch{}
|
|
|
|
switch cmd.readType {
|
|
|
|
case 1:
|
|
|
|
// match string
|
|
|
|
if lcs.MatchString, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
// match len
|
|
|
|
if lcs.Len, err = rd.ReadInt(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case 3:
|
|
|
|
// read LCSMatch
|
|
|
|
if err = rd.ReadFixedMapLen(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// read matches or len field
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "matches":
|
|
|
|
// read array of matched positions
|
|
|
|
if lcs.Matches, err = cmd.readMatchedPositions(rd); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case "len":
|
|
|
|
// read match length
|
|
|
|
if lcs.Len, err = rd.ReadInt(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = lcs
|
|
|
|
return nil
|
2023-03-19 13:20:42 +03:00
|
|
|
}
|
|
|
|
|
2023-03-24 10:38:11 +03:00
|
|
|
func (cmd *LCSCmd) readMatchedPositions(rd *proto.Reader) ([]LCSMatchedPosition, error) {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
positions := make([]LCSMatchedPosition, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
pn, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if positions[i].Key1, err = cmd.readPosition(rd); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if positions[i].Key2, err = cmd.readPosition(rd); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// read match length if WithMatchLen is true
|
|
|
|
if pn > 2 {
|
|
|
|
if positions[i].MatchLen, err = rd.ReadInt(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return positions, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *LCSCmd) readPosition(rd *proto.Reader) (pos LCSPosition, err error) {
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return pos, err
|
|
|
|
}
|
|
|
|
if pos.Start, err = rd.ReadInt(); err != nil {
|
|
|
|
return pos, err
|
|
|
|
}
|
|
|
|
if pos.End, err = rd.ReadInt(); err != nil {
|
|
|
|
return pos, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return pos, nil
|
|
|
|
}
|
2023-03-25 13:57:12 +03:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type KeyFlags struct {
|
|
|
|
Key string
|
|
|
|
Flags []string
|
|
|
|
}
|
|
|
|
|
|
|
|
type KeyFlagsCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []KeyFlags
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*KeyFlagsCmd)(nil)
|
|
|
|
|
|
|
|
func NewKeyFlagsCmd(ctx context.Context, args ...interface{}) *KeyFlagsCmd {
|
|
|
|
return &KeyFlagsCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *KeyFlagsCmd) SetVal(val []KeyFlags) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *KeyFlagsCmd) Val() []KeyFlags {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *KeyFlagsCmd) Result() ([]KeyFlags, error) {
|
|
|
|
return cmd.val, cmd.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *KeyFlagsCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *KeyFlagsCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if n == 0 {
|
|
|
|
cmd.val = make([]KeyFlags, 0)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val = make([]KeyFlags, n)
|
|
|
|
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
|
|
|
|
if err = rd.ReadFixedArrayLen(2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cmd.val[i].Key, err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
flagsLen, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val[i].Flags = make([]string, flagsLen)
|
|
|
|
|
|
|
|
for j := 0; j < flagsLen; j++ {
|
|
|
|
if cmd.val[i].Flags[j], err = rd.ReadString(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-03-28 07:19:54 +03:00
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type ClusterLink struct {
|
|
|
|
Direction string
|
|
|
|
Node string
|
|
|
|
CreateTime int64
|
|
|
|
Events string
|
|
|
|
SendBufferAllocated int64
|
|
|
|
SendBufferUsed int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type ClusterLinksCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []ClusterLink
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*ClusterLinksCmd)(nil)
|
|
|
|
|
|
|
|
func NewClusterLinksCmd(ctx context.Context, args ...interface{}) *ClusterLinksCmd {
|
|
|
|
return &ClusterLinksCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterLinksCmd) SetVal(val []ClusterLink) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterLinksCmd) Val() []ClusterLink {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterLinksCmd) Result() ([]ClusterLink, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterLinksCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterLinksCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]ClusterLink, n)
|
|
|
|
|
|
|
|
for i := 0; i < len(cmd.val); i++ {
|
|
|
|
m, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for j := 0; j < m; j++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "direction":
|
|
|
|
cmd.val[i].Direction, err = rd.ReadString()
|
|
|
|
case "node":
|
|
|
|
cmd.val[i].Node, err = rd.ReadString()
|
|
|
|
case "create-time":
|
|
|
|
cmd.val[i].CreateTime, err = rd.ReadInt()
|
|
|
|
case "events":
|
|
|
|
cmd.val[i].Events, err = rd.ReadString()
|
|
|
|
case "send-buffer-allocated":
|
|
|
|
cmd.val[i].SendBufferAllocated, err = rd.ReadInt()
|
|
|
|
case "send-buffer-used":
|
|
|
|
cmd.val[i].SendBufferUsed, err = rd.ReadInt()
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: unexpected key %q in CLUSTER LINKS reply", key)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-03-29 16:44:06 +03:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type SlotRange struct {
|
|
|
|
Start int64
|
|
|
|
End int64
|
|
|
|
}
|
|
|
|
|
|
|
|
type Node struct {
|
|
|
|
ID string
|
|
|
|
Endpoint string
|
|
|
|
IP string
|
|
|
|
Hostname string
|
|
|
|
Port int64
|
|
|
|
TLSPort int64
|
|
|
|
Role string
|
|
|
|
ReplicationOffset int64
|
|
|
|
Health string
|
|
|
|
}
|
|
|
|
|
|
|
|
type ClusterShard struct {
|
|
|
|
Slots []SlotRange
|
|
|
|
Nodes []Node
|
|
|
|
}
|
|
|
|
|
|
|
|
type ClusterShardsCmd struct {
|
|
|
|
baseCmd
|
|
|
|
|
|
|
|
val []ClusterShard
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Cmder = (*ClusterShardsCmd)(nil)
|
|
|
|
|
|
|
|
func NewClusterShardsCmd(ctx context.Context, args ...interface{}) *ClusterShardsCmd {
|
|
|
|
return &ClusterShardsCmd{
|
|
|
|
baseCmd: baseCmd{
|
|
|
|
ctx: ctx,
|
|
|
|
args: args,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterShardsCmd) SetVal(val []ClusterShard) {
|
|
|
|
cmd.val = val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterShardsCmd) Val() []ClusterShard {
|
|
|
|
return cmd.val
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterShardsCmd) Result() ([]ClusterShard, error) {
|
|
|
|
return cmd.Val(), cmd.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterShardsCmd) String() string {
|
|
|
|
return cmdString(cmd, cmd.val)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cmd *ClusterShardsCmd) readReply(rd *proto.Reader) error {
|
|
|
|
n, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val = make([]ClusterShard, n)
|
|
|
|
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
m, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for j := 0; j < m; j++ {
|
|
|
|
key, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch key {
|
|
|
|
case "slots":
|
|
|
|
l, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for k := 0; k < l; k += 2 {
|
|
|
|
start, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
end, err := rd.ReadInt()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.val[i].Slots = append(cmd.val[i].Slots, SlotRange{Start: start, End: end})
|
|
|
|
}
|
|
|
|
case "nodes":
|
|
|
|
nodesLen, err := rd.ReadArrayLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd.val[i].Nodes = make([]Node, nodesLen)
|
|
|
|
for k := 0; k < nodesLen; k++ {
|
|
|
|
nodeMapLen, err := rd.ReadMapLen()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for l := 0; l < nodeMapLen; l++ {
|
|
|
|
nodeKey, err := rd.ReadString()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch nodeKey {
|
|
|
|
case "id":
|
|
|
|
cmd.val[i].Nodes[k].ID, err = rd.ReadString()
|
|
|
|
case "endpoint":
|
|
|
|
cmd.val[i].Nodes[k].Endpoint, err = rd.ReadString()
|
|
|
|
case "ip":
|
|
|
|
cmd.val[i].Nodes[k].IP, err = rd.ReadString()
|
|
|
|
case "hostname":
|
|
|
|
cmd.val[i].Nodes[k].Hostname, err = rd.ReadString()
|
|
|
|
case "port":
|
|
|
|
cmd.val[i].Nodes[k].Port, err = rd.ReadInt()
|
|
|
|
case "tls-port":
|
|
|
|
cmd.val[i].Nodes[k].TLSPort, err = rd.ReadInt()
|
|
|
|
case "role":
|
|
|
|
cmd.val[i].Nodes[k].Role, err = rd.ReadString()
|
|
|
|
case "replication-offset":
|
|
|
|
cmd.val[i].Nodes[k].ReplicationOffset, err = rd.ReadInt()
|
|
|
|
case "health":
|
|
|
|
cmd.val[i].Nodes[k].Health, err = rd.ReadString()
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS node reply", nodeKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS reply", key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|