...

Source file src/github.com/redis/go-redis/v9/command.go

Documentation: github.com/redis/go-redis/v9

     1  package redis
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"fmt"
     7  	"net"
     8  	"regexp"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/redis/go-redis/v9/internal"
    15  	"github.com/redis/go-redis/v9/internal/hscan"
    16  	"github.com/redis/go-redis/v9/internal/proto"
    17  	"github.com/redis/go-redis/v9/internal/util"
    18  )
    19  
    20  // keylessCommands contains Redis commands that have empty key specifications (9th slot empty)
    21  // Only includes core Redis commands, excludes FT.*, ts.*, timeseries.*, search.* and subcommands
    22  var keylessCommands = map[string]struct{}{
    23  	"acl":          {},
    24  	"asking":       {},
    25  	"auth":         {},
    26  	"bgrewriteaof": {},
    27  	"bgsave":       {},
    28  	"client":       {},
    29  	"cluster":      {},
    30  	"config":       {},
    31  	"debug":        {},
    32  	"discard":      {},
    33  	"echo":         {},
    34  	"exec":         {},
    35  	"failover":     {},
    36  	"function":     {},
    37  	"hello":        {},
    38  	"latency":      {},
    39  	"lolwut":       {},
    40  	"module":       {},
    41  	"monitor":      {},
    42  	"multi":        {},
    43  	"pfselftest":   {},
    44  	"ping":         {},
    45  	"psubscribe":   {},
    46  	"psync":        {},
    47  	"publish":      {},
    48  	"pubsub":       {},
    49  	"punsubscribe": {},
    50  	"quit":         {},
    51  	"readonly":     {},
    52  	"readwrite":    {},
    53  	"replconf":     {},
    54  	"replicaof":    {},
    55  	"role":         {},
    56  	"save":         {},
    57  	"script":       {},
    58  	"select":       {},
    59  	"shutdown":     {},
    60  	"slaveof":      {},
    61  	"slowlog":      {},
    62  	"subscribe":    {},
    63  	"swapdb":       {},
    64  	"sync":         {},
    65  	"unsubscribe":  {},
    66  	"unwatch":      {},
    67  }
    68  
    69  type Cmder interface {
    70  	// command name.
    71  	// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster".
    72  	Name() string
    73  
    74  	// full command name.
    75  	// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster info".
    76  	FullName() string
    77  
    78  	// all args of the command.
    79  	// e.g. "set k v ex 10" -> "[set k v ex 10]".
    80  	Args() []interface{}
    81  
    82  	// format request and response string.
    83  	// e.g. "set k v ex 10" -> "set k v ex 10: OK", "get k" -> "get k: v".
    84  	String() string
    85  
    86  	stringArg(int) string
    87  	firstKeyPos() int8
    88  	SetFirstKeyPos(int8)
    89  
    90  	readTimeout() *time.Duration
    91  	readReply(rd *proto.Reader) error
    92  	readRawReply(rd *proto.Reader) error
    93  	SetErr(error)
    94  	Err() error
    95  }
    96  
    97  func setCmdsErr(cmds []Cmder, e error) {
    98  	for _, cmd := range cmds {
    99  		if cmd.Err() == nil {
   100  			cmd.SetErr(e)
   101  		}
   102  	}
   103  }
   104  
   105  func cmdsFirstErr(cmds []Cmder) error {
   106  	for _, cmd := range cmds {
   107  		if err := cmd.Err(); err != nil {
   108  			return err
   109  		}
   110  	}
   111  	return nil
   112  }
   113  
   114  func writeCmds(wr *proto.Writer, cmds []Cmder) error {
   115  	for _, cmd := range cmds {
   116  		if err := writeCmd(wr, cmd); err != nil {
   117  			return err
   118  		}
   119  	}
   120  	return nil
   121  }
   122  
   123  func writeCmd(wr *proto.Writer, cmd Cmder) error {
   124  	return wr.WriteArgs(cmd.Args())
   125  }
   126  
   127  // cmdFirstKeyPos returns the position of the first key in the command's arguments.
   128  // If the command does not have a key, it returns 0.
   129  // TODO: Use the data in CommandInfo to determine the first key position.
   130  func cmdFirstKeyPos(cmd Cmder) int {
   131  	if pos := cmd.firstKeyPos(); pos != 0 {
   132  		return int(pos)
   133  	}
   134  
   135  	name := cmd.Name()
   136  
   137  	// first check if the command is keyless
   138  	if _, ok := keylessCommands[name]; ok {
   139  		return 0
   140  	}
   141  
   142  	switch name {
   143  	case "eval", "evalsha", "eval_ro", "evalsha_ro":
   144  		if cmd.stringArg(2) != "0" {
   145  			return 3
   146  		}
   147  
   148  		return 0
   149  	case "publish":
   150  		return 1
   151  	case "memory":
   152  		// https://github.com/redis/redis/issues/7493
   153  		if cmd.stringArg(1) == "usage" {
   154  			return 2
   155  		}
   156  	}
   157  	return 1
   158  }
   159  
   160  func cmdString(cmd Cmder, val interface{}) string {
   161  	b := make([]byte, 0, 64)
   162  
   163  	for i, arg := range cmd.Args() {
   164  		if i > 0 {
   165  			b = append(b, ' ')
   166  		}
   167  		b = internal.AppendArg(b, arg)
   168  	}
   169  
   170  	if err := cmd.Err(); err != nil {
   171  		b = append(b, ": "...)
   172  		b = append(b, err.Error()...)
   173  	} else if val != nil {
   174  		b = append(b, ": "...)
   175  		b = internal.AppendArg(b, val)
   176  	}
   177  
   178  	return util.BytesToString(b)
   179  }
   180  
   181  //------------------------------------------------------------------------------
   182  
   183  type baseCmd struct {
   184  	ctx          context.Context
   185  	args         []interface{}
   186  	err          error
   187  	keyPos       int8
   188  	rawVal       interface{}
   189  	_readTimeout *time.Duration
   190  }
   191  
   192  var _ Cmder = (*Cmd)(nil)
   193  
   194  func (cmd *baseCmd) Name() string {
   195  	if len(cmd.args) == 0 {
   196  		return ""
   197  	}
   198  	// Cmd name must be lower cased.
   199  	return internal.ToLower(cmd.stringArg(0))
   200  }
   201  
   202  func (cmd *baseCmd) FullName() string {
   203  	switch name := cmd.Name(); name {
   204  	case "cluster", "command":
   205  		if len(cmd.args) == 1 {
   206  			return name
   207  		}
   208  		if s2, ok := cmd.args[1].(string); ok {
   209  			return name + " " + s2
   210  		}
   211  		return name
   212  	default:
   213  		return name
   214  	}
   215  }
   216  
   217  func (cmd *baseCmd) Args() []interface{} {
   218  	return cmd.args
   219  }
   220  
   221  func (cmd *baseCmd) stringArg(pos int) string {
   222  	if pos < 0 || pos >= len(cmd.args) {
   223  		return ""
   224  	}
   225  	arg := cmd.args[pos]
   226  	switch v := arg.(type) {
   227  	case string:
   228  		return v
   229  	case []byte:
   230  		return string(v)
   231  	default:
   232  		// TODO: consider using appendArg
   233  		return fmt.Sprint(v)
   234  	}
   235  }
   236  
   237  func (cmd *baseCmd) firstKeyPos() int8 {
   238  	return cmd.keyPos
   239  }
   240  
   241  func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) {
   242  	cmd.keyPos = keyPos
   243  }
   244  
   245  func (cmd *baseCmd) SetErr(e error) {
   246  	cmd.err = e
   247  }
   248  
   249  func (cmd *baseCmd) Err() error {
   250  	return cmd.err
   251  }
   252  
   253  func (cmd *baseCmd) readTimeout() *time.Duration {
   254  	return cmd._readTimeout
   255  }
   256  
   257  func (cmd *baseCmd) setReadTimeout(d time.Duration) {
   258  	cmd._readTimeout = &d
   259  }
   260  
   261  func (cmd *baseCmd) readRawReply(rd *proto.Reader) (err error) {
   262  	cmd.rawVal, err = rd.ReadReply()
   263  	return err
   264  }
   265  
   266  //------------------------------------------------------------------------------
   267  
   268  type Cmd struct {
   269  	baseCmd
   270  
   271  	val interface{}
   272  }
   273  
   274  func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
   275  	return &Cmd{
   276  		baseCmd: baseCmd{
   277  			ctx:  ctx,
   278  			args: args,
   279  		},
   280  	}
   281  }
   282  
   283  func (cmd *Cmd) String() string {
   284  	return cmdString(cmd, cmd.val)
   285  }
   286  
   287  func (cmd *Cmd) SetVal(val interface{}) {
   288  	cmd.val = val
   289  }
   290  
   291  func (cmd *Cmd) Val() interface{} {
   292  	return cmd.val
   293  }
   294  
   295  func (cmd *Cmd) Result() (interface{}, error) {
   296  	return cmd.val, cmd.err
   297  }
   298  
   299  func (cmd *Cmd) Text() (string, error) {
   300  	if cmd.err != nil {
   301  		return "", cmd.err
   302  	}
   303  	return toString(cmd.val)
   304  }
   305  
   306  func toString(val interface{}) (string, error) {
   307  	switch val := val.(type) {
   308  	case string:
   309  		return val, nil
   310  	default:
   311  		err := fmt.Errorf("redis: unexpected type=%T for String", val)
   312  		return "", err
   313  	}
   314  }
   315  
   316  func (cmd *Cmd) Int() (int, error) {
   317  	if cmd.err != nil {
   318  		return 0, cmd.err
   319  	}
   320  	switch val := cmd.val.(type) {
   321  	case int64:
   322  		return int(val), nil
   323  	case string:
   324  		return strconv.Atoi(val)
   325  	default:
   326  		err := fmt.Errorf("redis: unexpected type=%T for Int", val)
   327  		return 0, err
   328  	}
   329  }
   330  
   331  func (cmd *Cmd) Int64() (int64, error) {
   332  	if cmd.err != nil {
   333  		return 0, cmd.err
   334  	}
   335  	return toInt64(cmd.val)
   336  }
   337  
   338  func toInt64(val interface{}) (int64, error) {
   339  	switch val := val.(type) {
   340  	case int64:
   341  		return val, nil
   342  	case string:
   343  		return strconv.ParseInt(val, 10, 64)
   344  	default:
   345  		err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
   346  		return 0, err
   347  	}
   348  }
   349  
   350  func (cmd *Cmd) Uint64() (uint64, error) {
   351  	if cmd.err != nil {
   352  		return 0, cmd.err
   353  	}
   354  	return toUint64(cmd.val)
   355  }
   356  
   357  func toUint64(val interface{}) (uint64, error) {
   358  	switch val := val.(type) {
   359  	case int64:
   360  		return uint64(val), nil
   361  	case string:
   362  		return strconv.ParseUint(val, 10, 64)
   363  	default:
   364  		err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
   365  		return 0, err
   366  	}
   367  }
   368  
   369  func (cmd *Cmd) Float32() (float32, error) {
   370  	if cmd.err != nil {
   371  		return 0, cmd.err
   372  	}
   373  	return toFloat32(cmd.val)
   374  }
   375  
   376  func toFloat32(val interface{}) (float32, error) {
   377  	switch val := val.(type) {
   378  	case int64:
   379  		return float32(val), nil
   380  	case string:
   381  		f, err := strconv.ParseFloat(val, 32)
   382  		if err != nil {
   383  			return 0, err
   384  		}
   385  		return float32(f), nil
   386  	default:
   387  		err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
   388  		return 0, err
   389  	}
   390  }
   391  
   392  func (cmd *Cmd) Float64() (float64, error) {
   393  	if cmd.err != nil {
   394  		return 0, cmd.err
   395  	}
   396  	return toFloat64(cmd.val)
   397  }
   398  
   399  func toFloat64(val interface{}) (float64, error) {
   400  	switch val := val.(type) {
   401  	case int64:
   402  		return float64(val), nil
   403  	case string:
   404  		return strconv.ParseFloat(val, 64)
   405  	default:
   406  		err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
   407  		return 0, err
   408  	}
   409  }
   410  
   411  func (cmd *Cmd) Bool() (bool, error) {
   412  	if cmd.err != nil {
   413  		return false, cmd.err
   414  	}
   415  	return toBool(cmd.val)
   416  }
   417  
   418  func toBool(val interface{}) (bool, error) {
   419  	switch val := val.(type) {
   420  	case bool:
   421  		return val, nil
   422  	case int64:
   423  		return val != 0, nil
   424  	case string:
   425  		return strconv.ParseBool(val)
   426  	default:
   427  		err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
   428  		return false, err
   429  	}
   430  }
   431  
   432  func (cmd *Cmd) Slice() ([]interface{}, error) {
   433  	if cmd.err != nil {
   434  		return nil, cmd.err
   435  	}
   436  	switch val := cmd.val.(type) {
   437  	case []interface{}:
   438  		return val, nil
   439  	default:
   440  		return nil, fmt.Errorf("redis: unexpected type=%T for Slice", val)
   441  	}
   442  }
   443  
   444  func (cmd *Cmd) StringSlice() ([]string, error) {
   445  	slice, err := cmd.Slice()
   446  	if err != nil {
   447  		return nil, err
   448  	}
   449  
   450  	ss := make([]string, len(slice))
   451  	for i, iface := range slice {
   452  		val, err := toString(iface)
   453  		if err != nil {
   454  			return nil, err
   455  		}
   456  		ss[i] = val
   457  	}
   458  	return ss, nil
   459  }
   460  
   461  func (cmd *Cmd) Int64Slice() ([]int64, error) {
   462  	slice, err := cmd.Slice()
   463  	if err != nil {
   464  		return nil, err
   465  	}
   466  
   467  	nums := make([]int64, len(slice))
   468  	for i, iface := range slice {
   469  		val, err := toInt64(iface)
   470  		if err != nil {
   471  			return nil, err
   472  		}
   473  		nums[i] = val
   474  	}
   475  	return nums, nil
   476  }
   477  
   478  func (cmd *Cmd) Uint64Slice() ([]uint64, error) {
   479  	slice, err := cmd.Slice()
   480  	if err != nil {
   481  		return nil, err
   482  	}
   483  
   484  	nums := make([]uint64, len(slice))
   485  	for i, iface := range slice {
   486  		val, err := toUint64(iface)
   487  		if err != nil {
   488  			return nil, err
   489  		}
   490  		nums[i] = val
   491  	}
   492  	return nums, nil
   493  }
   494  
   495  func (cmd *Cmd) Float32Slice() ([]float32, error) {
   496  	slice, err := cmd.Slice()
   497  	if err != nil {
   498  		return nil, err
   499  	}
   500  
   501  	floats := make([]float32, len(slice))
   502  	for i, iface := range slice {
   503  		val, err := toFloat32(iface)
   504  		if err != nil {
   505  			return nil, err
   506  		}
   507  		floats[i] = val
   508  	}
   509  	return floats, nil
   510  }
   511  
   512  func (cmd *Cmd) Float64Slice() ([]float64, error) {
   513  	slice, err := cmd.Slice()
   514  	if err != nil {
   515  		return nil, err
   516  	}
   517  
   518  	floats := make([]float64, len(slice))
   519  	for i, iface := range slice {
   520  		val, err := toFloat64(iface)
   521  		if err != nil {
   522  			return nil, err
   523  		}
   524  		floats[i] = val
   525  	}
   526  	return floats, nil
   527  }
   528  
   529  func (cmd *Cmd) BoolSlice() ([]bool, error) {
   530  	slice, err := cmd.Slice()
   531  	if err != nil {
   532  		return nil, err
   533  	}
   534  
   535  	bools := make([]bool, len(slice))
   536  	for i, iface := range slice {
   537  		val, err := toBool(iface)
   538  		if err != nil {
   539  			return nil, err
   540  		}
   541  		bools[i] = val
   542  	}
   543  	return bools, nil
   544  }
   545  
   546  func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
   547  	cmd.val, err = rd.ReadReply()
   548  	return err
   549  }
   550  
   551  //------------------------------------------------------------------------------
   552  
   553  type SliceCmd struct {
   554  	baseCmd
   555  
   556  	val []interface{}
   557  }
   558  
   559  var _ Cmder = (*SliceCmd)(nil)
   560  
   561  func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
   562  	return &SliceCmd{
   563  		baseCmd: baseCmd{
   564  			ctx:  ctx,
   565  			args: args,
   566  		},
   567  	}
   568  }
   569  
   570  func (cmd *SliceCmd) SetVal(val []interface{}) {
   571  	cmd.val = val
   572  }
   573  
   574  func (cmd *SliceCmd) Val() []interface{} {
   575  	return cmd.val
   576  }
   577  
   578  func (cmd *SliceCmd) Result() ([]interface{}, error) {
   579  	return cmd.val, cmd.err
   580  }
   581  
   582  func (cmd *SliceCmd) String() string {
   583  	return cmdString(cmd, cmd.val)
   584  }
   585  
   586  // Scan scans the results from the map into a destination struct. The map keys
   587  // are matched in the Redis struct fields by the `redis:"field"` tag.
   588  func (cmd *SliceCmd) Scan(dst interface{}) error {
   589  	if cmd.err != nil {
   590  		return cmd.err
   591  	}
   592  
   593  	// Pass the list of keys and values.
   594  	// Skip the first two args for: HMGET key
   595  	var args []interface{}
   596  	if cmd.args[0] == "hmget" {
   597  		args = cmd.args[2:]
   598  	} else {
   599  		// Otherwise, it's: MGET field field ...
   600  		args = cmd.args[1:]
   601  	}
   602  
   603  	return hscan.Scan(dst, args, cmd.val)
   604  }
   605  
   606  func (cmd *SliceCmd) readReply(rd *proto.Reader) (err error) {
   607  	cmd.val, err = rd.ReadSlice()
   608  	return err
   609  }
   610  
   611  //------------------------------------------------------------------------------
   612  
   613  type StatusCmd struct {
   614  	baseCmd
   615  
   616  	val string
   617  }
   618  
   619  var _ Cmder = (*StatusCmd)(nil)
   620  
   621  func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
   622  	return &StatusCmd{
   623  		baseCmd: baseCmd{
   624  			ctx:  ctx,
   625  			args: args,
   626  		},
   627  	}
   628  }
   629  
   630  func (cmd *StatusCmd) SetVal(val string) {
   631  	cmd.val = val
   632  }
   633  
   634  func (cmd *StatusCmd) Val() string {
   635  	return cmd.val
   636  }
   637  
   638  func (cmd *StatusCmd) Result() (string, error) {
   639  	return cmd.val, cmd.err
   640  }
   641  
   642  func (cmd *StatusCmd) Bytes() ([]byte, error) {
   643  	return util.StringToBytes(cmd.val), cmd.err
   644  }
   645  
   646  func (cmd *StatusCmd) String() string {
   647  	return cmdString(cmd, cmd.val)
   648  }
   649  
   650  func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
   651  	cmd.val, err = rd.ReadString()
   652  	return err
   653  }
   654  
   655  //------------------------------------------------------------------------------
   656  
   657  type IntCmd struct {
   658  	baseCmd
   659  
   660  	val int64
   661  }
   662  
   663  var _ Cmder = (*IntCmd)(nil)
   664  
   665  func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
   666  	return &IntCmd{
   667  		baseCmd: baseCmd{
   668  			ctx:  ctx,
   669  			args: args,
   670  		},
   671  	}
   672  }
   673  
   674  func (cmd *IntCmd) SetVal(val int64) {
   675  	cmd.val = val
   676  }
   677  
   678  func (cmd *IntCmd) Val() int64 {
   679  	return cmd.val
   680  }
   681  
   682  func (cmd *IntCmd) Result() (int64, error) {
   683  	return cmd.val, cmd.err
   684  }
   685  
   686  func (cmd *IntCmd) Uint64() (uint64, error) {
   687  	return uint64(cmd.val), cmd.err
   688  }
   689  
   690  func (cmd *IntCmd) String() string {
   691  	return cmdString(cmd, cmd.val)
   692  }
   693  
   694  func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
   695  	cmd.val, err = rd.ReadInt()
   696  	return err
   697  }
   698  
   699  //------------------------------------------------------------------------------
   700  
   701  type IntSliceCmd struct {
   702  	baseCmd
   703  
   704  	val []int64
   705  }
   706  
   707  var _ Cmder = (*IntSliceCmd)(nil)
   708  
   709  func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd {
   710  	return &IntSliceCmd{
   711  		baseCmd: baseCmd{
   712  			ctx:  ctx,
   713  			args: args,
   714  		},
   715  	}
   716  }
   717  
   718  func (cmd *IntSliceCmd) SetVal(val []int64) {
   719  	cmd.val = val
   720  }
   721  
   722  func (cmd *IntSliceCmd) Val() []int64 {
   723  	return cmd.val
   724  }
   725  
   726  func (cmd *IntSliceCmd) Result() ([]int64, error) {
   727  	return cmd.val, cmd.err
   728  }
   729  
   730  func (cmd *IntSliceCmd) String() string {
   731  	return cmdString(cmd, cmd.val)
   732  }
   733  
   734  func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
   735  	n, err := rd.ReadArrayLen()
   736  	if err != nil {
   737  		return err
   738  	}
   739  	cmd.val = make([]int64, n)
   740  	for i := 0; i < len(cmd.val); i++ {
   741  		if cmd.val[i], err = rd.ReadInt(); err != nil {
   742  			return err
   743  		}
   744  	}
   745  	return nil
   746  }
   747  
   748  //------------------------------------------------------------------------------
   749  
   750  type DurationCmd struct {
   751  	baseCmd
   752  
   753  	val       time.Duration
   754  	precision time.Duration
   755  }
   756  
   757  var _ Cmder = (*DurationCmd)(nil)
   758  
   759  func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd {
   760  	return &DurationCmd{
   761  		baseCmd: baseCmd{
   762  			ctx:  ctx,
   763  			args: args,
   764  		},
   765  		precision: precision,
   766  	}
   767  }
   768  
   769  func (cmd *DurationCmd) SetVal(val time.Duration) {
   770  	cmd.val = val
   771  }
   772  
   773  func (cmd *DurationCmd) Val() time.Duration {
   774  	return cmd.val
   775  }
   776  
   777  func (cmd *DurationCmd) Result() (time.Duration, error) {
   778  	return cmd.val, cmd.err
   779  }
   780  
   781  func (cmd *DurationCmd) String() string {
   782  	return cmdString(cmd, cmd.val)
   783  }
   784  
   785  func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
   786  	n, err := rd.ReadInt()
   787  	if err != nil {
   788  		return err
   789  	}
   790  	switch n {
   791  	// -2 if the key does not exist
   792  	// -1 if the key exists but has no associated expire
   793  	case -2, -1:
   794  		cmd.val = time.Duration(n)
   795  	default:
   796  		cmd.val = time.Duration(n) * cmd.precision
   797  	}
   798  	return nil
   799  }
   800  
   801  //------------------------------------------------------------------------------
   802  
   803  type TimeCmd struct {
   804  	baseCmd
   805  
   806  	val time.Time
   807  }
   808  
   809  var _ Cmder = (*TimeCmd)(nil)
   810  
   811  func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
   812  	return &TimeCmd{
   813  		baseCmd: baseCmd{
   814  			ctx:  ctx,
   815  			args: args,
   816  		},
   817  	}
   818  }
   819  
   820  func (cmd *TimeCmd) SetVal(val time.Time) {
   821  	cmd.val = val
   822  }
   823  
   824  func (cmd *TimeCmd) Val() time.Time {
   825  	return cmd.val
   826  }
   827  
   828  func (cmd *TimeCmd) Result() (time.Time, error) {
   829  	return cmd.val, cmd.err
   830  }
   831  
   832  func (cmd *TimeCmd) String() string {
   833  	return cmdString(cmd, cmd.val)
   834  }
   835  
   836  func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
   837  	if err := rd.ReadFixedArrayLen(2); err != nil {
   838  		return err
   839  	}
   840  	second, err := rd.ReadInt()
   841  	if err != nil {
   842  		return err
   843  	}
   844  	microsecond, err := rd.ReadInt()
   845  	if err != nil {
   846  		return err
   847  	}
   848  	cmd.val = time.Unix(second, microsecond*1000)
   849  	return nil
   850  }
   851  
   852  //------------------------------------------------------------------------------
   853  
   854  type BoolCmd struct {
   855  	baseCmd
   856  
   857  	val bool
   858  }
   859  
   860  var _ Cmder = (*BoolCmd)(nil)
   861  
   862  func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
   863  	return &BoolCmd{
   864  		baseCmd: baseCmd{
   865  			ctx:  ctx,
   866  			args: args,
   867  		},
   868  	}
   869  }
   870  
   871  func (cmd *BoolCmd) SetVal(val bool) {
   872  	cmd.val = val
   873  }
   874  
   875  func (cmd *BoolCmd) Val() bool {
   876  	return cmd.val
   877  }
   878  
   879  func (cmd *BoolCmd) Result() (bool, error) {
   880  	return cmd.val, cmd.err
   881  }
   882  
   883  func (cmd *BoolCmd) String() string {
   884  	return cmdString(cmd, cmd.val)
   885  }
   886  
   887  func (cmd *BoolCmd) readReply(rd *proto.Reader) (err error) {
   888  	cmd.val, err = rd.ReadBool()
   889  
   890  	// `SET key value NX` returns nil when key already exists. But
   891  	// `SETNX key value` returns bool (0/1). So convert nil to bool.
   892  	if err == Nil {
   893  		cmd.val = false
   894  		err = nil
   895  	}
   896  	return err
   897  }
   898  
   899  //------------------------------------------------------------------------------
   900  
   901  type StringCmd struct {
   902  	baseCmd
   903  
   904  	val string
   905  }
   906  
   907  var _ Cmder = (*StringCmd)(nil)
   908  
   909  func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
   910  	return &StringCmd{
   911  		baseCmd: baseCmd{
   912  			ctx:  ctx,
   913  			args: args,
   914  		},
   915  	}
   916  }
   917  
   918  func (cmd *StringCmd) SetVal(val string) {
   919  	cmd.val = val
   920  }
   921  
   922  func (cmd *StringCmd) Val() string {
   923  	return cmd.val
   924  }
   925  
   926  func (cmd *StringCmd) Result() (string, error) {
   927  	return cmd.val, cmd.err
   928  }
   929  
   930  func (cmd *StringCmd) Bytes() ([]byte, error) {
   931  	return util.StringToBytes(cmd.val), cmd.err
   932  }
   933  
   934  func (cmd *StringCmd) Bool() (bool, error) {
   935  	if cmd.err != nil {
   936  		return false, cmd.err
   937  	}
   938  	return strconv.ParseBool(cmd.val)
   939  }
   940  
   941  func (cmd *StringCmd) Int() (int, error) {
   942  	if cmd.err != nil {
   943  		return 0, cmd.err
   944  	}
   945  	return strconv.Atoi(cmd.Val())
   946  }
   947  
   948  func (cmd *StringCmd) Int64() (int64, error) {
   949  	if cmd.err != nil {
   950  		return 0, cmd.err
   951  	}
   952  	return strconv.ParseInt(cmd.Val(), 10, 64)
   953  }
   954  
   955  func (cmd *StringCmd) Uint64() (uint64, error) {
   956  	if cmd.err != nil {
   957  		return 0, cmd.err
   958  	}
   959  	return strconv.ParseUint(cmd.Val(), 10, 64)
   960  }
   961  
   962  func (cmd *StringCmd) Float32() (float32, error) {
   963  	if cmd.err != nil {
   964  		return 0, cmd.err
   965  	}
   966  	f, err := strconv.ParseFloat(cmd.Val(), 32)
   967  	if err != nil {
   968  		return 0, err
   969  	}
   970  	return float32(f), nil
   971  }
   972  
   973  func (cmd *StringCmd) Float64() (float64, error) {
   974  	if cmd.err != nil {
   975  		return 0, cmd.err
   976  	}
   977  	return strconv.ParseFloat(cmd.Val(), 64)
   978  }
   979  
   980  func (cmd *StringCmd) Time() (time.Time, error) {
   981  	if cmd.err != nil {
   982  		return time.Time{}, cmd.err
   983  	}
   984  	return time.Parse(time.RFC3339Nano, cmd.Val())
   985  }
   986  
   987  func (cmd *StringCmd) Scan(val interface{}) error {
   988  	if cmd.err != nil {
   989  		return cmd.err
   990  	}
   991  	return proto.Scan([]byte(cmd.val), val)
   992  }
   993  
   994  func (cmd *StringCmd) String() string {
   995  	return cmdString(cmd, cmd.val)
   996  }
   997  
   998  func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
   999  	cmd.val, err = rd.ReadString()
  1000  	return err
  1001  }
  1002  
  1003  //------------------------------------------------------------------------------
  1004  
  1005  type FloatCmd struct {
  1006  	baseCmd
  1007  
  1008  	val float64
  1009  }
  1010  
  1011  var _ Cmder = (*FloatCmd)(nil)
  1012  
  1013  func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
  1014  	return &FloatCmd{
  1015  		baseCmd: baseCmd{
  1016  			ctx:  ctx,
  1017  			args: args,
  1018  		},
  1019  	}
  1020  }
  1021  
  1022  func (cmd *FloatCmd) SetVal(val float64) {
  1023  	cmd.val = val
  1024  }
  1025  
  1026  func (cmd *FloatCmd) Val() float64 {
  1027  	return cmd.val
  1028  }
  1029  
  1030  func (cmd *FloatCmd) Result() (float64, error) {
  1031  	return cmd.val, cmd.err
  1032  }
  1033  
  1034  func (cmd *FloatCmd) String() string {
  1035  	return cmdString(cmd, cmd.val)
  1036  }
  1037  
  1038  func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
  1039  	cmd.val, err = rd.ReadFloat()
  1040  	return err
  1041  }
  1042  
  1043  //------------------------------------------------------------------------------
  1044  
  1045  type FloatSliceCmd struct {
  1046  	baseCmd
  1047  
  1048  	val []float64
  1049  }
  1050  
  1051  var _ Cmder = (*FloatSliceCmd)(nil)
  1052  
  1053  func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSliceCmd {
  1054  	return &FloatSliceCmd{
  1055  		baseCmd: baseCmd{
  1056  			ctx:  ctx,
  1057  			args: args,
  1058  		},
  1059  	}
  1060  }
  1061  
  1062  func (cmd *FloatSliceCmd) SetVal(val []float64) {
  1063  	cmd.val = val
  1064  }
  1065  
  1066  func (cmd *FloatSliceCmd) Val() []float64 {
  1067  	return cmd.val
  1068  }
  1069  
  1070  func (cmd *FloatSliceCmd) Result() ([]float64, error) {
  1071  	return cmd.val, cmd.err
  1072  }
  1073  
  1074  func (cmd *FloatSliceCmd) String() string {
  1075  	return cmdString(cmd, cmd.val)
  1076  }
  1077  
  1078  func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error {
  1079  	n, err := rd.ReadArrayLen()
  1080  	if err != nil {
  1081  		return err
  1082  	}
  1083  
  1084  	cmd.val = make([]float64, n)
  1085  	for i := 0; i < len(cmd.val); i++ {
  1086  		switch num, err := rd.ReadFloat(); {
  1087  		case err == Nil:
  1088  			cmd.val[i] = 0
  1089  		case err != nil:
  1090  			return err
  1091  		default:
  1092  			cmd.val[i] = num
  1093  		}
  1094  	}
  1095  	return nil
  1096  }
  1097  
  1098  //------------------------------------------------------------------------------
  1099  
  1100  type StringSliceCmd struct {
  1101  	baseCmd
  1102  
  1103  	val []string
  1104  }
  1105  
  1106  var _ Cmder = (*StringSliceCmd)(nil)
  1107  
  1108  func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd {
  1109  	return &StringSliceCmd{
  1110  		baseCmd: baseCmd{
  1111  			ctx:  ctx,
  1112  			args: args,
  1113  		},
  1114  	}
  1115  }
  1116  
  1117  func (cmd *StringSliceCmd) SetVal(val []string) {
  1118  	cmd.val = val
  1119  }
  1120  
  1121  func (cmd *StringSliceCmd) Val() []string {
  1122  	return cmd.val
  1123  }
  1124  
  1125  func (cmd *StringSliceCmd) Result() ([]string, error) {
  1126  	return cmd.val, cmd.err
  1127  }
  1128  
  1129  func (cmd *StringSliceCmd) String() string {
  1130  	return cmdString(cmd, cmd.val)
  1131  }
  1132  
  1133  func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
  1134  	return proto.ScanSlice(cmd.Val(), container)
  1135  }
  1136  
  1137  func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
  1138  	n, err := rd.ReadArrayLen()
  1139  	if err != nil {
  1140  		return err
  1141  	}
  1142  	cmd.val = make([]string, n)
  1143  	for i := 0; i < len(cmd.val); i++ {
  1144  		switch s, err := rd.ReadString(); {
  1145  		case err == Nil:
  1146  			cmd.val[i] = ""
  1147  		case err != nil:
  1148  			return err
  1149  		default:
  1150  			cmd.val[i] = s
  1151  		}
  1152  	}
  1153  	return nil
  1154  }
  1155  
  1156  //------------------------------------------------------------------------------
  1157  
  1158  type KeyValue struct {
  1159  	Key   string
  1160  	Value string
  1161  }
  1162  
  1163  type KeyValueSliceCmd struct {
  1164  	baseCmd
  1165  
  1166  	val []KeyValue
  1167  }
  1168  
  1169  var _ Cmder = (*KeyValueSliceCmd)(nil)
  1170  
  1171  func NewKeyValueSliceCmd(ctx context.Context, args ...interface{}) *KeyValueSliceCmd {
  1172  	return &KeyValueSliceCmd{
  1173  		baseCmd: baseCmd{
  1174  			ctx:  ctx,
  1175  			args: args,
  1176  		},
  1177  	}
  1178  }
  1179  
  1180  func (cmd *KeyValueSliceCmd) SetVal(val []KeyValue) {
  1181  	cmd.val = val
  1182  }
  1183  
  1184  func (cmd *KeyValueSliceCmd) Val() []KeyValue {
  1185  	return cmd.val
  1186  }
  1187  
  1188  func (cmd *KeyValueSliceCmd) Result() ([]KeyValue, error) {
  1189  	return cmd.val, cmd.err
  1190  }
  1191  
  1192  func (cmd *KeyValueSliceCmd) String() string {
  1193  	return cmdString(cmd, cmd.val)
  1194  }
  1195  
  1196  // Many commands will respond to two formats:
  1197  //  1. 1) "one"
  1198  //  2. (double) 1
  1199  //  2. 1) "two"
  1200  //  2. (double) 2
  1201  //
  1202  // OR:
  1203  //  1. "two"
  1204  //  2. (double) 2
  1205  //  3. "one"
  1206  //  4. (double) 1
  1207  func (cmd *KeyValueSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl
  1208  	n, err := rd.ReadArrayLen()
  1209  	if err != nil {
  1210  		return err
  1211  	}
  1212  
  1213  	// If the n is 0, can't continue reading.
  1214  	if n == 0 {
  1215  		cmd.val = make([]KeyValue, 0)
  1216  		return nil
  1217  	}
  1218  
  1219  	typ, err := rd.PeekReplyType()
  1220  	if err != nil {
  1221  		return err
  1222  	}
  1223  	array := typ == proto.RespArray
  1224  
  1225  	if array {
  1226  		cmd.val = make([]KeyValue, n)
  1227  	} else {
  1228  		cmd.val = make([]KeyValue, n/2)
  1229  	}
  1230  
  1231  	for i := 0; i < len(cmd.val); i++ {
  1232  		if array {
  1233  			if err = rd.ReadFixedArrayLen(2); err != nil {
  1234  				return err
  1235  			}
  1236  		}
  1237  
  1238  		if cmd.val[i].Key, err = rd.ReadString(); err != nil {
  1239  			return err
  1240  		}
  1241  
  1242  		if cmd.val[i].Value, err = rd.ReadString(); err != nil {
  1243  			return err
  1244  		}
  1245  	}
  1246  
  1247  	return nil
  1248  }
  1249  
  1250  //------------------------------------------------------------------------------
  1251  
  1252  type BoolSliceCmd struct {
  1253  	baseCmd
  1254  
  1255  	val []bool
  1256  }
  1257  
  1258  var _ Cmder = (*BoolSliceCmd)(nil)
  1259  
  1260  func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd {
  1261  	return &BoolSliceCmd{
  1262  		baseCmd: baseCmd{
  1263  			ctx:  ctx,
  1264  			args: args,
  1265  		},
  1266  	}
  1267  }
  1268  
  1269  func (cmd *BoolSliceCmd) SetVal(val []bool) {
  1270  	cmd.val = val
  1271  }
  1272  
  1273  func (cmd *BoolSliceCmd) Val() []bool {
  1274  	return cmd.val
  1275  }
  1276  
  1277  func (cmd *BoolSliceCmd) Result() ([]bool, error) {
  1278  	return cmd.val, cmd.err
  1279  }
  1280  
  1281  func (cmd *BoolSliceCmd) String() string {
  1282  	return cmdString(cmd, cmd.val)
  1283  }
  1284  
  1285  func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
  1286  	n, err := rd.ReadArrayLen()
  1287  	if err != nil {
  1288  		return err
  1289  	}
  1290  	cmd.val = make([]bool, n)
  1291  	for i := 0; i < len(cmd.val); i++ {
  1292  		if cmd.val[i], err = rd.ReadBool(); err != nil {
  1293  			return err
  1294  		}
  1295  	}
  1296  	return nil
  1297  }
  1298  
  1299  //------------------------------------------------------------------------------
  1300  
  1301  type MapStringStringCmd struct {
  1302  	baseCmd
  1303  
  1304  	val map[string]string
  1305  }
  1306  
  1307  var _ Cmder = (*MapStringStringCmd)(nil)
  1308  
  1309  func NewMapStringStringCmd(ctx context.Context, args ...interface{}) *MapStringStringCmd {
  1310  	return &MapStringStringCmd{
  1311  		baseCmd: baseCmd{
  1312  			ctx:  ctx,
  1313  			args: args,
  1314  		},
  1315  	}
  1316  }
  1317  
  1318  func (cmd *MapStringStringCmd) Val() map[string]string {
  1319  	return cmd.val
  1320  }
  1321  
  1322  func (cmd *MapStringStringCmd) SetVal(val map[string]string) {
  1323  	cmd.val = val
  1324  }
  1325  
  1326  func (cmd *MapStringStringCmd) Result() (map[string]string, error) {
  1327  	return cmd.val, cmd.err
  1328  }
  1329  
  1330  func (cmd *MapStringStringCmd) String() string {
  1331  	return cmdString(cmd, cmd.val)
  1332  }
  1333  
  1334  // Scan scans the results from the map into a destination struct. The map keys
  1335  // are matched in the Redis struct fields by the `redis:"field"` tag.
  1336  func (cmd *MapStringStringCmd) Scan(dest interface{}) error {
  1337  	if cmd.err != nil {
  1338  		return cmd.err
  1339  	}
  1340  
  1341  	strct, err := hscan.Struct(dest)
  1342  	if err != nil {
  1343  		return err
  1344  	}
  1345  
  1346  	for k, v := range cmd.val {
  1347  		if err := strct.Scan(k, v); err != nil {
  1348  			return err
  1349  		}
  1350  	}
  1351  
  1352  	return nil
  1353  }
  1354  
  1355  func (cmd *MapStringStringCmd) readReply(rd *proto.Reader) error {
  1356  	n, err := rd.ReadMapLen()
  1357  	if err != nil {
  1358  		return err
  1359  	}
  1360  
  1361  	cmd.val = make(map[string]string, n)
  1362  	for i := 0; i < n; i++ {
  1363  		key, err := rd.ReadString()
  1364  		if err != nil {
  1365  			return err
  1366  		}
  1367  
  1368  		value, err := rd.ReadString()
  1369  		if err != nil {
  1370  			return err
  1371  		}
  1372  
  1373  		cmd.val[key] = value
  1374  	}
  1375  	return nil
  1376  }
  1377  
  1378  //------------------------------------------------------------------------------
  1379  
  1380  type MapStringIntCmd struct {
  1381  	baseCmd
  1382  
  1383  	val map[string]int64
  1384  }
  1385  
  1386  var _ Cmder = (*MapStringIntCmd)(nil)
  1387  
  1388  func NewMapStringIntCmd(ctx context.Context, args ...interface{}) *MapStringIntCmd {
  1389  	return &MapStringIntCmd{
  1390  		baseCmd: baseCmd{
  1391  			ctx:  ctx,
  1392  			args: args,
  1393  		},
  1394  	}
  1395  }
  1396  
  1397  func (cmd *MapStringIntCmd) SetVal(val map[string]int64) {
  1398  	cmd.val = val
  1399  }
  1400  
  1401  func (cmd *MapStringIntCmd) Val() map[string]int64 {
  1402  	return cmd.val
  1403  }
  1404  
  1405  func (cmd *MapStringIntCmd) Result() (map[string]int64, error) {
  1406  	return cmd.val, cmd.err
  1407  }
  1408  
  1409  func (cmd *MapStringIntCmd) String() string {
  1410  	return cmdString(cmd, cmd.val)
  1411  }
  1412  
  1413  func (cmd *MapStringIntCmd) readReply(rd *proto.Reader) error {
  1414  	n, err := rd.ReadMapLen()
  1415  	if err != nil {
  1416  		return err
  1417  	}
  1418  
  1419  	cmd.val = make(map[string]int64, n)
  1420  	for i := 0; i < n; i++ {
  1421  		key, err := rd.ReadString()
  1422  		if err != nil {
  1423  			return err
  1424  		}
  1425  
  1426  		nn, err := rd.ReadInt()
  1427  		if err != nil {
  1428  			return err
  1429  		}
  1430  		cmd.val[key] = nn
  1431  	}
  1432  	return nil
  1433  }
  1434  
  1435  // ------------------------------------------------------------------------------
  1436  type MapStringSliceInterfaceCmd struct {
  1437  	baseCmd
  1438  	val map[string][]interface{}
  1439  }
  1440  
  1441  func NewMapStringSliceInterfaceCmd(ctx context.Context, args ...interface{}) *MapStringSliceInterfaceCmd {
  1442  	return &MapStringSliceInterfaceCmd{
  1443  		baseCmd: baseCmd{
  1444  			ctx:  ctx,
  1445  			args: args,
  1446  		},
  1447  	}
  1448  }
  1449  
  1450  func (cmd *MapStringSliceInterfaceCmd) String() string {
  1451  	return cmdString(cmd, cmd.val)
  1452  }
  1453  
  1454  func (cmd *MapStringSliceInterfaceCmd) SetVal(val map[string][]interface{}) {
  1455  	cmd.val = val
  1456  }
  1457  
  1458  func (cmd *MapStringSliceInterfaceCmd) Result() (map[string][]interface{}, error) {
  1459  	return cmd.val, cmd.err
  1460  }
  1461  
  1462  func (cmd *MapStringSliceInterfaceCmd) Val() map[string][]interface{} {
  1463  	return cmd.val
  1464  }
  1465  
  1466  func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (err error) {
  1467  	readType, err := rd.PeekReplyType()
  1468  	if err != nil {
  1469  		return err
  1470  	}
  1471  
  1472  	cmd.val = make(map[string][]interface{})
  1473  
  1474  	switch readType {
  1475  	case proto.RespMap:
  1476  		n, err := rd.ReadMapLen()
  1477  		if err != nil {
  1478  			return err
  1479  		}
  1480  		for i := 0; i < n; i++ {
  1481  			k, err := rd.ReadString()
  1482  			if err != nil {
  1483  				return err
  1484  			}
  1485  			nn, err := rd.ReadArrayLen()
  1486  			if err != nil {
  1487  				return err
  1488  			}
  1489  			cmd.val[k] = make([]interface{}, nn)
  1490  			for j := 0; j < nn; j++ {
  1491  				value, err := rd.ReadReply()
  1492  				if err != nil {
  1493  					return err
  1494  				}
  1495  				cmd.val[k][j] = value
  1496  			}
  1497  		}
  1498  	case proto.RespArray:
  1499  		// RESP2 response
  1500  		n, err := rd.ReadArrayLen()
  1501  		if err != nil {
  1502  			return err
  1503  		}
  1504  
  1505  		for i := 0; i < n; i++ {
  1506  			// Each entry in this array is itself an array with key details
  1507  			itemLen, err := rd.ReadArrayLen()
  1508  			if err != nil {
  1509  				return err
  1510  			}
  1511  
  1512  			key, err := rd.ReadString()
  1513  			if err != nil {
  1514  				return err
  1515  			}
  1516  			cmd.val[key] = make([]interface{}, 0, itemLen-1)
  1517  			for j := 1; j < itemLen; j++ {
  1518  				// Read the inner array for timestamp-value pairs
  1519  				data, err := rd.ReadReply()
  1520  				if err != nil {
  1521  					return err
  1522  				}
  1523  				cmd.val[key] = append(cmd.val[key], data)
  1524  			}
  1525  		}
  1526  	}
  1527  
  1528  	return nil
  1529  }
  1530  
  1531  //------------------------------------------------------------------------------
  1532  
  1533  type StringStructMapCmd struct {
  1534  	baseCmd
  1535  
  1536  	val map[string]struct{}
  1537  }
  1538  
  1539  var _ Cmder = (*StringStructMapCmd)(nil)
  1540  
  1541  func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd {
  1542  	return &StringStructMapCmd{
  1543  		baseCmd: baseCmd{
  1544  			ctx:  ctx,
  1545  			args: args,
  1546  		},
  1547  	}
  1548  }
  1549  
  1550  func (cmd *StringStructMapCmd) SetVal(val map[string]struct{}) {
  1551  	cmd.val = val
  1552  }
  1553  
  1554  func (cmd *StringStructMapCmd) Val() map[string]struct{} {
  1555  	return cmd.val
  1556  }
  1557  
  1558  func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
  1559  	return cmd.val, cmd.err
  1560  }
  1561  
  1562  func (cmd *StringStructMapCmd) String() string {
  1563  	return cmdString(cmd, cmd.val)
  1564  }
  1565  
  1566  func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
  1567  	n, err := rd.ReadArrayLen()
  1568  	if err != nil {
  1569  		return err
  1570  	}
  1571  
  1572  	cmd.val = make(map[string]struct{}, n)
  1573  	for i := 0; i < n; i++ {
  1574  		key, err := rd.ReadString()
  1575  		if err != nil {
  1576  			return err
  1577  		}
  1578  		cmd.val[key] = struct{}{}
  1579  	}
  1580  	return nil
  1581  }
  1582  
  1583  //------------------------------------------------------------------------------
  1584  
  1585  type XMessage struct {
  1586  	ID     string
  1587  	Values map[string]interface{}
  1588  }
  1589  
  1590  type XMessageSliceCmd struct {
  1591  	baseCmd
  1592  
  1593  	val []XMessage
  1594  }
  1595  
  1596  var _ Cmder = (*XMessageSliceCmd)(nil)
  1597  
  1598  func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd {
  1599  	return &XMessageSliceCmd{
  1600  		baseCmd: baseCmd{
  1601  			ctx:  ctx,
  1602  			args: args,
  1603  		},
  1604  	}
  1605  }
  1606  
  1607  func (cmd *XMessageSliceCmd) SetVal(val []XMessage) {
  1608  	cmd.val = val
  1609  }
  1610  
  1611  func (cmd *XMessageSliceCmd) Val() []XMessage {
  1612  	return cmd.val
  1613  }
  1614  
  1615  func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
  1616  	return cmd.val, cmd.err
  1617  }
  1618  
  1619  func (cmd *XMessageSliceCmd) String() string {
  1620  	return cmdString(cmd, cmd.val)
  1621  }
  1622  
  1623  func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) (err error) {
  1624  	cmd.val, err = readXMessageSlice(rd)
  1625  	return err
  1626  }
  1627  
  1628  func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
  1629  	n, err := rd.ReadArrayLen()
  1630  	if err != nil {
  1631  		return nil, err
  1632  	}
  1633  
  1634  	msgs := make([]XMessage, n)
  1635  	for i := 0; i < len(msgs); i++ {
  1636  		if msgs[i], err = readXMessage(rd); err != nil {
  1637  			return nil, err
  1638  		}
  1639  	}
  1640  	return msgs, nil
  1641  }
  1642  
  1643  func readXMessage(rd *proto.Reader) (XMessage, error) {
  1644  	if err := rd.ReadFixedArrayLen(2); err != nil {
  1645  		return XMessage{}, err
  1646  	}
  1647  
  1648  	id, err := rd.ReadString()
  1649  	if err != nil {
  1650  		return XMessage{}, err
  1651  	}
  1652  
  1653  	v, err := stringInterfaceMapParser(rd)
  1654  	if err != nil {
  1655  		if err != proto.Nil {
  1656  			return XMessage{}, err
  1657  		}
  1658  	}
  1659  
  1660  	return XMessage{
  1661  		ID:     id,
  1662  		Values: v,
  1663  	}, nil
  1664  }
  1665  
  1666  func stringInterfaceMapParser(rd *proto.Reader) (map[string]interface{}, error) {
  1667  	n, err := rd.ReadMapLen()
  1668  	if err != nil {
  1669  		return nil, err
  1670  	}
  1671  
  1672  	m := make(map[string]interface{}, n)
  1673  	for i := 0; i < n; i++ {
  1674  		key, err := rd.ReadString()
  1675  		if err != nil {
  1676  			return nil, err
  1677  		}
  1678  
  1679  		value, err := rd.ReadString()
  1680  		if err != nil {
  1681  			return nil, err
  1682  		}
  1683  
  1684  		m[key] = value
  1685  	}
  1686  	return m, nil
  1687  }
  1688  
  1689  //------------------------------------------------------------------------------
  1690  
  1691  type XStream struct {
  1692  	Stream   string
  1693  	Messages []XMessage
  1694  }
  1695  
  1696  type XStreamSliceCmd struct {
  1697  	baseCmd
  1698  
  1699  	val []XStream
  1700  }
  1701  
  1702  var _ Cmder = (*XStreamSliceCmd)(nil)
  1703  
  1704  func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd {
  1705  	return &XStreamSliceCmd{
  1706  		baseCmd: baseCmd{
  1707  			ctx:  ctx,
  1708  			args: args,
  1709  		},
  1710  	}
  1711  }
  1712  
  1713  func (cmd *XStreamSliceCmd) SetVal(val []XStream) {
  1714  	cmd.val = val
  1715  }
  1716  
  1717  func (cmd *XStreamSliceCmd) Val() []XStream {
  1718  	return cmd.val
  1719  }
  1720  
  1721  func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
  1722  	return cmd.val, cmd.err
  1723  }
  1724  
  1725  func (cmd *XStreamSliceCmd) String() string {
  1726  	return cmdString(cmd, cmd.val)
  1727  }
  1728  
  1729  func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
  1730  	typ, err := rd.PeekReplyType()
  1731  	if err != nil {
  1732  		return err
  1733  	}
  1734  
  1735  	var n int
  1736  	if typ == proto.RespMap {
  1737  		n, err = rd.ReadMapLen()
  1738  	} else {
  1739  		n, err = rd.ReadArrayLen()
  1740  	}
  1741  	if err != nil {
  1742  		return err
  1743  	}
  1744  	cmd.val = make([]XStream, n)
  1745  	for i := 0; i < len(cmd.val); i++ {
  1746  		if typ != proto.RespMap {
  1747  			if err = rd.ReadFixedArrayLen(2); err != nil {
  1748  				return err
  1749  			}
  1750  		}
  1751  		if cmd.val[i].Stream, err = rd.ReadString(); err != nil {
  1752  			return err
  1753  		}
  1754  		if cmd.val[i].Messages, err = readXMessageSlice(rd); err != nil {
  1755  			return err
  1756  		}
  1757  	}
  1758  	return nil
  1759  }
  1760  
  1761  //------------------------------------------------------------------------------
  1762  
  1763  type XPending struct {
  1764  	Count     int64
  1765  	Lower     string
  1766  	Higher    string
  1767  	Consumers map[string]int64
  1768  }
  1769  
  1770  type XPendingCmd struct {
  1771  	baseCmd
  1772  	val *XPending
  1773  }
  1774  
  1775  var _ Cmder = (*XPendingCmd)(nil)
  1776  
  1777  func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd {
  1778  	return &XPendingCmd{
  1779  		baseCmd: baseCmd{
  1780  			ctx:  ctx,
  1781  			args: args,
  1782  		},
  1783  	}
  1784  }
  1785  
  1786  func (cmd *XPendingCmd) SetVal(val *XPending) {
  1787  	cmd.val = val
  1788  }
  1789  
  1790  func (cmd *XPendingCmd) Val() *XPending {
  1791  	return cmd.val
  1792  }
  1793  
  1794  func (cmd *XPendingCmd) Result() (*XPending, error) {
  1795  	return cmd.val, cmd.err
  1796  }
  1797  
  1798  func (cmd *XPendingCmd) String() string {
  1799  	return cmdString(cmd, cmd.val)
  1800  }
  1801  
  1802  func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
  1803  	var err error
  1804  	if err = rd.ReadFixedArrayLen(4); err != nil {
  1805  		return err
  1806  	}
  1807  	cmd.val = &XPending{}
  1808  
  1809  	if cmd.val.Count, err = rd.ReadInt(); err != nil {
  1810  		return err
  1811  	}
  1812  
  1813  	if cmd.val.Lower, err = rd.ReadString(); err != nil && err != Nil {
  1814  		return err
  1815  	}
  1816  
  1817  	if cmd.val.Higher, err = rd.ReadString(); err != nil && err != Nil {
  1818  		return err
  1819  	}
  1820  
  1821  	n, err := rd.ReadArrayLen()
  1822  	if err != nil && err != Nil {
  1823  		return err
  1824  	}
  1825  	cmd.val.Consumers = make(map[string]int64, n)
  1826  	for i := 0; i < n; i++ {
  1827  		if err = rd.ReadFixedArrayLen(2); err != nil {
  1828  			return err
  1829  		}
  1830  
  1831  		consumerName, err := rd.ReadString()
  1832  		if err != nil {
  1833  			return err
  1834  		}
  1835  		consumerPending, err := rd.ReadInt()
  1836  		if err != nil {
  1837  			return err
  1838  		}
  1839  		cmd.val.Consumers[consumerName] = consumerPending
  1840  	}
  1841  	return nil
  1842  }
  1843  
  1844  //------------------------------------------------------------------------------
  1845  
  1846  type XPendingExt struct {
  1847  	ID         string
  1848  	Consumer   string
  1849  	Idle       time.Duration
  1850  	RetryCount int64
  1851  }
  1852  
  1853  type XPendingExtCmd struct {
  1854  	baseCmd
  1855  	val []XPendingExt
  1856  }
  1857  
  1858  var _ Cmder = (*XPendingExtCmd)(nil)
  1859  
  1860  func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd {
  1861  	return &XPendingExtCmd{
  1862  		baseCmd: baseCmd{
  1863  			ctx:  ctx,
  1864  			args: args,
  1865  		},
  1866  	}
  1867  }
  1868  
  1869  func (cmd *XPendingExtCmd) SetVal(val []XPendingExt) {
  1870  	cmd.val = val
  1871  }
  1872  
  1873  func (cmd *XPendingExtCmd) Val() []XPendingExt {
  1874  	return cmd.val
  1875  }
  1876  
  1877  func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
  1878  	return cmd.val, cmd.err
  1879  }
  1880  
  1881  func (cmd *XPendingExtCmd) String() string {
  1882  	return cmdString(cmd, cmd.val)
  1883  }
  1884  
  1885  func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
  1886  	n, err := rd.ReadArrayLen()
  1887  	if err != nil {
  1888  		return err
  1889  	}
  1890  	cmd.val = make([]XPendingExt, n)
  1891  
  1892  	for i := 0; i < len(cmd.val); i++ {
  1893  		if err = rd.ReadFixedArrayLen(4); err != nil {
  1894  			return err
  1895  		}
  1896  
  1897  		if cmd.val[i].ID, err = rd.ReadString(); err != nil {
  1898  			return err
  1899  		}
  1900  
  1901  		if cmd.val[i].Consumer, err = rd.ReadString(); err != nil && err != Nil {
  1902  			return err
  1903  		}
  1904  
  1905  		idle, err := rd.ReadInt()
  1906  		if err != nil && err != Nil {
  1907  			return err
  1908  		}
  1909  		cmd.val[i].Idle = time.Duration(idle) * time.Millisecond
  1910  
  1911  		if cmd.val[i].RetryCount, err = rd.ReadInt(); err != nil && err != Nil {
  1912  			return err
  1913  		}
  1914  	}
  1915  
  1916  	return nil
  1917  }
  1918  
  1919  //------------------------------------------------------------------------------
  1920  
  1921  type XAutoClaimCmd struct {
  1922  	baseCmd
  1923  
  1924  	start string
  1925  	val   []XMessage
  1926  }
  1927  
  1928  var _ Cmder = (*XAutoClaimCmd)(nil)
  1929  
  1930  func NewXAutoClaimCmd(ctx context.Context, args ...interface{}) *XAutoClaimCmd {
  1931  	return &XAutoClaimCmd{
  1932  		baseCmd: baseCmd{
  1933  			ctx:  ctx,
  1934  			args: args,
  1935  		},
  1936  	}
  1937  }
  1938  
  1939  func (cmd *XAutoClaimCmd) SetVal(val []XMessage, start string) {
  1940  	cmd.val = val
  1941  	cmd.start = start
  1942  }
  1943  
  1944  func (cmd *XAutoClaimCmd) Val() (messages []XMessage, start string) {
  1945  	return cmd.val, cmd.start
  1946  }
  1947  
  1948  func (cmd *XAutoClaimCmd) Result() (messages []XMessage, start string, err error) {
  1949  	return cmd.val, cmd.start, cmd.err
  1950  }
  1951  
  1952  func (cmd *XAutoClaimCmd) String() string {
  1953  	return cmdString(cmd, cmd.val)
  1954  }
  1955  
  1956  func (cmd *XAutoClaimCmd) readReply(rd *proto.Reader) error {
  1957  	n, err := rd.ReadArrayLen()
  1958  	if err != nil {
  1959  		return err
  1960  	}
  1961  
  1962  	switch n {
  1963  	case 2, // Redis 6
  1964  		3: // Redis 7:
  1965  		// ok
  1966  	default:
  1967  		return fmt.Errorf("redis: got %d elements in XAutoClaim reply, wanted 2/3", n)
  1968  	}
  1969  
  1970  	cmd.start, err = rd.ReadString()
  1971  	if err != nil {
  1972  		return err
  1973  	}
  1974  
  1975  	cmd.val, err = readXMessageSlice(rd)
  1976  	if err != nil {
  1977  		return err
  1978  	}
  1979  
  1980  	if n >= 3 {
  1981  		if err := rd.DiscardNext(); err != nil {
  1982  			return err
  1983  		}
  1984  	}
  1985  
  1986  	return nil
  1987  }
  1988  
  1989  //------------------------------------------------------------------------------
  1990  
  1991  type XAutoClaimJustIDCmd struct {
  1992  	baseCmd
  1993  
  1994  	start string
  1995  	val   []string
  1996  }
  1997  
  1998  var _ Cmder = (*XAutoClaimJustIDCmd)(nil)
  1999  
  2000  func NewXAutoClaimJustIDCmd(ctx context.Context, args ...interface{}) *XAutoClaimJustIDCmd {
  2001  	return &XAutoClaimJustIDCmd{
  2002  		baseCmd: baseCmd{
  2003  			ctx:  ctx,
  2004  			args: args,
  2005  		},
  2006  	}
  2007  }
  2008  
  2009  func (cmd *XAutoClaimJustIDCmd) SetVal(val []string, start string) {
  2010  	cmd.val = val
  2011  	cmd.start = start
  2012  }
  2013  
  2014  func (cmd *XAutoClaimJustIDCmd) Val() (ids []string, start string) {
  2015  	return cmd.val, cmd.start
  2016  }
  2017  
  2018  func (cmd *XAutoClaimJustIDCmd) Result() (ids []string, start string, err error) {
  2019  	return cmd.val, cmd.start, cmd.err
  2020  }
  2021  
  2022  func (cmd *XAutoClaimJustIDCmd) String() string {
  2023  	return cmdString(cmd, cmd.val)
  2024  }
  2025  
  2026  func (cmd *XAutoClaimJustIDCmd) readReply(rd *proto.Reader) error {
  2027  	n, err := rd.ReadArrayLen()
  2028  	if err != nil {
  2029  		return err
  2030  	}
  2031  
  2032  	switch n {
  2033  	case 2, // Redis 6
  2034  		3: // Redis 7:
  2035  		// ok
  2036  	default:
  2037  		return fmt.Errorf("redis: got %d elements in XAutoClaimJustID reply, wanted 2/3", n)
  2038  	}
  2039  
  2040  	cmd.start, err = rd.ReadString()
  2041  	if err != nil {
  2042  		return err
  2043  	}
  2044  
  2045  	nn, err := rd.ReadArrayLen()
  2046  	if err != nil {
  2047  		return err
  2048  	}
  2049  
  2050  	cmd.val = make([]string, nn)
  2051  	for i := 0; i < nn; i++ {
  2052  		cmd.val[i], err = rd.ReadString()
  2053  		if err != nil {
  2054  			return err
  2055  		}
  2056  	}
  2057  
  2058  	if n >= 3 {
  2059  		if err := rd.DiscardNext(); err != nil {
  2060  			return err
  2061  		}
  2062  	}
  2063  
  2064  	return nil
  2065  }
  2066  
  2067  //------------------------------------------------------------------------------
  2068  
  2069  type XInfoConsumersCmd struct {
  2070  	baseCmd
  2071  	val []XInfoConsumer
  2072  }
  2073  
  2074  type XInfoConsumer struct {
  2075  	Name     string
  2076  	Pending  int64
  2077  	Idle     time.Duration
  2078  	Inactive time.Duration
  2079  }
  2080  
  2081  var _ Cmder = (*XInfoConsumersCmd)(nil)
  2082  
  2083  func NewXInfoConsumersCmd(ctx context.Context, stream string, group string) *XInfoConsumersCmd {
  2084  	return &XInfoConsumersCmd{
  2085  		baseCmd: baseCmd{
  2086  			ctx:  ctx,
  2087  			args: []interface{}{"xinfo", "consumers", stream, group},
  2088  		},
  2089  	}
  2090  }
  2091  
  2092  func (cmd *XInfoConsumersCmd) SetVal(val []XInfoConsumer) {
  2093  	cmd.val = val
  2094  }
  2095  
  2096  func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer {
  2097  	return cmd.val
  2098  }
  2099  
  2100  func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) {
  2101  	return cmd.val, cmd.err
  2102  }
  2103  
  2104  func (cmd *XInfoConsumersCmd) String() string {
  2105  	return cmdString(cmd, cmd.val)
  2106  }
  2107  
  2108  func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error {
  2109  	n, err := rd.ReadArrayLen()
  2110  	if err != nil {
  2111  		return err
  2112  	}
  2113  	cmd.val = make([]XInfoConsumer, n)
  2114  
  2115  	for i := 0; i < len(cmd.val); i++ {
  2116  		nn, err := rd.ReadMapLen()
  2117  		if err != nil {
  2118  			return err
  2119  		}
  2120  
  2121  		var key string
  2122  		for f := 0; f < nn; f++ {
  2123  			key, err = rd.ReadString()
  2124  			if err != nil {
  2125  				return err
  2126  			}
  2127  
  2128  			switch key {
  2129  			case "name":
  2130  				cmd.val[i].Name, err = rd.ReadString()
  2131  			case "pending":
  2132  				cmd.val[i].Pending, err = rd.ReadInt()
  2133  			case "idle":
  2134  				var idle int64
  2135  				idle, err = rd.ReadInt()
  2136  				cmd.val[i].Idle = time.Duration(idle) * time.Millisecond
  2137  			case "inactive":
  2138  				var inactive int64
  2139  				inactive, err = rd.ReadInt()
  2140  				cmd.val[i].Inactive = time.Duration(inactive) * time.Millisecond
  2141  			default:
  2142  				return fmt.Errorf("redis: unexpected content %s in XINFO CONSUMERS reply", key)
  2143  			}
  2144  			if err != nil {
  2145  				return err
  2146  			}
  2147  		}
  2148  	}
  2149  
  2150  	return nil
  2151  }
  2152  
  2153  //------------------------------------------------------------------------------
  2154  
  2155  type XInfoGroupsCmd struct {
  2156  	baseCmd
  2157  	val []XInfoGroup
  2158  }
  2159  
  2160  type XInfoGroup struct {
  2161  	Name            string
  2162  	Consumers       int64
  2163  	Pending         int64
  2164  	LastDeliveredID string
  2165  	EntriesRead     int64
  2166  	// Lag represents the number of pending messages in the stream not yet
  2167  	// delivered to this consumer group. Returns -1 when the lag cannot be determined.
  2168  	Lag int64
  2169  }
  2170  
  2171  var _ Cmder = (*XInfoGroupsCmd)(nil)
  2172  
  2173  func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd {
  2174  	return &XInfoGroupsCmd{
  2175  		baseCmd: baseCmd{
  2176  			ctx:  ctx,
  2177  			args: []interface{}{"xinfo", "groups", stream},
  2178  		},
  2179  	}
  2180  }
  2181  
  2182  func (cmd *XInfoGroupsCmd) SetVal(val []XInfoGroup) {
  2183  	cmd.val = val
  2184  }
  2185  
  2186  func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
  2187  	return cmd.val
  2188  }
  2189  
  2190  func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
  2191  	return cmd.val, cmd.err
  2192  }
  2193  
  2194  func (cmd *XInfoGroupsCmd) String() string {
  2195  	return cmdString(cmd, cmd.val)
  2196  }
  2197  
  2198  func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
  2199  	n, err := rd.ReadArrayLen()
  2200  	if err != nil {
  2201  		return err
  2202  	}
  2203  	cmd.val = make([]XInfoGroup, n)
  2204  
  2205  	for i := 0; i < len(cmd.val); i++ {
  2206  		group := &cmd.val[i]
  2207  
  2208  		nn, err := rd.ReadMapLen()
  2209  		if err != nil {
  2210  			return err
  2211  		}
  2212  
  2213  		var key string
  2214  		for j := 0; j < nn; j++ {
  2215  			key, err = rd.ReadString()
  2216  			if err != nil {
  2217  				return err
  2218  			}
  2219  
  2220  			switch key {
  2221  			case "name":
  2222  				group.Name, err = rd.ReadString()
  2223  				if err != nil {
  2224  					return err
  2225  				}
  2226  			case "consumers":
  2227  				group.Consumers, err = rd.ReadInt()
  2228  				if err != nil {
  2229  					return err
  2230  				}
  2231  			case "pending":
  2232  				group.Pending, err = rd.ReadInt()
  2233  				if err != nil {
  2234  					return err
  2235  				}
  2236  			case "last-delivered-id":
  2237  				group.LastDeliveredID, err = rd.ReadString()
  2238  				if err != nil {
  2239  					return err
  2240  				}
  2241  			case "entries-read":
  2242  				group.EntriesRead, err = rd.ReadInt()
  2243  				if err != nil && err != Nil {
  2244  					return err
  2245  				}
  2246  			case "lag":
  2247  				group.Lag, err = rd.ReadInt()
  2248  
  2249  				// lag: the number of entries in the stream that are still waiting to be delivered
  2250  				// to the group's consumers, or a NULL(Nil) when that number can't be determined.
  2251  				// In that case, we return -1.
  2252  				if err != nil && err != Nil {
  2253  					return err
  2254  				} else if err == Nil {
  2255  					group.Lag = -1
  2256  				}
  2257  			default:
  2258  				return fmt.Errorf("redis: unexpected key %q in XINFO GROUPS reply", key)
  2259  			}
  2260  		}
  2261  	}
  2262  
  2263  	return nil
  2264  }
  2265  
  2266  //------------------------------------------------------------------------------
  2267  
  2268  type XInfoStreamCmd struct {
  2269  	baseCmd
  2270  	val *XInfoStream
  2271  }
  2272  
  2273  type XInfoStream struct {
  2274  	Length               int64
  2275  	RadixTreeKeys        int64
  2276  	RadixTreeNodes       int64
  2277  	Groups               int64
  2278  	LastGeneratedID      string
  2279  	MaxDeletedEntryID    string
  2280  	EntriesAdded         int64
  2281  	FirstEntry           XMessage
  2282  	LastEntry            XMessage
  2283  	RecordedFirstEntryID string
  2284  }
  2285  
  2286  var _ Cmder = (*XInfoStreamCmd)(nil)
  2287  
  2288  func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd {
  2289  	return &XInfoStreamCmd{
  2290  		baseCmd: baseCmd{
  2291  			ctx:  ctx,
  2292  			args: []interface{}{"xinfo", "stream", stream},
  2293  		},
  2294  	}
  2295  }
  2296  
  2297  func (cmd *XInfoStreamCmd) SetVal(val *XInfoStream) {
  2298  	cmd.val = val
  2299  }
  2300  
  2301  func (cmd *XInfoStreamCmd) Val() *XInfoStream {
  2302  	return cmd.val
  2303  }
  2304  
  2305  func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
  2306  	return cmd.val, cmd.err
  2307  }
  2308  
  2309  func (cmd *XInfoStreamCmd) String() string {
  2310  	return cmdString(cmd, cmd.val)
  2311  }
  2312  
  2313  func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
  2314  	n, err := rd.ReadMapLen()
  2315  	if err != nil {
  2316  		return err
  2317  	}
  2318  	cmd.val = &XInfoStream{}
  2319  
  2320  	for i := 0; i < n; i++ {
  2321  		key, err := rd.ReadString()
  2322  		if err != nil {
  2323  			return err
  2324  		}
  2325  		switch key {
  2326  		case "length":
  2327  			cmd.val.Length, err = rd.ReadInt()
  2328  			if err != nil {
  2329  				return err
  2330  			}
  2331  		case "radix-tree-keys":
  2332  			cmd.val.RadixTreeKeys, err = rd.ReadInt()
  2333  			if err != nil {
  2334  				return err
  2335  			}
  2336  		case "radix-tree-nodes":
  2337  			cmd.val.RadixTreeNodes, err = rd.ReadInt()
  2338  			if err != nil {
  2339  				return err
  2340  			}
  2341  		case "groups":
  2342  			cmd.val.Groups, err = rd.ReadInt()
  2343  			if err != nil {
  2344  				return err
  2345  			}
  2346  		case "last-generated-id":
  2347  			cmd.val.LastGeneratedID, err = rd.ReadString()
  2348  			if err != nil {
  2349  				return err
  2350  			}
  2351  		case "max-deleted-entry-id":
  2352  			cmd.val.MaxDeletedEntryID, err = rd.ReadString()
  2353  			if err != nil {
  2354  				return err
  2355  			}
  2356  		case "entries-added":
  2357  			cmd.val.EntriesAdded, err = rd.ReadInt()
  2358  			if err != nil {
  2359  				return err
  2360  			}
  2361  		case "first-entry":
  2362  			cmd.val.FirstEntry, err = readXMessage(rd)
  2363  			if err != nil && err != Nil {
  2364  				return err
  2365  			}
  2366  		case "last-entry":
  2367  			cmd.val.LastEntry, err = readXMessage(rd)
  2368  			if err != nil && err != Nil {
  2369  				return err
  2370  			}
  2371  		case "recorded-first-entry-id":
  2372  			cmd.val.RecordedFirstEntryID, err = rd.ReadString()
  2373  			if err != nil {
  2374  				return err
  2375  			}
  2376  		default:
  2377  			return fmt.Errorf("redis: unexpected key %q in XINFO STREAM reply", key)
  2378  		}
  2379  	}
  2380  	return nil
  2381  }
  2382  
  2383  //------------------------------------------------------------------------------
  2384  
  2385  type XInfoStreamFullCmd struct {
  2386  	baseCmd
  2387  	val *XInfoStreamFull
  2388  }
  2389  
  2390  type XInfoStreamFull struct {
  2391  	Length               int64
  2392  	RadixTreeKeys        int64
  2393  	RadixTreeNodes       int64
  2394  	LastGeneratedID      string
  2395  	MaxDeletedEntryID    string
  2396  	EntriesAdded         int64
  2397  	Entries              []XMessage
  2398  	Groups               []XInfoStreamGroup
  2399  	RecordedFirstEntryID string
  2400  }
  2401  
  2402  type XInfoStreamGroup struct {
  2403  	Name            string
  2404  	LastDeliveredID string
  2405  	EntriesRead     int64
  2406  	Lag             int64
  2407  	PelCount        int64
  2408  	Pending         []XInfoStreamGroupPending
  2409  	Consumers       []XInfoStreamConsumer
  2410  }
  2411  
  2412  type XInfoStreamGroupPending struct {
  2413  	ID            string
  2414  	Consumer      string
  2415  	DeliveryTime  time.Time
  2416  	DeliveryCount int64
  2417  }
  2418  
  2419  type XInfoStreamConsumer struct {
  2420  	Name       string
  2421  	SeenTime   time.Time
  2422  	ActiveTime time.Time
  2423  	PelCount   int64
  2424  	Pending    []XInfoStreamConsumerPending
  2425  }
  2426  
  2427  type XInfoStreamConsumerPending struct {
  2428  	ID            string
  2429  	DeliveryTime  time.Time
  2430  	DeliveryCount int64
  2431  }
  2432  
  2433  var _ Cmder = (*XInfoStreamFullCmd)(nil)
  2434  
  2435  func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XInfoStreamFullCmd {
  2436  	return &XInfoStreamFullCmd{
  2437  		baseCmd: baseCmd{
  2438  			ctx:  ctx,
  2439  			args: args,
  2440  		},
  2441  	}
  2442  }
  2443  
  2444  func (cmd *XInfoStreamFullCmd) SetVal(val *XInfoStreamFull) {
  2445  	cmd.val = val
  2446  }
  2447  
  2448  func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull {
  2449  	return cmd.val
  2450  }
  2451  
  2452  func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) {
  2453  	return cmd.val, cmd.err
  2454  }
  2455  
  2456  func (cmd *XInfoStreamFullCmd) String() string {
  2457  	return cmdString(cmd, cmd.val)
  2458  }
  2459  
  2460  func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error {
  2461  	n, err := rd.ReadMapLen()
  2462  	if err != nil {
  2463  		return err
  2464  	}
  2465  
  2466  	cmd.val = &XInfoStreamFull{}
  2467  
  2468  	for i := 0; i < n; i++ {
  2469  		key, err := rd.ReadString()
  2470  		if err != nil {
  2471  			return err
  2472  		}
  2473  
  2474  		switch key {
  2475  		case "length":
  2476  			cmd.val.Length, err = rd.ReadInt()
  2477  			if err != nil {
  2478  				return err
  2479  			}
  2480  		case "radix-tree-keys":
  2481  			cmd.val.RadixTreeKeys, err = rd.ReadInt()
  2482  			if err != nil {
  2483  				return err
  2484  			}
  2485  		case "radix-tree-nodes":
  2486  			cmd.val.RadixTreeNodes, err = rd.ReadInt()
  2487  			if err != nil {
  2488  				return err
  2489  			}
  2490  		case "last-generated-id":
  2491  			cmd.val.LastGeneratedID, err = rd.ReadString()
  2492  			if err != nil {
  2493  				return err
  2494  			}
  2495  		case "entries-added":
  2496  			cmd.val.EntriesAdded, err = rd.ReadInt()
  2497  			if err != nil {
  2498  				return err
  2499  			}
  2500  		case "entries":
  2501  			cmd.val.Entries, err = readXMessageSlice(rd)
  2502  			if err != nil {
  2503  				return err
  2504  			}
  2505  		case "groups":
  2506  			cmd.val.Groups, err = readStreamGroups(rd)
  2507  			if err != nil {
  2508  				return err
  2509  			}
  2510  		case "max-deleted-entry-id":
  2511  			cmd.val.MaxDeletedEntryID, err = rd.ReadString()
  2512  			if err != nil {
  2513  				return err
  2514  			}
  2515  		case "recorded-first-entry-id":
  2516  			cmd.val.RecordedFirstEntryID, err = rd.ReadString()
  2517  			if err != nil {
  2518  				return err
  2519  			}
  2520  		default:
  2521  			return fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key)
  2522  		}
  2523  	}
  2524  	return nil
  2525  }
  2526  
  2527  func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) {
  2528  	n, err := rd.ReadArrayLen()
  2529  	if err != nil {
  2530  		return nil, err
  2531  	}
  2532  	groups := make([]XInfoStreamGroup, 0, n)
  2533  	for i := 0; i < n; i++ {
  2534  		nn, err := rd.ReadMapLen()
  2535  		if err != nil {
  2536  			return nil, err
  2537  		}
  2538  
  2539  		group := XInfoStreamGroup{}
  2540  
  2541  		for j := 0; j < nn; j++ {
  2542  			key, err := rd.ReadString()
  2543  			if err != nil {
  2544  				return nil, err
  2545  			}
  2546  
  2547  			switch key {
  2548  			case "name":
  2549  				group.Name, err = rd.ReadString()
  2550  				if err != nil {
  2551  					return nil, err
  2552  				}
  2553  			case "last-delivered-id":
  2554  				group.LastDeliveredID, err = rd.ReadString()
  2555  				if err != nil {
  2556  					return nil, err
  2557  				}
  2558  			case "entries-read":
  2559  				group.EntriesRead, err = rd.ReadInt()
  2560  				if err != nil && err != Nil {
  2561  					return nil, err
  2562  				}
  2563  			case "lag":
  2564  				// lag: the number of entries in the stream that are still waiting to be delivered
  2565  				// to the group's consumers, or a NULL(Nil) when that number can't be determined.
  2566  				group.Lag, err = rd.ReadInt()
  2567  				if err != nil && err != Nil {
  2568  					return nil, err
  2569  				}
  2570  			case "pel-count":
  2571  				group.PelCount, err = rd.ReadInt()
  2572  				if err != nil {
  2573  					return nil, err
  2574  				}
  2575  			case "pending":
  2576  				group.Pending, err = readXInfoStreamGroupPending(rd)
  2577  				if err != nil {
  2578  					return nil, err
  2579  				}
  2580  			case "consumers":
  2581  				group.Consumers, err = readXInfoStreamConsumers(rd)
  2582  				if err != nil {
  2583  					return nil, err
  2584  				}
  2585  			default:
  2586  				return nil, fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key)
  2587  			}
  2588  		}
  2589  
  2590  		groups = append(groups, group)
  2591  	}
  2592  
  2593  	return groups, nil
  2594  }
  2595  
  2596  func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPending, error) {
  2597  	n, err := rd.ReadArrayLen()
  2598  	if err != nil {
  2599  		return nil, err
  2600  	}
  2601  
  2602  	pending := make([]XInfoStreamGroupPending, 0, n)
  2603  
  2604  	for i := 0; i < n; i++ {
  2605  		if err = rd.ReadFixedArrayLen(4); err != nil {
  2606  			return nil, err
  2607  		}
  2608  
  2609  		p := XInfoStreamGroupPending{}
  2610  
  2611  		p.ID, err = rd.ReadString()
  2612  		if err != nil {
  2613  			return nil, err
  2614  		}
  2615  
  2616  		p.Consumer, err = rd.ReadString()
  2617  		if err != nil {
  2618  			return nil, err
  2619  		}
  2620  
  2621  		delivery, err := rd.ReadInt()
  2622  		if err != nil {
  2623  			return nil, err
  2624  		}
  2625  		p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
  2626  
  2627  		p.DeliveryCount, err = rd.ReadInt()
  2628  		if err != nil {
  2629  			return nil, err
  2630  		}
  2631  
  2632  		pending = append(pending, p)
  2633  	}
  2634  
  2635  	return pending, nil
  2636  }
  2637  
  2638  func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, error) {
  2639  	n, err := rd.ReadArrayLen()
  2640  	if err != nil {
  2641  		return nil, err
  2642  	}
  2643  
  2644  	consumers := make([]XInfoStreamConsumer, 0, n)
  2645  
  2646  	for i := 0; i < n; i++ {
  2647  		nn, err := rd.ReadMapLen()
  2648  		if err != nil {
  2649  			return nil, err
  2650  		}
  2651  
  2652  		c := XInfoStreamConsumer{}
  2653  
  2654  		for f := 0; f < nn; f++ {
  2655  			cKey, err := rd.ReadString()
  2656  			if err != nil {
  2657  				return nil, err
  2658  			}
  2659  
  2660  			switch cKey {
  2661  			case "name":
  2662  				c.Name, err = rd.ReadString()
  2663  			case "seen-time":
  2664  				seen, err := rd.ReadInt()
  2665  				if err != nil {
  2666  					return nil, err
  2667  				}
  2668  				c.SeenTime = time.UnixMilli(seen)
  2669  			case "active-time":
  2670  				active, err := rd.ReadInt()
  2671  				if err != nil {
  2672  					return nil, err
  2673  				}
  2674  				c.ActiveTime = time.UnixMilli(active)
  2675  			case "pel-count":
  2676  				c.PelCount, err = rd.ReadInt()
  2677  			case "pending":
  2678  				pendingNumber, err := rd.ReadArrayLen()
  2679  				if err != nil {
  2680  					return nil, err
  2681  				}
  2682  
  2683  				c.Pending = make([]XInfoStreamConsumerPending, 0, pendingNumber)
  2684  
  2685  				for pn := 0; pn < pendingNumber; pn++ {
  2686  					if err = rd.ReadFixedArrayLen(3); err != nil {
  2687  						return nil, err
  2688  					}
  2689  
  2690  					p := XInfoStreamConsumerPending{}
  2691  
  2692  					p.ID, err = rd.ReadString()
  2693  					if err != nil {
  2694  						return nil, err
  2695  					}
  2696  
  2697  					delivery, err := rd.ReadInt()
  2698  					if err != nil {
  2699  						return nil, err
  2700  					}
  2701  					p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
  2702  
  2703  					p.DeliveryCount, err = rd.ReadInt()
  2704  					if err != nil {
  2705  						return nil, err
  2706  					}
  2707  
  2708  					c.Pending = append(c.Pending, p)
  2709  				}
  2710  			default:
  2711  				return nil, fmt.Errorf("redis: unexpected content %s "+
  2712  					"in XINFO STREAM FULL reply", cKey)
  2713  			}
  2714  			if err != nil {
  2715  				return nil, err
  2716  			}
  2717  		}
  2718  		consumers = append(consumers, c)
  2719  	}
  2720  
  2721  	return consumers, nil
  2722  }
  2723  
  2724  //------------------------------------------------------------------------------
  2725  
  2726  type ZSliceCmd struct {
  2727  	baseCmd
  2728  
  2729  	val []Z
  2730  }
  2731  
  2732  var _ Cmder = (*ZSliceCmd)(nil)
  2733  
  2734  func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
  2735  	return &ZSliceCmd{
  2736  		baseCmd: baseCmd{
  2737  			ctx:  ctx,
  2738  			args: args,
  2739  		},
  2740  	}
  2741  }
  2742  
  2743  func (cmd *ZSliceCmd) SetVal(val []Z) {
  2744  	cmd.val = val
  2745  }
  2746  
  2747  func (cmd *ZSliceCmd) Val() []Z {
  2748  	return cmd.val
  2749  }
  2750  
  2751  func (cmd *ZSliceCmd) Result() ([]Z, error) {
  2752  	return cmd.val, cmd.err
  2753  }
  2754  
  2755  func (cmd *ZSliceCmd) String() string {
  2756  	return cmdString(cmd, cmd.val)
  2757  }
  2758  
  2759  func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl
  2760  	n, err := rd.ReadArrayLen()
  2761  	if err != nil {
  2762  		return err
  2763  	}
  2764  
  2765  	// If the n is 0, can't continue reading.
  2766  	if n == 0 {
  2767  		cmd.val = make([]Z, 0)
  2768  		return nil
  2769  	}
  2770  
  2771  	typ, err := rd.PeekReplyType()
  2772  	if err != nil {
  2773  		return err
  2774  	}
  2775  	array := typ == proto.RespArray
  2776  
  2777  	if array {
  2778  		cmd.val = make([]Z, n)
  2779  	} else {
  2780  		cmd.val = make([]Z, n/2)
  2781  	}
  2782  
  2783  	for i := 0; i < len(cmd.val); i++ {
  2784  		if array {
  2785  			if err = rd.ReadFixedArrayLen(2); err != nil {
  2786  				return err
  2787  			}
  2788  		}
  2789  
  2790  		if cmd.val[i].Member, err = rd.ReadString(); err != nil {
  2791  			return err
  2792  		}
  2793  
  2794  		if cmd.val[i].Score, err = rd.ReadFloat(); err != nil {
  2795  			return err
  2796  		}
  2797  	}
  2798  
  2799  	return nil
  2800  }
  2801  
  2802  //------------------------------------------------------------------------------
  2803  
  2804  type ZWithKeyCmd struct {
  2805  	baseCmd
  2806  
  2807  	val *ZWithKey
  2808  }
  2809  
  2810  var _ Cmder = (*ZWithKeyCmd)(nil)
  2811  
  2812  func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd {
  2813  	return &ZWithKeyCmd{
  2814  		baseCmd: baseCmd{
  2815  			ctx:  ctx,
  2816  			args: args,
  2817  		},
  2818  	}
  2819  }
  2820  
  2821  func (cmd *ZWithKeyCmd) SetVal(val *ZWithKey) {
  2822  	cmd.val = val
  2823  }
  2824  
  2825  func (cmd *ZWithKeyCmd) Val() *ZWithKey {
  2826  	return cmd.val
  2827  }
  2828  
  2829  func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
  2830  	return cmd.val, cmd.err
  2831  }
  2832  
  2833  func (cmd *ZWithKeyCmd) String() string {
  2834  	return cmdString(cmd, cmd.val)
  2835  }
  2836  
  2837  func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) (err error) {
  2838  	if err = rd.ReadFixedArrayLen(3); err != nil {
  2839  		return err
  2840  	}
  2841  	cmd.val = &ZWithKey{}
  2842  
  2843  	if cmd.val.Key, err = rd.ReadString(); err != nil {
  2844  		return err
  2845  	}
  2846  	if cmd.val.Member, err = rd.ReadString(); err != nil {
  2847  		return err
  2848  	}
  2849  	if cmd.val.Score, err = rd.ReadFloat(); err != nil {
  2850  		return err
  2851  	}
  2852  
  2853  	return nil
  2854  }
  2855  
  2856  //------------------------------------------------------------------------------
  2857  
  2858  type ScanCmd struct {
  2859  	baseCmd
  2860  
  2861  	page   []string
  2862  	cursor uint64
  2863  
  2864  	process cmdable
  2865  }
  2866  
  2867  var _ Cmder = (*ScanCmd)(nil)
  2868  
  2869  func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd {
  2870  	return &ScanCmd{
  2871  		baseCmd: baseCmd{
  2872  			ctx:  ctx,
  2873  			args: args,
  2874  		},
  2875  		process: process,
  2876  	}
  2877  }
  2878  
  2879  func (cmd *ScanCmd) SetVal(page []string, cursor uint64) {
  2880  	cmd.page = page
  2881  	cmd.cursor = cursor
  2882  }
  2883  
  2884  func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
  2885  	return cmd.page, cmd.cursor
  2886  }
  2887  
  2888  func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
  2889  	return cmd.page, cmd.cursor, cmd.err
  2890  }
  2891  
  2892  func (cmd *ScanCmd) String() string {
  2893  	return cmdString(cmd, cmd.page)
  2894  }
  2895  
  2896  func (cmd *ScanCmd) readReply(rd *proto.Reader) error {
  2897  	if err := rd.ReadFixedArrayLen(2); err != nil {
  2898  		return err
  2899  	}
  2900  
  2901  	cursor, err := rd.ReadUint()
  2902  	if err != nil {
  2903  		return err
  2904  	}
  2905  	cmd.cursor = cursor
  2906  
  2907  	n, err := rd.ReadArrayLen()
  2908  	if err != nil {
  2909  		return err
  2910  	}
  2911  	cmd.page = make([]string, n)
  2912  
  2913  	for i := 0; i < len(cmd.page); i++ {
  2914  		if cmd.page[i], err = rd.ReadString(); err != nil {
  2915  			return err
  2916  		}
  2917  	}
  2918  	return nil
  2919  }
  2920  
  2921  // Iterator creates a new ScanIterator.
  2922  func (cmd *ScanCmd) Iterator() *ScanIterator {
  2923  	return &ScanIterator{
  2924  		cmd: cmd,
  2925  	}
  2926  }
  2927  
  2928  //------------------------------------------------------------------------------
  2929  
  2930  type ClusterNode struct {
  2931  	ID                 string
  2932  	Addr               string
  2933  	NetworkingMetadata map[string]string
  2934  }
  2935  
  2936  type ClusterSlot struct {
  2937  	Start int
  2938  	End   int
  2939  	Nodes []ClusterNode
  2940  }
  2941  
  2942  type ClusterSlotsCmd struct {
  2943  	baseCmd
  2944  
  2945  	val []ClusterSlot
  2946  }
  2947  
  2948  var _ Cmder = (*ClusterSlotsCmd)(nil)
  2949  
  2950  func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd {
  2951  	return &ClusterSlotsCmd{
  2952  		baseCmd: baseCmd{
  2953  			ctx:  ctx,
  2954  			args: args,
  2955  		},
  2956  	}
  2957  }
  2958  
  2959  func (cmd *ClusterSlotsCmd) SetVal(val []ClusterSlot) {
  2960  	cmd.val = val
  2961  }
  2962  
  2963  func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
  2964  	return cmd.val
  2965  }
  2966  
  2967  func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
  2968  	return cmd.val, cmd.err
  2969  }
  2970  
  2971  func (cmd *ClusterSlotsCmd) String() string {
  2972  	return cmdString(cmd, cmd.val)
  2973  }
  2974  
  2975  func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
  2976  	n, err := rd.ReadArrayLen()
  2977  	if err != nil {
  2978  		return err
  2979  	}
  2980  	cmd.val = make([]ClusterSlot, n)
  2981  
  2982  	for i := 0; i < len(cmd.val); i++ {
  2983  		n, err = rd.ReadArrayLen()
  2984  		if err != nil {
  2985  			return err
  2986  		}
  2987  		if n < 2 {
  2988  			return fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
  2989  		}
  2990  
  2991  		start, err := rd.ReadInt()
  2992  		if err != nil {
  2993  			return err
  2994  		}
  2995  
  2996  		end, err := rd.ReadInt()
  2997  		if err != nil {
  2998  			return err
  2999  		}
  3000  
  3001  		// subtract start and end.
  3002  		nodes := make([]ClusterNode, n-2)
  3003  
  3004  		for j := 0; j < len(nodes); j++ {
  3005  			nn, err := rd.ReadArrayLen()
  3006  			if err != nil {
  3007  				return err
  3008  			}
  3009  			if nn < 2 || nn > 4 {
  3010  				return fmt.Errorf("got %d elements in cluster info address, expected 2, 3, or 4", n)
  3011  			}
  3012  
  3013  			ip, err := rd.ReadString()
  3014  			if err != nil {
  3015  				return err
  3016  			}
  3017  
  3018  			port, err := rd.ReadString()
  3019  			if err != nil {
  3020  				return err
  3021  			}
  3022  
  3023  			nodes[j].Addr = net.JoinHostPort(ip, port)
  3024  
  3025  			if nn >= 3 {
  3026  				id, err := rd.ReadString()
  3027  				if err != nil {
  3028  					return err
  3029  				}
  3030  				nodes[j].ID = id
  3031  			}
  3032  
  3033  			if nn >= 4 {
  3034  				metadataLength, err := rd.ReadMapLen()
  3035  				if err != nil {
  3036  					return err
  3037  				}
  3038  
  3039  				networkingMetadata := make(map[string]string, metadataLength)
  3040  
  3041  				for i := 0; i < metadataLength; i++ {
  3042  					key, err := rd.ReadString()
  3043  					if err != nil {
  3044  						return err
  3045  					}
  3046  					value, err := rd.ReadString()
  3047  					if err != nil {
  3048  						return err
  3049  					}
  3050  					networkingMetadata[key] = value
  3051  				}
  3052  
  3053  				nodes[j].NetworkingMetadata = networkingMetadata
  3054  			}
  3055  		}
  3056  
  3057  		cmd.val[i] = ClusterSlot{
  3058  			Start: int(start),
  3059  			End:   int(end),
  3060  			Nodes: nodes,
  3061  		}
  3062  	}
  3063  
  3064  	return nil
  3065  }
  3066  
  3067  //------------------------------------------------------------------------------
  3068  
  3069  // GeoLocation is used with GeoAdd to add geospatial location.
  3070  type GeoLocation struct {
  3071  	Name                      string
  3072  	Longitude, Latitude, Dist float64
  3073  	GeoHash                   int64
  3074  }
  3075  
  3076  // GeoRadiusQuery is used with GeoRadius to query geospatial index.
  3077  type GeoRadiusQuery struct {
  3078  	Radius float64
  3079  	// Can be m, km, ft, or mi. Default is km.
  3080  	Unit        string
  3081  	WithCoord   bool
  3082  	WithDist    bool
  3083  	WithGeoHash bool
  3084  	Count       int
  3085  	// Can be ASC or DESC. Default is no sort order.
  3086  	Sort      string
  3087  	Store     string
  3088  	StoreDist string
  3089  
  3090  	// WithCoord+WithDist+WithGeoHash
  3091  	withLen int
  3092  }
  3093  
  3094  type GeoLocationCmd struct {
  3095  	baseCmd
  3096  
  3097  	q         *GeoRadiusQuery
  3098  	locations []GeoLocation
  3099  }
  3100  
  3101  var _ Cmder = (*GeoLocationCmd)(nil)
  3102  
  3103  func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
  3104  	return &GeoLocationCmd{
  3105  		baseCmd: baseCmd{
  3106  			ctx:  ctx,
  3107  			args: geoLocationArgs(q, args...),
  3108  		},
  3109  		q: q,
  3110  	}
  3111  }
  3112  
  3113  func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} {
  3114  	args = append(args, q.Radius)
  3115  	if q.Unit != "" {
  3116  		args = append(args, q.Unit)
  3117  	} else {
  3118  		args = append(args, "km")
  3119  	}
  3120  	if q.WithCoord {
  3121  		args = append(args, "withcoord")
  3122  		q.withLen++
  3123  	}
  3124  	if q.WithDist {
  3125  		args = append(args, "withdist")
  3126  		q.withLen++
  3127  	}
  3128  	if q.WithGeoHash {
  3129  		args = append(args, "withhash")
  3130  		q.withLen++
  3131  	}
  3132  	if q.Count > 0 {
  3133  		args = append(args, "count", q.Count)
  3134  	}
  3135  	if q.Sort != "" {
  3136  		args = append(args, q.Sort)
  3137  	}
  3138  	if q.Store != "" {
  3139  		args = append(args, "store")
  3140  		args = append(args, q.Store)
  3141  	}
  3142  	if q.StoreDist != "" {
  3143  		args = append(args, "storedist")
  3144  		args = append(args, q.StoreDist)
  3145  	}
  3146  	return args
  3147  }
  3148  
  3149  func (cmd *GeoLocationCmd) SetVal(locations []GeoLocation) {
  3150  	cmd.locations = locations
  3151  }
  3152  
  3153  func (cmd *GeoLocationCmd) Val() []GeoLocation {
  3154  	return cmd.locations
  3155  }
  3156  
  3157  func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
  3158  	return cmd.locations, cmd.err
  3159  }
  3160  
  3161  func (cmd *GeoLocationCmd) String() string {
  3162  	return cmdString(cmd, cmd.locations)
  3163  }
  3164  
  3165  func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
  3166  	n, err := rd.ReadArrayLen()
  3167  	if err != nil {
  3168  		return err
  3169  	}
  3170  	cmd.locations = make([]GeoLocation, n)
  3171  
  3172  	for i := 0; i < len(cmd.locations); i++ {
  3173  		// only name
  3174  		if cmd.q.withLen == 0 {
  3175  			if cmd.locations[i].Name, err = rd.ReadString(); err != nil {
  3176  				return err
  3177  			}
  3178  			continue
  3179  		}
  3180  
  3181  		// +name
  3182  		if err = rd.ReadFixedArrayLen(cmd.q.withLen + 1); err != nil {
  3183  			return err
  3184  		}
  3185  
  3186  		if cmd.locations[i].Name, err = rd.ReadString(); err != nil {
  3187  			return err
  3188  		}
  3189  		if cmd.q.WithDist {
  3190  			if cmd.locations[i].Dist, err = rd.ReadFloat(); err != nil {
  3191  				return err
  3192  			}
  3193  		}
  3194  		if cmd.q.WithGeoHash {
  3195  			if cmd.locations[i].GeoHash, err = rd.ReadInt(); err != nil {
  3196  				return err
  3197  			}
  3198  		}
  3199  		if cmd.q.WithCoord {
  3200  			if err = rd.ReadFixedArrayLen(2); err != nil {
  3201  				return err
  3202  			}
  3203  			if cmd.locations[i].Longitude, err = rd.ReadFloat(); err != nil {
  3204  				return err
  3205  			}
  3206  			if cmd.locations[i].Latitude, err = rd.ReadFloat(); err != nil {
  3207  				return err
  3208  			}
  3209  		}
  3210  	}
  3211  
  3212  	return nil
  3213  }
  3214  
  3215  //------------------------------------------------------------------------------
  3216  
  3217  // GeoSearchQuery is used for GEOSearch/GEOSearchStore command query.
  3218  type GeoSearchQuery struct {
  3219  	Member string
  3220  
  3221  	// Latitude and Longitude when using FromLonLat option.
  3222  	Longitude float64
  3223  	Latitude  float64
  3224  
  3225  	// Distance and unit when using ByRadius option.
  3226  	// Can use m, km, ft, or mi. Default is km.
  3227  	Radius     float64
  3228  	RadiusUnit string
  3229  
  3230  	// Height, width and unit when using ByBox option.
  3231  	// Can be m, km, ft, or mi. Default is km.
  3232  	BoxWidth  float64
  3233  	BoxHeight float64
  3234  	BoxUnit   string
  3235  
  3236  	// Can be ASC or DESC. Default is no sort order.
  3237  	Sort     string
  3238  	Count    int
  3239  	CountAny bool
  3240  }
  3241  
  3242  type GeoSearchLocationQuery struct {
  3243  	GeoSearchQuery
  3244  
  3245  	WithCoord bool
  3246  	WithDist  bool
  3247  	WithHash  bool
  3248  }
  3249  
  3250  type GeoSearchStoreQuery struct {
  3251  	GeoSearchQuery
  3252  
  3253  	// When using the StoreDist option, the command stores the items in a
  3254  	// sorted set populated with their distance from the center of the circle or box,
  3255  	// as a floating-point number, in the same unit specified for that shape.
  3256  	StoreDist bool
  3257  }
  3258  
  3259  func geoSearchLocationArgs(q *GeoSearchLocationQuery, args []interface{}) []interface{} {
  3260  	args = geoSearchArgs(&q.GeoSearchQuery, args)
  3261  
  3262  	if q.WithCoord {
  3263  		args = append(args, "withcoord")
  3264  	}
  3265  	if q.WithDist {
  3266  		args = append(args, "withdist")
  3267  	}
  3268  	if q.WithHash {
  3269  		args = append(args, "withhash")
  3270  	}
  3271  
  3272  	return args
  3273  }
  3274  
  3275  func geoSearchArgs(q *GeoSearchQuery, args []interface{}) []interface{} {
  3276  	if q.Member != "" {
  3277  		args = append(args, "frommember", q.Member)
  3278  	} else {
  3279  		args = append(args, "fromlonlat", q.Longitude, q.Latitude)
  3280  	}
  3281  
  3282  	if q.Radius > 0 {
  3283  		if q.RadiusUnit == "" {
  3284  			q.RadiusUnit = "km"
  3285  		}
  3286  		args = append(args, "byradius", q.Radius, q.RadiusUnit)
  3287  	} else {
  3288  		if q.BoxUnit == "" {
  3289  			q.BoxUnit = "km"
  3290  		}
  3291  		args = append(args, "bybox", q.BoxWidth, q.BoxHeight, q.BoxUnit)
  3292  	}
  3293  
  3294  	if q.Sort != "" {
  3295  		args = append(args, q.Sort)
  3296  	}
  3297  
  3298  	if q.Count > 0 {
  3299  		args = append(args, "count", q.Count)
  3300  		if q.CountAny {
  3301  			args = append(args, "any")
  3302  		}
  3303  	}
  3304  
  3305  	return args
  3306  }
  3307  
  3308  type GeoSearchLocationCmd struct {
  3309  	baseCmd
  3310  
  3311  	opt *GeoSearchLocationQuery
  3312  	val []GeoLocation
  3313  }
  3314  
  3315  var _ Cmder = (*GeoSearchLocationCmd)(nil)
  3316  
  3317  func NewGeoSearchLocationCmd(
  3318  	ctx context.Context, opt *GeoSearchLocationQuery, args ...interface{},
  3319  ) *GeoSearchLocationCmd {
  3320  	return &GeoSearchLocationCmd{
  3321  		baseCmd: baseCmd{
  3322  			ctx:  ctx,
  3323  			args: args,
  3324  		},
  3325  		opt: opt,
  3326  	}
  3327  }
  3328  
  3329  func (cmd *GeoSearchLocationCmd) SetVal(val []GeoLocation) {
  3330  	cmd.val = val
  3331  }
  3332  
  3333  func (cmd *GeoSearchLocationCmd) Val() []GeoLocation {
  3334  	return cmd.val
  3335  }
  3336  
  3337  func (cmd *GeoSearchLocationCmd) Result() ([]GeoLocation, error) {
  3338  	return cmd.val, cmd.err
  3339  }
  3340  
  3341  func (cmd *GeoSearchLocationCmd) String() string {
  3342  	return cmdString(cmd, cmd.val)
  3343  }
  3344  
  3345  func (cmd *GeoSearchLocationCmd) readReply(rd *proto.Reader) error {
  3346  	n, err := rd.ReadArrayLen()
  3347  	if err != nil {
  3348  		return err
  3349  	}
  3350  
  3351  	cmd.val = make([]GeoLocation, n)
  3352  	for i := 0; i < n; i++ {
  3353  		_, err = rd.ReadArrayLen()
  3354  		if err != nil {
  3355  			return err
  3356  		}
  3357  
  3358  		var loc GeoLocation
  3359  
  3360  		loc.Name, err = rd.ReadString()
  3361  		if err != nil {
  3362  			return err
  3363  		}
  3364  		if cmd.opt.WithDist {
  3365  			loc.Dist, err = rd.ReadFloat()
  3366  			if err != nil {
  3367  				return err
  3368  			}
  3369  		}
  3370  		if cmd.opt.WithHash {
  3371  			loc.GeoHash, err = rd.ReadInt()
  3372  			if err != nil {
  3373  				return err
  3374  			}
  3375  		}
  3376  		if cmd.opt.WithCoord {
  3377  			if err = rd.ReadFixedArrayLen(2); err != nil {
  3378  				return err
  3379  			}
  3380  			loc.Longitude, err = rd.ReadFloat()
  3381  			if err != nil {
  3382  				return err
  3383  			}
  3384  			loc.Latitude, err = rd.ReadFloat()
  3385  			if err != nil {
  3386  				return err
  3387  			}
  3388  		}
  3389  
  3390  		cmd.val[i] = loc
  3391  	}
  3392  
  3393  	return nil
  3394  }
  3395  
  3396  //------------------------------------------------------------------------------
  3397  
  3398  type GeoPos struct {
  3399  	Longitude, Latitude float64
  3400  }
  3401  
  3402  type GeoPosCmd struct {
  3403  	baseCmd
  3404  
  3405  	val []*GeoPos
  3406  }
  3407  
  3408  var _ Cmder = (*GeoPosCmd)(nil)
  3409  
  3410  func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
  3411  	return &GeoPosCmd{
  3412  		baseCmd: baseCmd{
  3413  			ctx:  ctx,
  3414  			args: args,
  3415  		},
  3416  	}
  3417  }
  3418  
  3419  func (cmd *GeoPosCmd) SetVal(val []*GeoPos) {
  3420  	cmd.val = val
  3421  }
  3422  
  3423  func (cmd *GeoPosCmd) Val() []*GeoPos {
  3424  	return cmd.val
  3425  }
  3426  
  3427  func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
  3428  	return cmd.val, cmd.err
  3429  }
  3430  
  3431  func (cmd *GeoPosCmd) String() string {
  3432  	return cmdString(cmd, cmd.val)
  3433  }
  3434  
  3435  func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
  3436  	n, err := rd.ReadArrayLen()
  3437  	if err != nil {
  3438  		return err
  3439  	}
  3440  	cmd.val = make([]*GeoPos, n)
  3441  
  3442  	for i := 0; i < len(cmd.val); i++ {
  3443  		err = rd.ReadFixedArrayLen(2)
  3444  		if err != nil {
  3445  			if err == Nil {
  3446  				cmd.val[i] = nil
  3447  				continue
  3448  			}
  3449  			return err
  3450  		}
  3451  
  3452  		longitude, err := rd.ReadFloat()
  3453  		if err != nil {
  3454  			return err
  3455  		}
  3456  		latitude, err := rd.ReadFloat()
  3457  		if err != nil {
  3458  			return err
  3459  		}
  3460  
  3461  		cmd.val[i] = &GeoPos{
  3462  			Longitude: longitude,
  3463  			Latitude:  latitude,
  3464  		}
  3465  	}
  3466  
  3467  	return nil
  3468  }
  3469  
  3470  //------------------------------------------------------------------------------
  3471  
  3472  type CommandInfo struct {
  3473  	Name        string
  3474  	Arity       int8
  3475  	Flags       []string
  3476  	ACLFlags    []string
  3477  	FirstKeyPos int8
  3478  	LastKeyPos  int8
  3479  	StepCount   int8
  3480  	ReadOnly    bool
  3481  }
  3482  
  3483  type CommandsInfoCmd struct {
  3484  	baseCmd
  3485  
  3486  	val map[string]*CommandInfo
  3487  }
  3488  
  3489  var _ Cmder = (*CommandsInfoCmd)(nil)
  3490  
  3491  func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd {
  3492  	return &CommandsInfoCmd{
  3493  		baseCmd: baseCmd{
  3494  			ctx:  ctx,
  3495  			args: args,
  3496  		},
  3497  	}
  3498  }
  3499  
  3500  func (cmd *CommandsInfoCmd) SetVal(val map[string]*CommandInfo) {
  3501  	cmd.val = val
  3502  }
  3503  
  3504  func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
  3505  	return cmd.val
  3506  }
  3507  
  3508  func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
  3509  	return cmd.val, cmd.err
  3510  }
  3511  
  3512  func (cmd *CommandsInfoCmd) String() string {
  3513  	return cmdString(cmd, cmd.val)
  3514  }
  3515  
  3516  func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
  3517  	const numArgRedis5 = 6
  3518  	const numArgRedis6 = 7
  3519  	const numArgRedis7 = 10
  3520  
  3521  	n, err := rd.ReadArrayLen()
  3522  	if err != nil {
  3523  		return err
  3524  	}
  3525  	cmd.val = make(map[string]*CommandInfo, n)
  3526  
  3527  	for i := 0; i < n; i++ {
  3528  		nn, err := rd.ReadArrayLen()
  3529  		if err != nil {
  3530  			return err
  3531  		}
  3532  
  3533  		switch nn {
  3534  		case numArgRedis5, numArgRedis6, numArgRedis7:
  3535  			// ok
  3536  		default:
  3537  			return fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 6/7/10", nn)
  3538  		}
  3539  
  3540  		cmdInfo := &CommandInfo{}
  3541  		if cmdInfo.Name, err = rd.ReadString(); err != nil {
  3542  			return err
  3543  		}
  3544  
  3545  		arity, err := rd.ReadInt()
  3546  		if err != nil {
  3547  			return err
  3548  		}
  3549  		cmdInfo.Arity = int8(arity)
  3550  
  3551  		flagLen, err := rd.ReadArrayLen()
  3552  		if err != nil {
  3553  			return err
  3554  		}
  3555  		cmdInfo.Flags = make([]string, flagLen)
  3556  		for f := 0; f < len(cmdInfo.Flags); f++ {
  3557  			switch s, err := rd.ReadString(); {
  3558  			case err == Nil:
  3559  				cmdInfo.Flags[f] = ""
  3560  			case err != nil:
  3561  				return err
  3562  			default:
  3563  				if !cmdInfo.ReadOnly && s == "readonly" {
  3564  					cmdInfo.ReadOnly = true
  3565  				}
  3566  				cmdInfo.Flags[f] = s
  3567  			}
  3568  		}
  3569  
  3570  		firstKeyPos, err := rd.ReadInt()
  3571  		if err != nil {
  3572  			return err
  3573  		}
  3574  		cmdInfo.FirstKeyPos = int8(firstKeyPos)
  3575  
  3576  		lastKeyPos, err := rd.ReadInt()
  3577  		if err != nil {
  3578  			return err
  3579  		}
  3580  		cmdInfo.LastKeyPos = int8(lastKeyPos)
  3581  
  3582  		stepCount, err := rd.ReadInt()
  3583  		if err != nil {
  3584  			return err
  3585  		}
  3586  		cmdInfo.StepCount = int8(stepCount)
  3587  
  3588  		if nn >= numArgRedis6 {
  3589  			aclFlagLen, err := rd.ReadArrayLen()
  3590  			if err != nil {
  3591  				return err
  3592  			}
  3593  			cmdInfo.ACLFlags = make([]string, aclFlagLen)
  3594  			for f := 0; f < len(cmdInfo.ACLFlags); f++ {
  3595  				switch s, err := rd.ReadString(); {
  3596  				case err == Nil:
  3597  					cmdInfo.ACLFlags[f] = ""
  3598  				case err != nil:
  3599  					return err
  3600  				default:
  3601  					cmdInfo.ACLFlags[f] = s
  3602  				}
  3603  			}
  3604  		}
  3605  
  3606  		if nn >= numArgRedis7 {
  3607  			if err := rd.DiscardNext(); err != nil {
  3608  				return err
  3609  			}
  3610  			if err := rd.DiscardNext(); err != nil {
  3611  				return err
  3612  			}
  3613  			if err := rd.DiscardNext(); err != nil {
  3614  				return err
  3615  			}
  3616  		}
  3617  
  3618  		cmd.val[cmdInfo.Name] = cmdInfo
  3619  	}
  3620  
  3621  	return nil
  3622  }
  3623  
  3624  //------------------------------------------------------------------------------
  3625  
  3626  type cmdsInfoCache struct {
  3627  	fn func(ctx context.Context) (map[string]*CommandInfo, error)
  3628  
  3629  	once internal.Once
  3630  	cmds map[string]*CommandInfo
  3631  }
  3632  
  3633  func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache {
  3634  	return &cmdsInfoCache{
  3635  		fn: fn,
  3636  	}
  3637  }
  3638  
  3639  func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) {
  3640  	err := c.once.Do(func() error {
  3641  		cmds, err := c.fn(ctx)
  3642  		if err != nil {
  3643  			return err
  3644  		}
  3645  
  3646  		lowerCmds := make(map[string]*CommandInfo, len(cmds))
  3647  
  3648  		// Extensions have cmd names in upper case. Convert them to lower case.
  3649  		for k, v := range cmds {
  3650  			lowerCmds[internal.ToLower(k)] = v
  3651  		}
  3652  
  3653  		c.cmds = lowerCmds
  3654  		return nil
  3655  	})
  3656  	return c.cmds, err
  3657  }
  3658  
  3659  //------------------------------------------------------------------------------
  3660  
  3661  type SlowLog struct {
  3662  	ID       int64
  3663  	Time     time.Time
  3664  	Duration time.Duration
  3665  	Args     []string
  3666  	// These are also optional fields emitted only by Redis 4.0 or greater:
  3667  	// https://redis.io/commands/slowlog#output-format
  3668  	ClientAddr string
  3669  	ClientName string
  3670  }
  3671  
  3672  type SlowLogCmd struct {
  3673  	baseCmd
  3674  
  3675  	val []SlowLog
  3676  }
  3677  
  3678  var _ Cmder = (*SlowLogCmd)(nil)
  3679  
  3680  func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
  3681  	return &SlowLogCmd{
  3682  		baseCmd: baseCmd{
  3683  			ctx:  ctx,
  3684  			args: args,
  3685  		},
  3686  	}
  3687  }
  3688  
  3689  func (cmd *SlowLogCmd) SetVal(val []SlowLog) {
  3690  	cmd.val = val
  3691  }
  3692  
  3693  func (cmd *SlowLogCmd) Val() []SlowLog {
  3694  	return cmd.val
  3695  }
  3696  
  3697  func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
  3698  	return cmd.val, cmd.err
  3699  }
  3700  
  3701  func (cmd *SlowLogCmd) String() string {
  3702  	return cmdString(cmd, cmd.val)
  3703  }
  3704  
  3705  func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
  3706  	n, err := rd.ReadArrayLen()
  3707  	if err != nil {
  3708  		return err
  3709  	}
  3710  	cmd.val = make([]SlowLog, n)
  3711  
  3712  	for i := 0; i < len(cmd.val); i++ {
  3713  		nn, err := rd.ReadArrayLen()
  3714  		if err != nil {
  3715  			return err
  3716  		}
  3717  		if nn < 4 {
  3718  			return fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", nn)
  3719  		}
  3720  
  3721  		if cmd.val[i].ID, err = rd.ReadInt(); err != nil {
  3722  			return err
  3723  		}
  3724  
  3725  		createdAt, err := rd.ReadInt()
  3726  		if err != nil {
  3727  			return err
  3728  		}
  3729  		cmd.val[i].Time = time.Unix(createdAt, 0)
  3730  
  3731  		costs, err := rd.ReadInt()
  3732  		if err != nil {
  3733  			return err
  3734  		}
  3735  		cmd.val[i].Duration = time.Duration(costs) * time.Microsecond
  3736  
  3737  		cmdLen, err := rd.ReadArrayLen()
  3738  		if err != nil {
  3739  			return err
  3740  		}
  3741  		if cmdLen < 1 {
  3742  			return fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
  3743  		}
  3744  
  3745  		cmd.val[i].Args = make([]string, cmdLen)
  3746  		for f := 0; f < len(cmd.val[i].Args); f++ {
  3747  			cmd.val[i].Args[f], err = rd.ReadString()
  3748  			if err != nil {
  3749  				return err
  3750  			}
  3751  		}
  3752  
  3753  		if nn >= 5 {
  3754  			if cmd.val[i].ClientAddr, err = rd.ReadString(); err != nil {
  3755  				return err
  3756  			}
  3757  		}
  3758  
  3759  		if nn >= 6 {
  3760  			if cmd.val[i].ClientName, err = rd.ReadString(); err != nil {
  3761  				return err
  3762  			}
  3763  		}
  3764  	}
  3765  
  3766  	return nil
  3767  }
  3768  
  3769  //-----------------------------------------------------------------------
  3770  
  3771  type MapStringInterfaceCmd struct {
  3772  	baseCmd
  3773  
  3774  	val map[string]interface{}
  3775  }
  3776  
  3777  var _ Cmder = (*MapStringInterfaceCmd)(nil)
  3778  
  3779  func NewMapStringInterfaceCmd(ctx context.Context, args ...interface{}) *MapStringInterfaceCmd {
  3780  	return &MapStringInterfaceCmd{
  3781  		baseCmd: baseCmd{
  3782  			ctx:  ctx,
  3783  			args: args,
  3784  		},
  3785  	}
  3786  }
  3787  
  3788  func (cmd *MapStringInterfaceCmd) SetVal(val map[string]interface{}) {
  3789  	cmd.val = val
  3790  }
  3791  
  3792  func (cmd *MapStringInterfaceCmd) Val() map[string]interface{} {
  3793  	return cmd.val
  3794  }
  3795  
  3796  func (cmd *MapStringInterfaceCmd) Result() (map[string]interface{}, error) {
  3797  	return cmd.val, cmd.err
  3798  }
  3799  
  3800  func (cmd *MapStringInterfaceCmd) String() string {
  3801  	return cmdString(cmd, cmd.val)
  3802  }
  3803  
  3804  func (cmd *MapStringInterfaceCmd) readReply(rd *proto.Reader) error {
  3805  	n, err := rd.ReadMapLen()
  3806  	if err != nil {
  3807  		return err
  3808  	}
  3809  
  3810  	cmd.val = make(map[string]interface{}, n)
  3811  	for i := 0; i < n; i++ {
  3812  		k, err := rd.ReadString()
  3813  		if err != nil {
  3814  			return err
  3815  		}
  3816  		v, err := rd.ReadReply()
  3817  		if err != nil {
  3818  			if err == Nil {
  3819  				cmd.val[k] = Nil
  3820  				continue
  3821  			}
  3822  			if err, ok := err.(proto.RedisError); ok {
  3823  				cmd.val[k] = err
  3824  				continue
  3825  			}
  3826  			return err
  3827  		}
  3828  		cmd.val[k] = v
  3829  	}
  3830  	return nil
  3831  }
  3832  
  3833  //-----------------------------------------------------------------------
  3834  
  3835  type MapStringStringSliceCmd struct {
  3836  	baseCmd
  3837  
  3838  	val []map[string]string
  3839  }
  3840  
  3841  var _ Cmder = (*MapStringStringSliceCmd)(nil)
  3842  
  3843  func NewMapStringStringSliceCmd(ctx context.Context, args ...interface{}) *MapStringStringSliceCmd {
  3844  	return &MapStringStringSliceCmd{
  3845  		baseCmd: baseCmd{
  3846  			ctx:  ctx,
  3847  			args: args,
  3848  		},
  3849  	}
  3850  }
  3851  
  3852  func (cmd *MapStringStringSliceCmd) SetVal(val []map[string]string) {
  3853  	cmd.val = val
  3854  }
  3855  
  3856  func (cmd *MapStringStringSliceCmd) Val() []map[string]string {
  3857  	return cmd.val
  3858  }
  3859  
  3860  func (cmd *MapStringStringSliceCmd) Result() ([]map[string]string, error) {
  3861  	return cmd.val, cmd.err
  3862  }
  3863  
  3864  func (cmd *MapStringStringSliceCmd) String() string {
  3865  	return cmdString(cmd, cmd.val)
  3866  }
  3867  
  3868  func (cmd *MapStringStringSliceCmd) readReply(rd *proto.Reader) error {
  3869  	n, err := rd.ReadArrayLen()
  3870  	if err != nil {
  3871  		return err
  3872  	}
  3873  
  3874  	cmd.val = make([]map[string]string, n)
  3875  	for i := 0; i < n; i++ {
  3876  		nn, err := rd.ReadMapLen()
  3877  		if err != nil {
  3878  			return err
  3879  		}
  3880  		cmd.val[i] = make(map[string]string, nn)
  3881  		for f := 0; f < nn; f++ {
  3882  			k, err := rd.ReadString()
  3883  			if err != nil {
  3884  				return err
  3885  			}
  3886  
  3887  			v, err := rd.ReadString()
  3888  			if err != nil {
  3889  				return err
  3890  			}
  3891  			cmd.val[i][k] = v
  3892  		}
  3893  	}
  3894  	return nil
  3895  }
  3896  
  3897  // -----------------------------------------------------------------------
  3898  
  3899  // MapMapStringInterfaceCmd represents a command that returns a map of strings to interface{}.
  3900  type MapMapStringInterfaceCmd struct {
  3901  	baseCmd
  3902  	val map[string]interface{}
  3903  }
  3904  
  3905  func NewMapMapStringInterfaceCmd(ctx context.Context, args ...interface{}) *MapMapStringInterfaceCmd {
  3906  	return &MapMapStringInterfaceCmd{
  3907  		baseCmd: baseCmd{
  3908  			ctx:  ctx,
  3909  			args: args,
  3910  		},
  3911  	}
  3912  }
  3913  
  3914  func (cmd *MapMapStringInterfaceCmd) String() string {
  3915  	return cmdString(cmd, cmd.val)
  3916  }
  3917  
  3918  func (cmd *MapMapStringInterfaceCmd) SetVal(val map[string]interface{}) {
  3919  	cmd.val = val
  3920  }
  3921  
  3922  func (cmd *MapMapStringInterfaceCmd) Result() (map[string]interface{}, error) {
  3923  	return cmd.val, cmd.err
  3924  }
  3925  
  3926  func (cmd *MapMapStringInterfaceCmd) Val() map[string]interface{} {
  3927  	return cmd.val
  3928  }
  3929  
  3930  // readReply will try to parse the reply from the proto.Reader for both resp2 and resp3
  3931  func (cmd *MapMapStringInterfaceCmd) readReply(rd *proto.Reader) (err error) {
  3932  	data, err := rd.ReadReply()
  3933  	if err != nil {
  3934  		return err
  3935  	}
  3936  	resultMap := map[string]interface{}{}
  3937  
  3938  	switch midResponse := data.(type) {
  3939  	case map[interface{}]interface{}: // resp3 will return map
  3940  		for k, v := range midResponse {
  3941  			stringKey, ok := k.(string)
  3942  			if !ok {
  3943  				return fmt.Errorf("redis: invalid map key %#v", k)
  3944  			}
  3945  			resultMap[stringKey] = v
  3946  		}
  3947  	case []interface{}: // resp2 will return array of arrays
  3948  		n := len(midResponse)
  3949  		for i := 0; i < n; i++ {
  3950  			finalArr, ok := midResponse[i].([]interface{}) // final array that we need to transform to map
  3951  			if !ok {
  3952  				return fmt.Errorf("redis: unexpected response %#v", data)
  3953  			}
  3954  			m := len(finalArr)
  3955  			if m%2 != 0 { // since this should be map, keys should be even number
  3956  				return fmt.Errorf("redis: unexpected response %#v", data)
  3957  			}
  3958  
  3959  			for j := 0; j < m; j += 2 {
  3960  				stringKey, ok := finalArr[j].(string) // the first one
  3961  				if !ok {
  3962  					return fmt.Errorf("redis: invalid map key %#v", finalArr[i])
  3963  				}
  3964  				resultMap[stringKey] = finalArr[j+1] // second one is value
  3965  			}
  3966  		}
  3967  	default:
  3968  		return fmt.Errorf("redis: unexpected response %#v", data)
  3969  	}
  3970  
  3971  	cmd.val = resultMap
  3972  	return nil
  3973  }
  3974  
  3975  //-----------------------------------------------------------------------
  3976  
  3977  type MapStringInterfaceSliceCmd struct {
  3978  	baseCmd
  3979  
  3980  	val []map[string]interface{}
  3981  }
  3982  
  3983  var _ Cmder = (*MapStringInterfaceSliceCmd)(nil)
  3984  
  3985  func NewMapStringInterfaceSliceCmd(ctx context.Context, args ...interface{}) *MapStringInterfaceSliceCmd {
  3986  	return &MapStringInterfaceSliceCmd{
  3987  		baseCmd: baseCmd{
  3988  			ctx:  ctx,
  3989  			args: args,
  3990  		},
  3991  	}
  3992  }
  3993  
  3994  func (cmd *MapStringInterfaceSliceCmd) SetVal(val []map[string]interface{}) {
  3995  	cmd.val = val
  3996  }
  3997  
  3998  func (cmd *MapStringInterfaceSliceCmd) Val() []map[string]interface{} {
  3999  	return cmd.val
  4000  }
  4001  
  4002  func (cmd *MapStringInterfaceSliceCmd) Result() ([]map[string]interface{}, error) {
  4003  	return cmd.val, cmd.err
  4004  }
  4005  
  4006  func (cmd *MapStringInterfaceSliceCmd) String() string {
  4007  	return cmdString(cmd, cmd.val)
  4008  }
  4009  
  4010  func (cmd *MapStringInterfaceSliceCmd) readReply(rd *proto.Reader) error {
  4011  	n, err := rd.ReadArrayLen()
  4012  	if err != nil {
  4013  		return err
  4014  	}
  4015  
  4016  	cmd.val = make([]map[string]interface{}, n)
  4017  	for i := 0; i < n; i++ {
  4018  		nn, err := rd.ReadMapLen()
  4019  		if err != nil {
  4020  			return err
  4021  		}
  4022  		cmd.val[i] = make(map[string]interface{}, nn)
  4023  		for f := 0; f < nn; f++ {
  4024  			k, err := rd.ReadString()
  4025  			if err != nil {
  4026  				return err
  4027  			}
  4028  			v, err := rd.ReadReply()
  4029  			if err != nil {
  4030  				if err != Nil {
  4031  					return err
  4032  				}
  4033  			}
  4034  			cmd.val[i][k] = v
  4035  		}
  4036  	}
  4037  	return nil
  4038  }
  4039  
  4040  //------------------------------------------------------------------------------
  4041  
  4042  type KeyValuesCmd struct {
  4043  	baseCmd
  4044  
  4045  	key string
  4046  	val []string
  4047  }
  4048  
  4049  var _ Cmder = (*KeyValuesCmd)(nil)
  4050  
  4051  func NewKeyValuesCmd(ctx context.Context, args ...interface{}) *KeyValuesCmd {
  4052  	return &KeyValuesCmd{
  4053  		baseCmd: baseCmd{
  4054  			ctx:  ctx,
  4055  			args: args,
  4056  		},
  4057  	}
  4058  }
  4059  
  4060  func (cmd *KeyValuesCmd) SetVal(key string, val []string) {
  4061  	cmd.key = key
  4062  	cmd.val = val
  4063  }
  4064  
  4065  func (cmd *KeyValuesCmd) Val() (string, []string) {
  4066  	return cmd.key, cmd.val
  4067  }
  4068  
  4069  func (cmd *KeyValuesCmd) Result() (string, []string, error) {
  4070  	return cmd.key, cmd.val, cmd.err
  4071  }
  4072  
  4073  func (cmd *KeyValuesCmd) String() string {
  4074  	return cmdString(cmd, cmd.val)
  4075  }
  4076  
  4077  func (cmd *KeyValuesCmd) readReply(rd *proto.Reader) (err error) {
  4078  	if err = rd.ReadFixedArrayLen(2); err != nil {
  4079  		return err
  4080  	}
  4081  
  4082  	cmd.key, err = rd.ReadString()
  4083  	if err != nil {
  4084  		return err
  4085  	}
  4086  
  4087  	n, err := rd.ReadArrayLen()
  4088  	if err != nil {
  4089  		return err
  4090  	}
  4091  	cmd.val = make([]string, n)
  4092  	for i := 0; i < n; i++ {
  4093  		cmd.val[i], err = rd.ReadString()
  4094  		if err != nil {
  4095  			return err
  4096  		}
  4097  	}
  4098  
  4099  	return nil
  4100  }
  4101  
  4102  //------------------------------------------------------------------------------
  4103  
  4104  type ZSliceWithKeyCmd struct {
  4105  	baseCmd
  4106  
  4107  	key string
  4108  	val []Z
  4109  }
  4110  
  4111  var _ Cmder = (*ZSliceWithKeyCmd)(nil)
  4112  
  4113  func NewZSliceWithKeyCmd(ctx context.Context, args ...interface{}) *ZSliceWithKeyCmd {
  4114  	return &ZSliceWithKeyCmd{
  4115  		baseCmd: baseCmd{
  4116  			ctx:  ctx,
  4117  			args: args,
  4118  		},
  4119  	}
  4120  }
  4121  
  4122  func (cmd *ZSliceWithKeyCmd) SetVal(key string, val []Z) {
  4123  	cmd.key = key
  4124  	cmd.val = val
  4125  }
  4126  
  4127  func (cmd *ZSliceWithKeyCmd) Val() (string, []Z) {
  4128  	return cmd.key, cmd.val
  4129  }
  4130  
  4131  func (cmd *ZSliceWithKeyCmd) Result() (string, []Z, error) {
  4132  	return cmd.key, cmd.val, cmd.err
  4133  }
  4134  
  4135  func (cmd *ZSliceWithKeyCmd) String() string {
  4136  	return cmdString(cmd, cmd.val)
  4137  }
  4138  
  4139  func (cmd *ZSliceWithKeyCmd) readReply(rd *proto.Reader) (err error) {
  4140  	if err = rd.ReadFixedArrayLen(2); err != nil {
  4141  		return err
  4142  	}
  4143  
  4144  	cmd.key, err = rd.ReadString()
  4145  	if err != nil {
  4146  		return err
  4147  	}
  4148  
  4149  	n, err := rd.ReadArrayLen()
  4150  	if err != nil {
  4151  		return err
  4152  	}
  4153  
  4154  	typ, err := rd.PeekReplyType()
  4155  	if err != nil {
  4156  		return err
  4157  	}
  4158  	array := typ == proto.RespArray
  4159  
  4160  	if array {
  4161  		cmd.val = make([]Z, n)
  4162  	} else {
  4163  		cmd.val = make([]Z, n/2)
  4164  	}
  4165  
  4166  	for i := 0; i < len(cmd.val); i++ {
  4167  		if array {
  4168  			if err = rd.ReadFixedArrayLen(2); err != nil {
  4169  				return err
  4170  			}
  4171  		}
  4172  
  4173  		if cmd.val[i].Member, err = rd.ReadString(); err != nil {
  4174  			return err
  4175  		}
  4176  
  4177  		if cmd.val[i].Score, err = rd.ReadFloat(); err != nil {
  4178  			return err
  4179  		}
  4180  	}
  4181  
  4182  	return nil
  4183  }
  4184  
  4185  type Function struct {
  4186  	Name        string
  4187  	Description string
  4188  	Flags       []string
  4189  }
  4190  
  4191  type Library struct {
  4192  	Name      string
  4193  	Engine    string
  4194  	Functions []Function
  4195  	Code      string
  4196  }
  4197  
  4198  type FunctionListCmd struct {
  4199  	baseCmd
  4200  
  4201  	val []Library
  4202  }
  4203  
  4204  var _ Cmder = (*FunctionListCmd)(nil)
  4205  
  4206  func NewFunctionListCmd(ctx context.Context, args ...interface{}) *FunctionListCmd {
  4207  	return &FunctionListCmd{
  4208  		baseCmd: baseCmd{
  4209  			ctx:  ctx,
  4210  			args: args,
  4211  		},
  4212  	}
  4213  }
  4214  
  4215  func (cmd *FunctionListCmd) SetVal(val []Library) {
  4216  	cmd.val = val
  4217  }
  4218  
  4219  func (cmd *FunctionListCmd) String() string {
  4220  	return cmdString(cmd, cmd.val)
  4221  }
  4222  
  4223  func (cmd *FunctionListCmd) Val() []Library {
  4224  	return cmd.val
  4225  }
  4226  
  4227  func (cmd *FunctionListCmd) Result() ([]Library, error) {
  4228  	return cmd.val, cmd.err
  4229  }
  4230  
  4231  func (cmd *FunctionListCmd) First() (*Library, error) {
  4232  	if cmd.err != nil {
  4233  		return nil, cmd.err
  4234  	}
  4235  	if len(cmd.val) > 0 {
  4236  		return &cmd.val[0], nil
  4237  	}
  4238  	return nil, Nil
  4239  }
  4240  
  4241  func (cmd *FunctionListCmd) readReply(rd *proto.Reader) (err error) {
  4242  	n, err := rd.ReadArrayLen()
  4243  	if err != nil {
  4244  		return err
  4245  	}
  4246  
  4247  	libraries := make([]Library, n)
  4248  	for i := 0; i < n; i++ {
  4249  		nn, err := rd.ReadMapLen()
  4250  		if err != nil {
  4251  			return err
  4252  		}
  4253  
  4254  		library := Library{}
  4255  		for f := 0; f < nn; f++ {
  4256  			key, err := rd.ReadString()
  4257  			if err != nil {
  4258  				return err
  4259  			}
  4260  
  4261  			switch key {
  4262  			case "library_name":
  4263  				library.Name, err = rd.ReadString()
  4264  			case "engine":
  4265  				library.Engine, err = rd.ReadString()
  4266  			case "functions":
  4267  				library.Functions, err = cmd.readFunctions(rd)
  4268  			case "library_code":
  4269  				library.Code, err = rd.ReadString()
  4270  			default:
  4271  				return fmt.Errorf("redis: function list unexpected key %s", key)
  4272  			}
  4273  
  4274  			if err != nil {
  4275  				return err
  4276  			}
  4277  		}
  4278  
  4279  		libraries[i] = library
  4280  	}
  4281  	cmd.val = libraries
  4282  	return nil
  4283  }
  4284  
  4285  func (cmd *FunctionListCmd) readFunctions(rd *proto.Reader) ([]Function, error) {
  4286  	n, err := rd.ReadArrayLen()
  4287  	if err != nil {
  4288  		return nil, err
  4289  	}
  4290  
  4291  	functions := make([]Function, n)
  4292  	for i := 0; i < n; i++ {
  4293  		nn, err := rd.ReadMapLen()
  4294  		if err != nil {
  4295  			return nil, err
  4296  		}
  4297  
  4298  		function := Function{}
  4299  		for f := 0; f < nn; f++ {
  4300  			key, err := rd.ReadString()
  4301  			if err != nil {
  4302  				return nil, err
  4303  			}
  4304  
  4305  			switch key {
  4306  			case "name":
  4307  				if function.Name, err = rd.ReadString(); err != nil {
  4308  					return nil, err
  4309  				}
  4310  			case "description":
  4311  				if function.Description, err = rd.ReadString(); err != nil && err != Nil {
  4312  					return nil, err
  4313  				}
  4314  			case "flags":
  4315  				// resp set
  4316  				nx, err := rd.ReadArrayLen()
  4317  				if err != nil {
  4318  					return nil, err
  4319  				}
  4320  
  4321  				function.Flags = make([]string, nx)
  4322  				for j := 0; j < nx; j++ {
  4323  					if function.Flags[j], err = rd.ReadString(); err != nil {
  4324  						return nil, err
  4325  					}
  4326  				}
  4327  			default:
  4328  				return nil, fmt.Errorf("redis: function list unexpected key %s", key)
  4329  			}
  4330  		}
  4331  
  4332  		functions[i] = function
  4333  	}
  4334  	return functions, nil
  4335  }
  4336  
  4337  // FunctionStats contains information about the scripts currently executing on the server, and the available engines
  4338  //   - Engines:
  4339  //     Statistics about the engine like number of functions and number of libraries
  4340  //   - RunningScript:
  4341  //     The script currently running on the shard we're connecting to.
  4342  //     For Redis Enterprise and Redis Cloud, this represents the
  4343  //     function with the longest running time, across all the running functions, on all shards
  4344  //   - RunningScripts
  4345  //     All scripts currently running in a Redis Enterprise clustered database.
  4346  //     Only available on Redis Enterprise
  4347  type FunctionStats struct {
  4348  	Engines   []Engine
  4349  	isRunning bool
  4350  	rs        RunningScript
  4351  	allrs     []RunningScript
  4352  }
  4353  
  4354  func (fs *FunctionStats) Running() bool {
  4355  	return fs.isRunning
  4356  }
  4357  
  4358  func (fs *FunctionStats) RunningScript() (RunningScript, bool) {
  4359  	return fs.rs, fs.isRunning
  4360  }
  4361  
  4362  // AllRunningScripts returns all scripts currently running in a Redis Enterprise clustered database.
  4363  // Only available on Redis Enterprise
  4364  func (fs *FunctionStats) AllRunningScripts() []RunningScript {
  4365  	return fs.allrs
  4366  }
  4367  
  4368  type RunningScript struct {
  4369  	Name     string
  4370  	Command  []string
  4371  	Duration time.Duration
  4372  }
  4373  
  4374  type Engine struct {
  4375  	Language       string
  4376  	LibrariesCount int64
  4377  	FunctionsCount int64
  4378  }
  4379  
  4380  type FunctionStatsCmd struct {
  4381  	baseCmd
  4382  	val FunctionStats
  4383  }
  4384  
  4385  var _ Cmder = (*FunctionStatsCmd)(nil)
  4386  
  4387  func NewFunctionStatsCmd(ctx context.Context, args ...interface{}) *FunctionStatsCmd {
  4388  	return &FunctionStatsCmd{
  4389  		baseCmd: baseCmd{
  4390  			ctx:  ctx,
  4391  			args: args,
  4392  		},
  4393  	}
  4394  }
  4395  
  4396  func (cmd *FunctionStatsCmd) SetVal(val FunctionStats) {
  4397  	cmd.val = val
  4398  }
  4399  
  4400  func (cmd *FunctionStatsCmd) String() string {
  4401  	return cmdString(cmd, cmd.val)
  4402  }
  4403  
  4404  func (cmd *FunctionStatsCmd) Val() FunctionStats {
  4405  	return cmd.val
  4406  }
  4407  
  4408  func (cmd *FunctionStatsCmd) Result() (FunctionStats, error) {
  4409  	return cmd.val, cmd.err
  4410  }
  4411  
  4412  func (cmd *FunctionStatsCmd) readReply(rd *proto.Reader) (err error) {
  4413  	n, err := rd.ReadMapLen()
  4414  	if err != nil {
  4415  		return err
  4416  	}
  4417  
  4418  	var key string
  4419  	var result FunctionStats
  4420  	for f := 0; f < n; f++ {
  4421  		key, err = rd.ReadString()
  4422  		if err != nil {
  4423  			return err
  4424  		}
  4425  
  4426  		switch key {
  4427  		case "running_script":
  4428  			result.rs, result.isRunning, err = cmd.readRunningScript(rd)
  4429  		case "engines":
  4430  			result.Engines, err = cmd.readEngines(rd)
  4431  		case "all_running_scripts": // Redis Enterprise only
  4432  			result.allrs, result.isRunning, err = cmd.readRunningScripts(rd)
  4433  		default:
  4434  			return fmt.Errorf("redis: function stats unexpected key %s", key)
  4435  		}
  4436  
  4437  		if err != nil {
  4438  			return err
  4439  		}
  4440  	}
  4441  
  4442  	cmd.val = result
  4443  	return nil
  4444  }
  4445  
  4446  func (cmd *FunctionStatsCmd) readRunningScript(rd *proto.Reader) (RunningScript, bool, error) {
  4447  	err := rd.ReadFixedMapLen(3)
  4448  	if err != nil {
  4449  		if err == Nil {
  4450  			return RunningScript{}, false, nil
  4451  		}
  4452  		return RunningScript{}, false, err
  4453  	}
  4454  
  4455  	var runningScript RunningScript
  4456  	for i := 0; i < 3; i++ {
  4457  		key, err := rd.ReadString()
  4458  		if err != nil {
  4459  			return RunningScript{}, false, err
  4460  		}
  4461  
  4462  		switch key {
  4463  		case "name":
  4464  			runningScript.Name, err = rd.ReadString()
  4465  		case "duration_ms":
  4466  			runningScript.Duration, err = cmd.readDuration(rd)
  4467  		case "command":
  4468  			runningScript.Command, err = cmd.readCommand(rd)
  4469  		default:
  4470  			return RunningScript{}, false, fmt.Errorf("redis: function stats unexpected running_script key %s", key)
  4471  		}
  4472  
  4473  		if err != nil {
  4474  			return RunningScript{}, false, err
  4475  		}
  4476  	}
  4477  
  4478  	return runningScript, true, nil
  4479  }
  4480  
  4481  func (cmd *FunctionStatsCmd) readEngines(rd *proto.Reader) ([]Engine, error) {
  4482  	n, err := rd.ReadMapLen()
  4483  	if err != nil {
  4484  		return nil, err
  4485  	}
  4486  
  4487  	engines := make([]Engine, 0, n)
  4488  	for i := 0; i < n; i++ {
  4489  		engine := Engine{}
  4490  		engine.Language, err = rd.ReadString()
  4491  		if err != nil {
  4492  			return nil, err
  4493  		}
  4494  
  4495  		err = rd.ReadFixedMapLen(2)
  4496  		if err != nil {
  4497  			return nil, fmt.Errorf("redis: function stats unexpected %s engine map length", engine.Language)
  4498  		}
  4499  
  4500  		for i := 0; i < 2; i++ {
  4501  			key, err := rd.ReadString()
  4502  			switch key {
  4503  			case "libraries_count":
  4504  				engine.LibrariesCount, err = rd.ReadInt()
  4505  			case "functions_count":
  4506  				engine.FunctionsCount, err = rd.ReadInt()
  4507  			}
  4508  			if err != nil {
  4509  				return nil, err
  4510  			}
  4511  		}
  4512  
  4513  		engines = append(engines, engine)
  4514  	}
  4515  	return engines, nil
  4516  }
  4517  
  4518  func (cmd *FunctionStatsCmd) readDuration(rd *proto.Reader) (time.Duration, error) {
  4519  	t, err := rd.ReadInt()
  4520  	if err != nil {
  4521  		return time.Duration(0), err
  4522  	}
  4523  	return time.Duration(t) * time.Millisecond, nil
  4524  }
  4525  
  4526  func (cmd *FunctionStatsCmd) readCommand(rd *proto.Reader) ([]string, error) {
  4527  	n, err := rd.ReadArrayLen()
  4528  	if err != nil {
  4529  		return nil, err
  4530  	}
  4531  
  4532  	command := make([]string, 0, n)
  4533  	for i := 0; i < n; i++ {
  4534  		x, err := rd.ReadString()
  4535  		if err != nil {
  4536  			return nil, err
  4537  		}
  4538  		command = append(command, x)
  4539  	}
  4540  
  4541  	return command, nil
  4542  }
  4543  
  4544  func (cmd *FunctionStatsCmd) readRunningScripts(rd *proto.Reader) ([]RunningScript, bool, error) {
  4545  	n, err := rd.ReadArrayLen()
  4546  	if err != nil {
  4547  		return nil, false, err
  4548  	}
  4549  
  4550  	runningScripts := make([]RunningScript, 0, n)
  4551  	for i := 0; i < n; i++ {
  4552  		rs, _, err := cmd.readRunningScript(rd)
  4553  		if err != nil {
  4554  			return nil, false, err
  4555  		}
  4556  		runningScripts = append(runningScripts, rs)
  4557  	}
  4558  
  4559  	return runningScripts, len(runningScripts) > 0, nil
  4560  }
  4561  
  4562  //------------------------------------------------------------------------------
  4563  
  4564  // LCSQuery is a parameter used for the LCS command
  4565  type LCSQuery struct {
  4566  	Key1         string
  4567  	Key2         string
  4568  	Len          bool
  4569  	Idx          bool
  4570  	MinMatchLen  int
  4571  	WithMatchLen bool
  4572  }
  4573  
  4574  // LCSMatch is the result set of the LCS command.
  4575  type LCSMatch struct {
  4576  	MatchString string
  4577  	Matches     []LCSMatchedPosition
  4578  	Len         int64
  4579  }
  4580  
  4581  type LCSMatchedPosition struct {
  4582  	Key1 LCSPosition
  4583  	Key2 LCSPosition
  4584  
  4585  	// only for withMatchLen is true
  4586  	MatchLen int64
  4587  }
  4588  
  4589  type LCSPosition struct {
  4590  	Start int64
  4591  	End   int64
  4592  }
  4593  
  4594  type LCSCmd struct {
  4595  	baseCmd
  4596  
  4597  	// 1: match string
  4598  	// 2: match len
  4599  	// 3: match idx LCSMatch
  4600  	readType uint8
  4601  	val      *LCSMatch
  4602  }
  4603  
  4604  func NewLCSCmd(ctx context.Context, q *LCSQuery) *LCSCmd {
  4605  	args := make([]interface{}, 3, 7)
  4606  	args[0] = "lcs"
  4607  	args[1] = q.Key1
  4608  	args[2] = q.Key2
  4609  
  4610  	cmd := &LCSCmd{readType: 1}
  4611  	if q.Len {
  4612  		cmd.readType = 2
  4613  		args = append(args, "len")
  4614  	} else if q.Idx {
  4615  		cmd.readType = 3
  4616  		args = append(args, "idx")
  4617  		if q.MinMatchLen != 0 {
  4618  			args = append(args, "minmatchlen", q.MinMatchLen)
  4619  		}
  4620  		if q.WithMatchLen {
  4621  			args = append(args, "withmatchlen")
  4622  		}
  4623  	}
  4624  	cmd.baseCmd = baseCmd{
  4625  		ctx:  ctx,
  4626  		args: args,
  4627  	}
  4628  
  4629  	return cmd
  4630  }
  4631  
  4632  func (cmd *LCSCmd) SetVal(val *LCSMatch) {
  4633  	cmd.val = val
  4634  }
  4635  
  4636  func (cmd *LCSCmd) String() string {
  4637  	return cmdString(cmd, cmd.val)
  4638  }
  4639  
  4640  func (cmd *LCSCmd) Val() *LCSMatch {
  4641  	return cmd.val
  4642  }
  4643  
  4644  func (cmd *LCSCmd) Result() (*LCSMatch, error) {
  4645  	return cmd.val, cmd.err
  4646  }
  4647  
  4648  func (cmd *LCSCmd) readReply(rd *proto.Reader) (err error) {
  4649  	lcs := &LCSMatch{}
  4650  	switch cmd.readType {
  4651  	case 1:
  4652  		// match string
  4653  		if lcs.MatchString, err = rd.ReadString(); err != nil {
  4654  			return err
  4655  		}
  4656  	case 2:
  4657  		// match len
  4658  		if lcs.Len, err = rd.ReadInt(); err != nil {
  4659  			return err
  4660  		}
  4661  	case 3:
  4662  		// read LCSMatch
  4663  		if err = rd.ReadFixedMapLen(2); err != nil {
  4664  			return err
  4665  		}
  4666  
  4667  		// read matches or len field
  4668  		for i := 0; i < 2; i++ {
  4669  			key, err := rd.ReadString()
  4670  			if err != nil {
  4671  				return err
  4672  			}
  4673  
  4674  			switch key {
  4675  			case "matches":
  4676  				// read array of matched positions
  4677  				if lcs.Matches, err = cmd.readMatchedPositions(rd); err != nil {
  4678  					return err
  4679  				}
  4680  			case "len":
  4681  				// read match length
  4682  				if lcs.Len, err = rd.ReadInt(); err != nil {
  4683  					return err
  4684  				}
  4685  			}
  4686  		}
  4687  	}
  4688  
  4689  	cmd.val = lcs
  4690  	return nil
  4691  }
  4692  
  4693  func (cmd *LCSCmd) readMatchedPositions(rd *proto.Reader) ([]LCSMatchedPosition, error) {
  4694  	n, err := rd.ReadArrayLen()
  4695  	if err != nil {
  4696  		return nil, err
  4697  	}
  4698  
  4699  	positions := make([]LCSMatchedPosition, n)
  4700  	for i := 0; i < n; i++ {
  4701  		pn, err := rd.ReadArrayLen()
  4702  		if err != nil {
  4703  			return nil, err
  4704  		}
  4705  
  4706  		if positions[i].Key1, err = cmd.readPosition(rd); err != nil {
  4707  			return nil, err
  4708  		}
  4709  		if positions[i].Key2, err = cmd.readPosition(rd); err != nil {
  4710  			return nil, err
  4711  		}
  4712  
  4713  		// read match length if WithMatchLen is true
  4714  		if pn > 2 {
  4715  			if positions[i].MatchLen, err = rd.ReadInt(); err != nil {
  4716  				return nil, err
  4717  			}
  4718  		}
  4719  	}
  4720  
  4721  	return positions, nil
  4722  }
  4723  
  4724  func (cmd *LCSCmd) readPosition(rd *proto.Reader) (pos LCSPosition, err error) {
  4725  	if err = rd.ReadFixedArrayLen(2); err != nil {
  4726  		return pos, err
  4727  	}
  4728  	if pos.Start, err = rd.ReadInt(); err != nil {
  4729  		return pos, err
  4730  	}
  4731  	if pos.End, err = rd.ReadInt(); err != nil {
  4732  		return pos, err
  4733  	}
  4734  
  4735  	return pos, nil
  4736  }
  4737  
  4738  // ------------------------------------------------------------------------
  4739  
  4740  type KeyFlags struct {
  4741  	Key   string
  4742  	Flags []string
  4743  }
  4744  
  4745  type KeyFlagsCmd struct {
  4746  	baseCmd
  4747  
  4748  	val []KeyFlags
  4749  }
  4750  
  4751  var _ Cmder = (*KeyFlagsCmd)(nil)
  4752  
  4753  func NewKeyFlagsCmd(ctx context.Context, args ...interface{}) *KeyFlagsCmd {
  4754  	return &KeyFlagsCmd{
  4755  		baseCmd: baseCmd{
  4756  			ctx:  ctx,
  4757  			args: args,
  4758  		},
  4759  	}
  4760  }
  4761  
  4762  func (cmd *KeyFlagsCmd) SetVal(val []KeyFlags) {
  4763  	cmd.val = val
  4764  }
  4765  
  4766  func (cmd *KeyFlagsCmd) Val() []KeyFlags {
  4767  	return cmd.val
  4768  }
  4769  
  4770  func (cmd *KeyFlagsCmd) Result() ([]KeyFlags, error) {
  4771  	return cmd.val, cmd.err
  4772  }
  4773  
  4774  func (cmd *KeyFlagsCmd) String() string {
  4775  	return cmdString(cmd, cmd.val)
  4776  }
  4777  
  4778  func (cmd *KeyFlagsCmd) readReply(rd *proto.Reader) error {
  4779  	n, err := rd.ReadArrayLen()
  4780  	if err != nil {
  4781  		return err
  4782  	}
  4783  
  4784  	if n == 0 {
  4785  		cmd.val = make([]KeyFlags, 0)
  4786  		return nil
  4787  	}
  4788  
  4789  	cmd.val = make([]KeyFlags, n)
  4790  
  4791  	for i := 0; i < len(cmd.val); i++ {
  4792  
  4793  		if err = rd.ReadFixedArrayLen(2); err != nil {
  4794  			return err
  4795  		}
  4796  
  4797  		if cmd.val[i].Key, err = rd.ReadString(); err != nil {
  4798  			return err
  4799  		}
  4800  		flagsLen, err := rd.ReadArrayLen()
  4801  		if err != nil {
  4802  			return err
  4803  		}
  4804  		cmd.val[i].Flags = make([]string, flagsLen)
  4805  
  4806  		for j := 0; j < flagsLen; j++ {
  4807  			if cmd.val[i].Flags[j], err = rd.ReadString(); err != nil {
  4808  				return err
  4809  			}
  4810  		}
  4811  	}
  4812  
  4813  	return nil
  4814  }
  4815  
  4816  // ---------------------------------------------------------------------------------------------------
  4817  
  4818  type ClusterLink struct {
  4819  	Direction           string
  4820  	Node                string
  4821  	CreateTime          int64
  4822  	Events              string
  4823  	SendBufferAllocated int64
  4824  	SendBufferUsed      int64
  4825  }
  4826  
  4827  type ClusterLinksCmd struct {
  4828  	baseCmd
  4829  
  4830  	val []ClusterLink
  4831  }
  4832  
  4833  var _ Cmder = (*ClusterLinksCmd)(nil)
  4834  
  4835  func NewClusterLinksCmd(ctx context.Context, args ...interface{}) *ClusterLinksCmd {
  4836  	return &ClusterLinksCmd{
  4837  		baseCmd: baseCmd{
  4838  			ctx:  ctx,
  4839  			args: args,
  4840  		},
  4841  	}
  4842  }
  4843  
  4844  func (cmd *ClusterLinksCmd) SetVal(val []ClusterLink) {
  4845  	cmd.val = val
  4846  }
  4847  
  4848  func (cmd *ClusterLinksCmd) Val() []ClusterLink {
  4849  	return cmd.val
  4850  }
  4851  
  4852  func (cmd *ClusterLinksCmd) Result() ([]ClusterLink, error) {
  4853  	return cmd.val, cmd.err
  4854  }
  4855  
  4856  func (cmd *ClusterLinksCmd) String() string {
  4857  	return cmdString(cmd, cmd.val)
  4858  }
  4859  
  4860  func (cmd *ClusterLinksCmd) readReply(rd *proto.Reader) error {
  4861  	n, err := rd.ReadArrayLen()
  4862  	if err != nil {
  4863  		return err
  4864  	}
  4865  	cmd.val = make([]ClusterLink, n)
  4866  
  4867  	for i := 0; i < len(cmd.val); i++ {
  4868  		m, err := rd.ReadMapLen()
  4869  		if err != nil {
  4870  			return err
  4871  		}
  4872  
  4873  		for j := 0; j < m; j++ {
  4874  			key, err := rd.ReadString()
  4875  			if err != nil {
  4876  				return err
  4877  			}
  4878  
  4879  			switch key {
  4880  			case "direction":
  4881  				cmd.val[i].Direction, err = rd.ReadString()
  4882  			case "node":
  4883  				cmd.val[i].Node, err = rd.ReadString()
  4884  			case "create-time":
  4885  				cmd.val[i].CreateTime, err = rd.ReadInt()
  4886  			case "events":
  4887  				cmd.val[i].Events, err = rd.ReadString()
  4888  			case "send-buffer-allocated":
  4889  				cmd.val[i].SendBufferAllocated, err = rd.ReadInt()
  4890  			case "send-buffer-used":
  4891  				cmd.val[i].SendBufferUsed, err = rd.ReadInt()
  4892  			default:
  4893  				return fmt.Errorf("redis: unexpected key %q in CLUSTER LINKS reply", key)
  4894  			}
  4895  
  4896  			if err != nil {
  4897  				return err
  4898  			}
  4899  		}
  4900  	}
  4901  
  4902  	return nil
  4903  }
  4904  
  4905  // ------------------------------------------------------------------------------------------------------------------
  4906  
  4907  type SlotRange struct {
  4908  	Start int64
  4909  	End   int64
  4910  }
  4911  
  4912  type Node struct {
  4913  	ID                string
  4914  	Endpoint          string
  4915  	IP                string
  4916  	Hostname          string
  4917  	Port              int64
  4918  	TLSPort           int64
  4919  	Role              string
  4920  	ReplicationOffset int64
  4921  	Health            string
  4922  }
  4923  
  4924  type ClusterShard struct {
  4925  	Slots []SlotRange
  4926  	Nodes []Node
  4927  }
  4928  
  4929  type ClusterShardsCmd struct {
  4930  	baseCmd
  4931  
  4932  	val []ClusterShard
  4933  }
  4934  
  4935  var _ Cmder = (*ClusterShardsCmd)(nil)
  4936  
  4937  func NewClusterShardsCmd(ctx context.Context, args ...interface{}) *ClusterShardsCmd {
  4938  	return &ClusterShardsCmd{
  4939  		baseCmd: baseCmd{
  4940  			ctx:  ctx,
  4941  			args: args,
  4942  		},
  4943  	}
  4944  }
  4945  
  4946  func (cmd *ClusterShardsCmd) SetVal(val []ClusterShard) {
  4947  	cmd.val = val
  4948  }
  4949  
  4950  func (cmd *ClusterShardsCmd) Val() []ClusterShard {
  4951  	return cmd.val
  4952  }
  4953  
  4954  func (cmd *ClusterShardsCmd) Result() ([]ClusterShard, error) {
  4955  	return cmd.val, cmd.err
  4956  }
  4957  
  4958  func (cmd *ClusterShardsCmd) String() string {
  4959  	return cmdString(cmd, cmd.val)
  4960  }
  4961  
  4962  func (cmd *ClusterShardsCmd) readReply(rd *proto.Reader) error {
  4963  	n, err := rd.ReadArrayLen()
  4964  	if err != nil {
  4965  		return err
  4966  	}
  4967  	cmd.val = make([]ClusterShard, n)
  4968  
  4969  	for i := 0; i < n; i++ {
  4970  		m, err := rd.ReadMapLen()
  4971  		if err != nil {
  4972  			return err
  4973  		}
  4974  
  4975  		for j := 0; j < m; j++ {
  4976  			key, err := rd.ReadString()
  4977  			if err != nil {
  4978  				return err
  4979  			}
  4980  
  4981  			switch key {
  4982  			case "slots":
  4983  				l, err := rd.ReadArrayLen()
  4984  				if err != nil {
  4985  					return err
  4986  				}
  4987  				for k := 0; k < l; k += 2 {
  4988  					start, err := rd.ReadInt()
  4989  					if err != nil {
  4990  						return err
  4991  					}
  4992  
  4993  					end, err := rd.ReadInt()
  4994  					if err != nil {
  4995  						return err
  4996  					}
  4997  
  4998  					cmd.val[i].Slots = append(cmd.val[i].Slots, SlotRange{Start: start, End: end})
  4999  				}
  5000  			case "nodes":
  5001  				nodesLen, err := rd.ReadArrayLen()
  5002  				if err != nil {
  5003  					return err
  5004  				}
  5005  				cmd.val[i].Nodes = make([]Node, nodesLen)
  5006  				for k := 0; k < nodesLen; k++ {
  5007  					nodeMapLen, err := rd.ReadMapLen()
  5008  					if err != nil {
  5009  						return err
  5010  					}
  5011  
  5012  					for l := 0; l < nodeMapLen; l++ {
  5013  						nodeKey, err := rd.ReadString()
  5014  						if err != nil {
  5015  							return err
  5016  						}
  5017  
  5018  						switch nodeKey {
  5019  						case "id":
  5020  							cmd.val[i].Nodes[k].ID, err = rd.ReadString()
  5021  						case "endpoint":
  5022  							cmd.val[i].Nodes[k].Endpoint, err = rd.ReadString()
  5023  						case "ip":
  5024  							cmd.val[i].Nodes[k].IP, err = rd.ReadString()
  5025  						case "hostname":
  5026  							cmd.val[i].Nodes[k].Hostname, err = rd.ReadString()
  5027  						case "port":
  5028  							cmd.val[i].Nodes[k].Port, err = rd.ReadInt()
  5029  						case "tls-port":
  5030  							cmd.val[i].Nodes[k].TLSPort, err = rd.ReadInt()
  5031  						case "role":
  5032  							cmd.val[i].Nodes[k].Role, err = rd.ReadString()
  5033  						case "replication-offset":
  5034  							cmd.val[i].Nodes[k].ReplicationOffset, err = rd.ReadInt()
  5035  						case "health":
  5036  							cmd.val[i].Nodes[k].Health, err = rd.ReadString()
  5037  						default:
  5038  							return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS node reply", nodeKey)
  5039  						}
  5040  
  5041  						if err != nil {
  5042  							return err
  5043  						}
  5044  					}
  5045  				}
  5046  			default:
  5047  				return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS reply", key)
  5048  			}
  5049  		}
  5050  	}
  5051  
  5052  	return nil
  5053  }
  5054  
  5055  // -----------------------------------------
  5056  
  5057  type RankScore struct {
  5058  	Rank  int64
  5059  	Score float64
  5060  }
  5061  
  5062  type RankWithScoreCmd struct {
  5063  	baseCmd
  5064  
  5065  	val RankScore
  5066  }
  5067  
  5068  var _ Cmder = (*RankWithScoreCmd)(nil)
  5069  
  5070  func NewRankWithScoreCmd(ctx context.Context, args ...interface{}) *RankWithScoreCmd {
  5071  	return &RankWithScoreCmd{
  5072  		baseCmd: baseCmd{
  5073  			ctx:  ctx,
  5074  			args: args,
  5075  		},
  5076  	}
  5077  }
  5078  
  5079  func (cmd *RankWithScoreCmd) SetVal(val RankScore) {
  5080  	cmd.val = val
  5081  }
  5082  
  5083  func (cmd *RankWithScoreCmd) Val() RankScore {
  5084  	return cmd.val
  5085  }
  5086  
  5087  func (cmd *RankWithScoreCmd) Result() (RankScore, error) {
  5088  	return cmd.val, cmd.err
  5089  }
  5090  
  5091  func (cmd *RankWithScoreCmd) String() string {
  5092  	return cmdString(cmd, cmd.val)
  5093  }
  5094  
  5095  func (cmd *RankWithScoreCmd) readReply(rd *proto.Reader) error {
  5096  	if err := rd.ReadFixedArrayLen(2); err != nil {
  5097  		return err
  5098  	}
  5099  
  5100  	rank, err := rd.ReadInt()
  5101  	if err != nil {
  5102  		return err
  5103  	}
  5104  
  5105  	score, err := rd.ReadFloat()
  5106  	if err != nil {
  5107  		return err
  5108  	}
  5109  
  5110  	cmd.val = RankScore{Rank: rank, Score: score}
  5111  
  5112  	return nil
  5113  }
  5114  
  5115  // --------------------------------------------------------------------------------------------------
  5116  
  5117  // ClientFlags is redis-server client flags, copy from redis/src/server.h (redis 7.0)
  5118  type ClientFlags uint64
  5119  
  5120  const (
  5121  	ClientSlave            ClientFlags = 1 << 0  /* This client is a replica */
  5122  	ClientMaster           ClientFlags = 1 << 1  /* This client is a master */
  5123  	ClientMonitor          ClientFlags = 1 << 2  /* This client is a slave monitor, see MONITOR */
  5124  	ClientMulti            ClientFlags = 1 << 3  /* This client is in a MULTI context */
  5125  	ClientBlocked          ClientFlags = 1 << 4  /* The client is waiting in a blocking operation */
  5126  	ClientDirtyCAS         ClientFlags = 1 << 5  /* Watched keys modified. EXEC will fail. */
  5127  	ClientCloseAfterReply  ClientFlags = 1 << 6  /* Close after writing entire reply. */
  5128  	ClientUnBlocked        ClientFlags = 1 << 7  /* This client was unblocked and is stored in server.unblocked_clients */
  5129  	ClientScript           ClientFlags = 1 << 8  /* This is a non-connected client used by Lua */
  5130  	ClientAsking           ClientFlags = 1 << 9  /* Client issued the ASKING command */
  5131  	ClientCloseASAP        ClientFlags = 1 << 10 /* Close this client ASAP */
  5132  	ClientUnixSocket       ClientFlags = 1 << 11 /* Client connected via Unix domain socket */
  5133  	ClientDirtyExec        ClientFlags = 1 << 12 /* EXEC will fail for errors while queueing */
  5134  	ClientMasterForceReply ClientFlags = 1 << 13 /* Queue replies even if is master */
  5135  	ClientForceAOF         ClientFlags = 1 << 14 /* Force AOF propagation of current cmd. */
  5136  	ClientForceRepl        ClientFlags = 1 << 15 /* Force replication of current cmd. */
  5137  	ClientPrePSync         ClientFlags = 1 << 16 /* Instance don't understand PSYNC. */
  5138  	ClientReadOnly         ClientFlags = 1 << 17 /* Cluster client is in read-only state. */
  5139  	ClientPubSub           ClientFlags = 1 << 18 /* Client is in Pub/Sub mode. */
  5140  	ClientPreventAOFProp   ClientFlags = 1 << 19 /* Don't propagate to AOF. */
  5141  	ClientPreventReplProp  ClientFlags = 1 << 20 /* Don't propagate to slaves. */
  5142  	ClientPreventProp      ClientFlags = ClientPreventAOFProp | ClientPreventReplProp
  5143  	ClientPendingWrite     ClientFlags = 1 << 21 /* Client has output to send but a-write handler is yet not installed. */
  5144  	ClientReplyOff         ClientFlags = 1 << 22 /* Don't send replies to client. */
  5145  	ClientReplySkipNext    ClientFlags = 1 << 23 /* Set ClientREPLY_SKIP for next cmd */
  5146  	ClientReplySkip        ClientFlags = 1 << 24 /* Don't send just this reply. */
  5147  	ClientLuaDebug         ClientFlags = 1 << 25 /* Run EVAL in debug mode. */
  5148  	ClientLuaDebugSync     ClientFlags = 1 << 26 /* EVAL debugging without fork() */
  5149  	ClientModule           ClientFlags = 1 << 27 /* Non connected client used by some module. */
  5150  	ClientProtected        ClientFlags = 1 << 28 /* Client should not be freed for now. */
  5151  	ClientExecutingCommand ClientFlags = 1 << 29 /* Indicates that the client is currently in the process of handling
  5152  	   a command. usually this will be marked only during call()
  5153  	   however, blocked clients might have this flag kept until they
  5154  	   will try to reprocess the command. */
  5155  	ClientPendingCommand      ClientFlags = 1 << 30 /* Indicates the client has a fully * parsed command ready for execution. */
  5156  	ClientTracking            ClientFlags = 1 << 31 /* Client enabled keys tracking in order to perform client side caching. */
  5157  	ClientTrackingBrokenRedir ClientFlags = 1 << 32 /* Target client is invalid. */
  5158  	ClientTrackingBCAST       ClientFlags = 1 << 33 /* Tracking in BCAST mode. */
  5159  	ClientTrackingOptIn       ClientFlags = 1 << 34 /* Tracking in opt-in mode. */
  5160  	ClientTrackingOptOut      ClientFlags = 1 << 35 /* Tracking in opt-out mode. */
  5161  	ClientTrackingCaching     ClientFlags = 1 << 36 /* CACHING yes/no was given, depending on optin/optout mode. */
  5162  	ClientTrackingNoLoop      ClientFlags = 1 << 37 /* Don't send invalidation messages about writes performed by myself.*/
  5163  	ClientInTimeoutTable      ClientFlags = 1 << 38 /* This client is in the timeout table. */
  5164  	ClientProtocolError       ClientFlags = 1 << 39 /* Protocol error chatting with it. */
  5165  	ClientCloseAfterCommand   ClientFlags = 1 << 40 /* Close after executing commands * and writing entire reply. */
  5166  	ClientDenyBlocking        ClientFlags = 1 << 41 /* Indicate that the client should not be blocked. currently, turned on inside MULTI, Lua, RM_Call, and AOF client */
  5167  	ClientReplRDBOnly         ClientFlags = 1 << 42 /* This client is a replica that only wants RDB without replication buffer. */
  5168  	ClientNoEvict             ClientFlags = 1 << 43 /* This client is protected against client memory eviction. */
  5169  	ClientAllowOOM            ClientFlags = 1 << 44 /* Client used by RM_Call is allowed to fully execute scripts even when in OOM */
  5170  	ClientNoTouch             ClientFlags = 1 << 45 /* This client will not touch LFU/LRU stats. */
  5171  	ClientPushing             ClientFlags = 1 << 46 /* This client is pushing notifications. */
  5172  )
  5173  
  5174  // ClientInfo is redis-server ClientInfo, not go-redis *Client
  5175  type ClientInfo struct {
  5176  	ID                 int64         // redis version 2.8.12, a unique 64-bit client ID
  5177  	Addr               string        // address/port of the client
  5178  	LAddr              string        // address/port of local address client connected to (bind address)
  5179  	FD                 int64         // file descriptor corresponding to the socket
  5180  	Name               string        // the name set by the client with CLIENT SETNAME
  5181  	Age                time.Duration // total duration of the connection in seconds
  5182  	Idle               time.Duration // idle time of the connection in seconds
  5183  	Flags              ClientFlags   // client flags (see below)
  5184  	DB                 int           // current database ID
  5185  	Sub                int           // number of channel subscriptions
  5186  	PSub               int           // number of pattern matching subscriptions
  5187  	SSub               int           // redis version 7.0.3, number of shard channel subscriptions
  5188  	Multi              int           // number of commands in a MULTI/EXEC context
  5189  	Watch              int           // redis version 7.4 RC1, number of keys this client is currently watching.
  5190  	QueryBuf           int           // qbuf, query buffer length (0 means no query pending)
  5191  	QueryBufFree       int           // qbuf-free, free space of the query buffer (0 means the buffer is full)
  5192  	ArgvMem            int           // incomplete arguments for the next command (already extracted from query buffer)
  5193  	MultiMem           int           // redis version 7.0, memory is used up by buffered multi commands
  5194  	BufferSize         int           // rbs, usable size of buffer
  5195  	BufferPeak         int           // rbp, peak used size of buffer in last 5 sec interval
  5196  	OutputBufferLength int           // obl, output buffer length
  5197  	OutputListLength   int           // oll, output list length (replies are queued in this list when the buffer is full)
  5198  	OutputMemory       int           // omem, output buffer memory usage
  5199  	TotalMemory        int           // tot-mem, total memory consumed by this client in its various buffers
  5200  	TotalNetIn         int           // tot-net-in, total network input
  5201  	TotalNetOut        int           // tot-net-out, total network output
  5202  	TotalCmds          int           // tot-cmds, total number of commands processed
  5203  	IoThread           int           // io-thread id
  5204  	Events             string        // file descriptor events (see below)
  5205  	LastCmd            string        // cmd, last command played
  5206  	User               string        // the authenticated username of the client
  5207  	Redir              int64         // client id of current client tracking redirection
  5208  	Resp               int           // redis version 7.0, client RESP protocol version
  5209  	LibName            string        // redis version 7.2, client library name
  5210  	LibVer             string        // redis version 7.2, client library version
  5211  }
  5212  
  5213  type ClientInfoCmd struct {
  5214  	baseCmd
  5215  
  5216  	val *ClientInfo
  5217  }
  5218  
  5219  var _ Cmder = (*ClientInfoCmd)(nil)
  5220  
  5221  func NewClientInfoCmd(ctx context.Context, args ...interface{}) *ClientInfoCmd {
  5222  	return &ClientInfoCmd{
  5223  		baseCmd: baseCmd{
  5224  			ctx:  ctx,
  5225  			args: args,
  5226  		},
  5227  	}
  5228  }
  5229  
  5230  func (cmd *ClientInfoCmd) SetVal(val *ClientInfo) {
  5231  	cmd.val = val
  5232  }
  5233  
  5234  func (cmd *ClientInfoCmd) String() string {
  5235  	return cmdString(cmd, cmd.val)
  5236  }
  5237  
  5238  func (cmd *ClientInfoCmd) Val() *ClientInfo {
  5239  	return cmd.val
  5240  }
  5241  
  5242  func (cmd *ClientInfoCmd) Result() (*ClientInfo, error) {
  5243  	return cmd.val, cmd.err
  5244  }
  5245  
  5246  func (cmd *ClientInfoCmd) readReply(rd *proto.Reader) (err error) {
  5247  	txt, err := rd.ReadString()
  5248  	if err != nil {
  5249  		return err
  5250  	}
  5251  
  5252  	// sds o = catClientInfoString(sdsempty(), c);
  5253  	// o = sdscatlen(o,"\n",1);
  5254  	// addReplyVerbatim(c,o,sdslen(o),"txt");
  5255  	// sdsfree(o);
  5256  	cmd.val, err = parseClientInfo(strings.TrimSpace(txt))
  5257  	return err
  5258  }
  5259  
  5260  // fmt.Sscanf() cannot handle null values
  5261  func parseClientInfo(txt string) (info *ClientInfo, err error) {
  5262  	info = &ClientInfo{}
  5263  	for _, s := range strings.Split(txt, " ") {
  5264  		kv := strings.Split(s, "=")
  5265  		if len(kv) != 2 {
  5266  			return nil, fmt.Errorf("redis: unexpected client info data (%s)", s)
  5267  		}
  5268  		key, val := kv[0], kv[1]
  5269  
  5270  		switch key {
  5271  		case "id":
  5272  			info.ID, err = strconv.ParseInt(val, 10, 64)
  5273  		case "addr":
  5274  			info.Addr = val
  5275  		case "laddr":
  5276  			info.LAddr = val
  5277  		case "fd":
  5278  			info.FD, err = strconv.ParseInt(val, 10, 64)
  5279  		case "name":
  5280  			info.Name = val
  5281  		case "age":
  5282  			var age int
  5283  			if age, err = strconv.Atoi(val); err == nil {
  5284  				info.Age = time.Duration(age) * time.Second
  5285  			}
  5286  		case "idle":
  5287  			var idle int
  5288  			if idle, err = strconv.Atoi(val); err == nil {
  5289  				info.Idle = time.Duration(idle) * time.Second
  5290  			}
  5291  		case "flags":
  5292  			if val == "N" {
  5293  				break
  5294  			}
  5295  
  5296  			for i := 0; i < len(val); i++ {
  5297  				switch val[i] {
  5298  				case 'S':
  5299  					info.Flags |= ClientSlave
  5300  				case 'O':
  5301  					info.Flags |= ClientSlave | ClientMonitor
  5302  				case 'M':
  5303  					info.Flags |= ClientMaster
  5304  				case 'P':
  5305  					info.Flags |= ClientPubSub
  5306  				case 'x':
  5307  					info.Flags |= ClientMulti
  5308  				case 'b':
  5309  					info.Flags |= ClientBlocked
  5310  				case 't':
  5311  					info.Flags |= ClientTracking
  5312  				case 'R':
  5313  					info.Flags |= ClientTrackingBrokenRedir
  5314  				case 'B':
  5315  					info.Flags |= ClientTrackingBCAST
  5316  				case 'd':
  5317  					info.Flags |= ClientDirtyCAS
  5318  				case 'c':
  5319  					info.Flags |= ClientCloseAfterCommand
  5320  				case 'u':
  5321  					info.Flags |= ClientUnBlocked
  5322  				case 'A':
  5323  					info.Flags |= ClientCloseASAP
  5324  				case 'U':
  5325  					info.Flags |= ClientUnixSocket
  5326  				case 'r':
  5327  					info.Flags |= ClientReadOnly
  5328  				case 'e':
  5329  					info.Flags |= ClientNoEvict
  5330  				case 'T':
  5331  					info.Flags |= ClientNoTouch
  5332  				default:
  5333  					return nil, fmt.Errorf("redis: unexpected client info flags(%s)", string(val[i]))
  5334  				}
  5335  			}
  5336  		case "db":
  5337  			info.DB, err = strconv.Atoi(val)
  5338  		case "sub":
  5339  			info.Sub, err = strconv.Atoi(val)
  5340  		case "psub":
  5341  			info.PSub, err = strconv.Atoi(val)
  5342  		case "ssub":
  5343  			info.SSub, err = strconv.Atoi(val)
  5344  		case "multi":
  5345  			info.Multi, err = strconv.Atoi(val)
  5346  		case "watch":
  5347  			info.Watch, err = strconv.Atoi(val)
  5348  		case "qbuf":
  5349  			info.QueryBuf, err = strconv.Atoi(val)
  5350  		case "qbuf-free":
  5351  			info.QueryBufFree, err = strconv.Atoi(val)
  5352  		case "argv-mem":
  5353  			info.ArgvMem, err = strconv.Atoi(val)
  5354  		case "multi-mem":
  5355  			info.MultiMem, err = strconv.Atoi(val)
  5356  		case "rbs":
  5357  			info.BufferSize, err = strconv.Atoi(val)
  5358  		case "rbp":
  5359  			info.BufferPeak, err = strconv.Atoi(val)
  5360  		case "obl":
  5361  			info.OutputBufferLength, err = strconv.Atoi(val)
  5362  		case "oll":
  5363  			info.OutputListLength, err = strconv.Atoi(val)
  5364  		case "omem":
  5365  			info.OutputMemory, err = strconv.Atoi(val)
  5366  		case "tot-mem":
  5367  			info.TotalMemory, err = strconv.Atoi(val)
  5368  		case "tot-net-in":
  5369  			info.TotalNetIn, err = strconv.Atoi(val)
  5370  		case "tot-net-out":
  5371  			info.TotalNetOut, err = strconv.Atoi(val)
  5372  		case "tot-cmds":
  5373  			info.TotalCmds, err = strconv.Atoi(val)
  5374  		case "events":
  5375  			info.Events = val
  5376  		case "cmd":
  5377  			info.LastCmd = val
  5378  		case "user":
  5379  			info.User = val
  5380  		case "redir":
  5381  			info.Redir, err = strconv.ParseInt(val, 10, 64)
  5382  		case "resp":
  5383  			info.Resp, err = strconv.Atoi(val)
  5384  		case "lib-name":
  5385  			info.LibName = val
  5386  		case "lib-ver":
  5387  			info.LibVer = val
  5388  		case "io-thread":
  5389  			info.IoThread, err = strconv.Atoi(val)
  5390  		default:
  5391  			return nil, fmt.Errorf("redis: unexpected client info key(%s)", key)
  5392  		}
  5393  
  5394  		if err != nil {
  5395  			return nil, err
  5396  		}
  5397  	}
  5398  
  5399  	return info, nil
  5400  }
  5401  
  5402  // -------------------------------------------
  5403  
  5404  type ACLLogEntry struct {
  5405  	Count                int64
  5406  	Reason               string
  5407  	Context              string
  5408  	Object               string
  5409  	Username             string
  5410  	AgeSeconds           float64
  5411  	ClientInfo           *ClientInfo
  5412  	EntryID              int64
  5413  	TimestampCreated     int64
  5414  	TimestampLastUpdated int64
  5415  }
  5416  
  5417  type ACLLogCmd struct {
  5418  	baseCmd
  5419  
  5420  	val []*ACLLogEntry
  5421  }
  5422  
  5423  var _ Cmder = (*ACLLogCmd)(nil)
  5424  
  5425  func NewACLLogCmd(ctx context.Context, args ...interface{}) *ACLLogCmd {
  5426  	return &ACLLogCmd{
  5427  		baseCmd: baseCmd{
  5428  			ctx:  ctx,
  5429  			args: args,
  5430  		},
  5431  	}
  5432  }
  5433  
  5434  func (cmd *ACLLogCmd) SetVal(val []*ACLLogEntry) {
  5435  	cmd.val = val
  5436  }
  5437  
  5438  func (cmd *ACLLogCmd) Val() []*ACLLogEntry {
  5439  	return cmd.val
  5440  }
  5441  
  5442  func (cmd *ACLLogCmd) Result() ([]*ACLLogEntry, error) {
  5443  	return cmd.val, cmd.err
  5444  }
  5445  
  5446  func (cmd *ACLLogCmd) String() string {
  5447  	return cmdString(cmd, cmd.val)
  5448  }
  5449  
  5450  func (cmd *ACLLogCmd) readReply(rd *proto.Reader) error {
  5451  	n, err := rd.ReadArrayLen()
  5452  	if err != nil {
  5453  		return err
  5454  	}
  5455  
  5456  	cmd.val = make([]*ACLLogEntry, n)
  5457  	for i := 0; i < n; i++ {
  5458  		cmd.val[i] = &ACLLogEntry{}
  5459  		entry := cmd.val[i]
  5460  		respLen, err := rd.ReadMapLen()
  5461  		if err != nil {
  5462  			return err
  5463  		}
  5464  		for j := 0; j < respLen; j++ {
  5465  			key, err := rd.ReadString()
  5466  			if err != nil {
  5467  				return err
  5468  			}
  5469  
  5470  			switch key {
  5471  			case "count":
  5472  				entry.Count, err = rd.ReadInt()
  5473  			case "reason":
  5474  				entry.Reason, err = rd.ReadString()
  5475  			case "context":
  5476  				entry.Context, err = rd.ReadString()
  5477  			case "object":
  5478  				entry.Object, err = rd.ReadString()
  5479  			case "username":
  5480  				entry.Username, err = rd.ReadString()
  5481  			case "age-seconds":
  5482  				entry.AgeSeconds, err = rd.ReadFloat()
  5483  			case "client-info":
  5484  				txt, err := rd.ReadString()
  5485  				if err != nil {
  5486  					return err
  5487  				}
  5488  				entry.ClientInfo, err = parseClientInfo(strings.TrimSpace(txt))
  5489  				if err != nil {
  5490  					return err
  5491  				}
  5492  			case "entry-id":
  5493  				entry.EntryID, err = rd.ReadInt()
  5494  			case "timestamp-created":
  5495  				entry.TimestampCreated, err = rd.ReadInt()
  5496  			case "timestamp-last-updated":
  5497  				entry.TimestampLastUpdated, err = rd.ReadInt()
  5498  			default:
  5499  				return fmt.Errorf("redis: unexpected key %q in ACL LOG reply", key)
  5500  			}
  5501  
  5502  			if err != nil {
  5503  				return err
  5504  			}
  5505  		}
  5506  	}
  5507  
  5508  	return nil
  5509  }
  5510  
  5511  // LibraryInfo holds the library info.
  5512  type LibraryInfo struct {
  5513  	LibName *string
  5514  	LibVer  *string
  5515  }
  5516  
  5517  // WithLibraryName returns a valid LibraryInfo with library name only.
  5518  func WithLibraryName(libName string) LibraryInfo {
  5519  	return LibraryInfo{LibName: &libName}
  5520  }
  5521  
  5522  // WithLibraryVersion returns a valid LibraryInfo with library version only.
  5523  func WithLibraryVersion(libVer string) LibraryInfo {
  5524  	return LibraryInfo{LibVer: &libVer}
  5525  }
  5526  
  5527  // -------------------------------------------
  5528  
  5529  type InfoCmd struct {
  5530  	baseCmd
  5531  	val map[string]map[string]string
  5532  }
  5533  
  5534  var _ Cmder = (*InfoCmd)(nil)
  5535  
  5536  func NewInfoCmd(ctx context.Context, args ...interface{}) *InfoCmd {
  5537  	return &InfoCmd{
  5538  		baseCmd: baseCmd{
  5539  			ctx:  ctx,
  5540  			args: args,
  5541  		},
  5542  	}
  5543  }
  5544  
  5545  func (cmd *InfoCmd) SetVal(val map[string]map[string]string) {
  5546  	cmd.val = val
  5547  }
  5548  
  5549  func (cmd *InfoCmd) Val() map[string]map[string]string {
  5550  	return cmd.val
  5551  }
  5552  
  5553  func (cmd *InfoCmd) Result() (map[string]map[string]string, error) {
  5554  	return cmd.val, cmd.err
  5555  }
  5556  
  5557  func (cmd *InfoCmd) String() string {
  5558  	return cmdString(cmd, cmd.val)
  5559  }
  5560  
  5561  func (cmd *InfoCmd) readReply(rd *proto.Reader) error {
  5562  	val, err := rd.ReadString()
  5563  	if err != nil {
  5564  		return err
  5565  	}
  5566  
  5567  	section := ""
  5568  	scanner := bufio.NewScanner(strings.NewReader(val))
  5569  	for scanner.Scan() {
  5570  		line := scanner.Text()
  5571  		if strings.HasPrefix(line, "#") {
  5572  			if cmd.val == nil {
  5573  				cmd.val = make(map[string]map[string]string)
  5574  			}
  5575  			section = strings.TrimPrefix(line, "# ")
  5576  			cmd.val[section] = make(map[string]string)
  5577  		} else if line != "" {
  5578  			if section == "Modules" {
  5579  				moduleRe := regexp.MustCompile(`module:name=(.+?),(.+)$`)
  5580  				kv := moduleRe.FindStringSubmatch(line)
  5581  				if len(kv) == 3 {
  5582  					cmd.val[section][kv[1]] = kv[2]
  5583  				}
  5584  			} else {
  5585  				kv := strings.SplitN(line, ":", 2)
  5586  				if len(kv) == 2 {
  5587  					cmd.val[section][kv[0]] = kv[1]
  5588  				}
  5589  			}
  5590  		}
  5591  	}
  5592  
  5593  	return nil
  5594  }
  5595  
  5596  func (cmd *InfoCmd) Item(section, key string) string {
  5597  	if cmd.val == nil {
  5598  		return ""
  5599  	} else if cmd.val[section] == nil {
  5600  		return ""
  5601  	} else {
  5602  		return cmd.val[section][key]
  5603  	}
  5604  }
  5605  
  5606  type MonitorStatus int
  5607  
  5608  const (
  5609  	monitorStatusIdle MonitorStatus = iota
  5610  	monitorStatusStart
  5611  	monitorStatusStop
  5612  )
  5613  
  5614  type MonitorCmd struct {
  5615  	baseCmd
  5616  	ch     chan string
  5617  	status MonitorStatus
  5618  	mu     sync.Mutex
  5619  }
  5620  
  5621  func newMonitorCmd(ctx context.Context, ch chan string) *MonitorCmd {
  5622  	return &MonitorCmd{
  5623  		baseCmd: baseCmd{
  5624  			ctx:  ctx,
  5625  			args: []interface{}{"monitor"},
  5626  		},
  5627  		ch:     ch,
  5628  		status: monitorStatusIdle,
  5629  		mu:     sync.Mutex{},
  5630  	}
  5631  }
  5632  
  5633  func (cmd *MonitorCmd) String() string {
  5634  	return cmdString(cmd, nil)
  5635  }
  5636  
  5637  func (cmd *MonitorCmd) readReply(rd *proto.Reader) error {
  5638  	ctx, cancel := context.WithCancel(cmd.ctx)
  5639  	go func(ctx context.Context) {
  5640  		for {
  5641  			select {
  5642  			case <-ctx.Done():
  5643  				return
  5644  			default:
  5645  				err := cmd.readMonitor(rd, cancel)
  5646  				if err != nil {
  5647  					cmd.err = err
  5648  					return
  5649  				}
  5650  			}
  5651  		}
  5652  	}(ctx)
  5653  	return nil
  5654  }
  5655  
  5656  func (cmd *MonitorCmd) readMonitor(rd *proto.Reader, cancel context.CancelFunc) error {
  5657  	for {
  5658  		cmd.mu.Lock()
  5659  		st := cmd.status
  5660  		pk, _ := rd.Peek(1)
  5661  		cmd.mu.Unlock()
  5662  		if len(pk) != 0 && st == monitorStatusStart {
  5663  			cmd.mu.Lock()
  5664  			line, err := rd.ReadString()
  5665  			cmd.mu.Unlock()
  5666  			if err != nil {
  5667  				return err
  5668  			}
  5669  			cmd.ch <- line
  5670  		}
  5671  		if st == monitorStatusStop {
  5672  			cancel()
  5673  			break
  5674  		}
  5675  	}
  5676  	return nil
  5677  }
  5678  
  5679  func (cmd *MonitorCmd) Start() {
  5680  	cmd.mu.Lock()
  5681  	defer cmd.mu.Unlock()
  5682  	cmd.status = monitorStatusStart
  5683  }
  5684  
  5685  func (cmd *MonitorCmd) Stop() {
  5686  	cmd.mu.Lock()
  5687  	defer cmd.mu.Unlock()
  5688  	cmd.status = monitorStatusStop
  5689  }
  5690  
  5691  type VectorScoreSliceCmd struct {
  5692  	baseCmd
  5693  
  5694  	val []VectorScore
  5695  }
  5696  
  5697  var _ Cmder = (*VectorScoreSliceCmd)(nil)
  5698  
  5699  func NewVectorInfoSliceCmd(ctx context.Context, args ...any) *VectorScoreSliceCmd {
  5700  	return &VectorScoreSliceCmd{
  5701  		baseCmd: baseCmd{
  5702  			ctx:  ctx,
  5703  			args: args,
  5704  		},
  5705  	}
  5706  }
  5707  
  5708  func (cmd *VectorScoreSliceCmd) SetVal(val []VectorScore) {
  5709  	cmd.val = val
  5710  }
  5711  
  5712  func (cmd *VectorScoreSliceCmd) Val() []VectorScore {
  5713  	return cmd.val
  5714  }
  5715  
  5716  func (cmd *VectorScoreSliceCmd) Result() ([]VectorScore, error) {
  5717  	return cmd.val, cmd.err
  5718  }
  5719  
  5720  func (cmd *VectorScoreSliceCmd) String() string {
  5721  	return cmdString(cmd, cmd.val)
  5722  }
  5723  
  5724  func (cmd *VectorScoreSliceCmd) readReply(rd *proto.Reader) error {
  5725  	n, err := rd.ReadMapLen()
  5726  	if err != nil {
  5727  		return err
  5728  	}
  5729  
  5730  	cmd.val = make([]VectorScore, n)
  5731  	for i := 0; i < n; i++ {
  5732  		name, err := rd.ReadString()
  5733  		if err != nil {
  5734  			return err
  5735  		}
  5736  		cmd.val[i].Name = name
  5737  
  5738  		score, err := rd.ReadFloat()
  5739  		if err != nil {
  5740  			return err
  5741  		}
  5742  		cmd.val[i].Score = score
  5743  	}
  5744  	return nil
  5745  }
  5746  

View as plain text