forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/redis/go-redis/v9/command.go

8792 lines
111 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
package redis
import (
"bufio"
"context"
"fmt"
"net"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/redis/go-redis/v9/internal"
"github.com/redis/go-redis/v9/internal/hscan"
"github.com/redis/go-redis/v9/internal/proto"
"github.com/redis/go-redis/v9/internal/util"
)
type Cmder interface {
2024-02-18 10:42:21 +00:00
// command name.
2024-02-18 10:42:21 +00:00
// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster".
2024-02-18 10:42:21 +00:00
Name() string
// full command name.
2024-02-18 10:42:21 +00:00
// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster info".
2024-02-18 10:42:21 +00:00
FullName() string
// all args of the command.
2024-02-18 10:42:21 +00:00
// e.g. "set k v ex 10" -> "[set k v ex 10]".
2024-02-18 10:42:21 +00:00
Args() []interface{}
// format request and response string.
2024-02-18 10:42:21 +00:00
// e.g. "set k v ex 10" -> "set k v ex 10: OK", "get k" -> "get k: v".
2024-02-18 10:42:21 +00:00
String() string
stringArg(int) string
2024-02-18 10:42:21 +00:00
firstKeyPos() int8
2024-02-18 10:42:21 +00:00
SetFirstKeyPos(int8)
readTimeout() *time.Duration
2024-02-18 10:42:21 +00:00
readReply(rd *proto.Reader) error
SetErr(error)
2024-02-18 10:42:21 +00:00
Err() error
}
func setCmdsErr(cmds []Cmder, e error) {
2024-02-18 10:42:21 +00:00
for _, cmd := range cmds {
2024-02-18 10:42:21 +00:00
if cmd.Err() == nil {
2024-02-18 10:42:21 +00:00
cmd.SetErr(e)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func cmdsFirstErr(cmds []Cmder) error {
2024-02-18 10:42:21 +00:00
for _, cmd := range cmds {
2024-02-18 10:42:21 +00:00
if err := cmd.Err(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func writeCmds(wr *proto.Writer, cmds []Cmder) error {
2024-02-18 10:42:21 +00:00
for _, cmd := range cmds {
2024-02-18 10:42:21 +00:00
if err := writeCmd(wr, cmd); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func writeCmd(wr *proto.Writer, cmd Cmder) error {
2024-02-18 10:42:21 +00:00
return wr.WriteArgs(cmd.Args())
2024-02-18 10:42:21 +00:00
}
func cmdFirstKeyPos(cmd Cmder) int {
2024-02-18 10:42:21 +00:00
if pos := cmd.firstKeyPos(); pos != 0 {
2024-02-18 10:42:21 +00:00
return int(pos)
2024-02-18 10:42:21 +00:00
}
switch cmd.Name() {
2024-02-18 10:42:21 +00:00
case "eval", "evalsha", "eval_ro", "evalsha_ro":
2024-02-18 10:42:21 +00:00
if cmd.stringArg(2) != "0" {
2024-02-18 10:42:21 +00:00
return 3
2024-02-18 10:42:21 +00:00
}
return 0
2024-02-18 10:42:21 +00:00
case "publish":
2024-02-18 10:42:21 +00:00
return 1
2024-02-18 10:42:21 +00:00
case "memory":
2024-02-18 10:42:21 +00:00
// https://github.com/redis/redis/issues/7493
2024-02-18 10:42:21 +00:00
if cmd.stringArg(1) == "usage" {
2024-02-18 10:42:21 +00:00
return 2
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 1
2024-02-18 10:42:21 +00:00
}
func cmdString(cmd Cmder, val interface{}) string {
2024-02-18 10:42:21 +00:00
b := make([]byte, 0, 64)
for i, arg := range cmd.Args() {
2024-02-18 10:42:21 +00:00
if i > 0 {
2024-02-18 10:42:21 +00:00
b = append(b, ' ')
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
b = internal.AppendArg(b, arg)
2024-02-18 10:42:21 +00:00
}
if err := cmd.Err(); err != nil {
2024-02-18 10:42:21 +00:00
b = append(b, ": "...)
2024-02-18 10:42:21 +00:00
b = append(b, err.Error()...)
2024-02-18 10:42:21 +00:00
} else if val != nil {
2024-02-18 10:42:21 +00:00
b = append(b, ": "...)
2024-02-18 10:42:21 +00:00
b = internal.AppendArg(b, val)
2024-02-18 10:42:21 +00:00
}
return util.BytesToString(b)
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type baseCmd struct {
ctx context.Context
args []interface{}
err error
2024-02-18 10:42:21 +00:00
keyPos int8
_readTimeout *time.Duration
}
var _ Cmder = (*Cmd)(nil)
func (cmd *baseCmd) Name() string {
2024-02-18 10:42:21 +00:00
if len(cmd.args) == 0 {
2024-02-18 10:42:21 +00:00
return ""
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
// Cmd name must be lower cased.
2024-02-18 10:42:21 +00:00
return internal.ToLower(cmd.stringArg(0))
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) FullName() string {
2024-02-18 10:42:21 +00:00
switch name := cmd.Name(); name {
2024-02-18 10:42:21 +00:00
case "cluster", "command":
2024-02-18 10:42:21 +00:00
if len(cmd.args) == 1 {
2024-02-18 10:42:21 +00:00
return name
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if s2, ok := cmd.args[1].(string); ok {
2024-02-18 10:42:21 +00:00
return name + " " + s2
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return name
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return name
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) Args() []interface{} {
2024-02-18 10:42:21 +00:00
return cmd.args
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) stringArg(pos int) string {
2024-02-18 10:42:21 +00:00
if pos < 0 || pos >= len(cmd.args) {
2024-02-18 10:42:21 +00:00
return ""
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
arg := cmd.args[pos]
2024-02-18 10:42:21 +00:00
switch v := arg.(type) {
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return v
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
// TODO: consider using appendArg
2024-02-18 10:42:21 +00:00
return fmt.Sprint(v)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) firstKeyPos() int8 {
2024-02-18 10:42:21 +00:00
return cmd.keyPos
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) {
2024-02-18 10:42:21 +00:00
cmd.keyPos = keyPos
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) SetErr(e error) {
2024-02-18 10:42:21 +00:00
cmd.err = e
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) Err() error {
2024-02-18 10:42:21 +00:00
return cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) readTimeout() *time.Duration {
2024-02-18 10:42:21 +00:00
return cmd._readTimeout
2024-02-18 10:42:21 +00:00
}
func (cmd *baseCmd) setReadTimeout(d time.Duration) {
2024-02-18 10:42:21 +00:00
cmd._readTimeout = &d
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type Cmd struct {
baseCmd
val interface{}
}
func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
2024-02-18 10:42:21 +00:00
return &Cmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) SetVal(val interface{}) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Val() interface{} {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Result() (interface{}, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Text() (string, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return "", cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return toString(cmd.val)
2024-02-18 10:42:21 +00:00
}
func toString(val interface{}) (string, error) {
2024-02-18 10:42:21 +00:00
switch val := val.(type) {
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return val, nil
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := fmt.Errorf("redis: unexpected type=%T for String", val)
2024-02-18 10:42:21 +00:00
return "", err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Int() (int, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
switch val := cmd.val.(type) {
2024-02-18 10:42:21 +00:00
case int64:
2024-02-18 10:42:21 +00:00
return int(val), nil
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := fmt.Errorf("redis: unexpected type=%T for Int", val)
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Int64() (int64, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return toInt64(cmd.val)
2024-02-18 10:42:21 +00:00
}
func toInt64(val interface{}) (int64, error) {
2024-02-18 10:42:21 +00:00
switch val := val.(type) {
2024-02-18 10:42:21 +00:00
case int64:
2024-02-18 10:42:21 +00:00
return val, nil
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return strconv.ParseInt(val, 10, 64)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Uint64() (uint64, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return toUint64(cmd.val)
2024-02-18 10:42:21 +00:00
}
func toUint64(val interface{}) (uint64, error) {
2024-02-18 10:42:21 +00:00
switch val := val.(type) {
2024-02-18 10:42:21 +00:00
case int64:
2024-02-18 10:42:21 +00:00
return uint64(val), nil
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return strconv.ParseUint(val, 10, 64)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Float32() (float32, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return toFloat32(cmd.val)
2024-02-18 10:42:21 +00:00
}
func toFloat32(val interface{}) (float32, error) {
2024-02-18 10:42:21 +00:00
switch val := val.(type) {
2024-02-18 10:42:21 +00:00
case int64:
2024-02-18 10:42:21 +00:00
return float32(val), nil
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
f, err := strconv.ParseFloat(val, 32)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return float32(f), nil
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Float64() (float64, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return toFloat64(cmd.val)
2024-02-18 10:42:21 +00:00
}
func toFloat64(val interface{}) (float64, error) {
2024-02-18 10:42:21 +00:00
switch val := val.(type) {
2024-02-18 10:42:21 +00:00
case int64:
2024-02-18 10:42:21 +00:00
return float64(val), nil
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return strconv.ParseFloat(val, 64)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Bool() (bool, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return false, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return toBool(cmd.val)
2024-02-18 10:42:21 +00:00
}
func toBool(val interface{}) (bool, error) {
2024-02-18 10:42:21 +00:00
switch val := val.(type) {
2024-02-18 10:42:21 +00:00
case bool:
2024-02-18 10:42:21 +00:00
return val, nil
2024-02-18 10:42:21 +00:00
case int64:
2024-02-18 10:42:21 +00:00
return val != 0, nil
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return strconv.ParseBool(val)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
2024-02-18 10:42:21 +00:00
return false, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Slice() ([]interface{}, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return nil, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
switch val := cmd.val.(type) {
2024-02-18 10:42:21 +00:00
case []interface{}:
2024-02-18 10:42:21 +00:00
return val, nil
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: unexpected type=%T for Slice", val)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) StringSlice() ([]string, error) {
2024-02-18 10:42:21 +00:00
slice, err := cmd.Slice()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
ss := make([]string, len(slice))
2024-02-18 10:42:21 +00:00
for i, iface := range slice {
2024-02-18 10:42:21 +00:00
val, err := toString(iface)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
ss[i] = val
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return ss, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Int64Slice() ([]int64, error) {
2024-02-18 10:42:21 +00:00
slice, err := cmd.Slice()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
nums := make([]int64, len(slice))
2024-02-18 10:42:21 +00:00
for i, iface := range slice {
2024-02-18 10:42:21 +00:00
val, err := toInt64(iface)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
nums[i] = val
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nums, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Uint64Slice() ([]uint64, error) {
2024-02-18 10:42:21 +00:00
slice, err := cmd.Slice()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
nums := make([]uint64, len(slice))
2024-02-18 10:42:21 +00:00
for i, iface := range slice {
2024-02-18 10:42:21 +00:00
val, err := toUint64(iface)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
nums[i] = val
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nums, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Float32Slice() ([]float32, error) {
2024-02-18 10:42:21 +00:00
slice, err := cmd.Slice()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
floats := make([]float32, len(slice))
2024-02-18 10:42:21 +00:00
for i, iface := range slice {
2024-02-18 10:42:21 +00:00
val, err := toFloat32(iface)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
floats[i] = val
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return floats, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) Float64Slice() ([]float64, error) {
2024-02-18 10:42:21 +00:00
slice, err := cmd.Slice()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
floats := make([]float64, len(slice))
2024-02-18 10:42:21 +00:00
for i, iface := range slice {
2024-02-18 10:42:21 +00:00
val, err := toFloat64(iface)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
floats[i] = val
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return floats, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) BoolSlice() ([]bool, error) {
2024-02-18 10:42:21 +00:00
slice, err := cmd.Slice()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
bools := make([]bool, len(slice))
2024-02-18 10:42:21 +00:00
for i, iface := range slice {
2024-02-18 10:42:21 +00:00
val, err := toBool(iface)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
bools[i] = val
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return bools, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = rd.ReadReply()
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type SliceCmd struct {
baseCmd
val []interface{}
}
var _ Cmder = (*SliceCmd)(nil)
func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
2024-02-18 10:42:21 +00:00
return &SliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *SliceCmd) SetVal(val []interface{}) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *SliceCmd) Val() []interface{} {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *SliceCmd) Result() ([]interface{}, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *SliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
// Scan scans the results from the map into a destination struct. The map keys
2024-02-18 10:42:21 +00:00
// are matched in the Redis struct fields by the `redis:"field"` tag.
2024-02-18 10:42:21 +00:00
func (cmd *SliceCmd) Scan(dst interface{}) error {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return cmd.err
2024-02-18 10:42:21 +00:00
}
// Pass the list of keys and values.
2024-02-18 10:42:21 +00:00
// Skip the first two args for: HMGET key
2024-02-18 10:42:21 +00:00
var args []interface{}
2024-02-18 10:42:21 +00:00
if cmd.args[0] == "hmget" {
2024-02-18 10:42:21 +00:00
args = cmd.args[2:]
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
// Otherwise, it's: MGET field field ...
2024-02-18 10:42:21 +00:00
args = cmd.args[1:]
2024-02-18 10:42:21 +00:00
}
return hscan.Scan(dst, args, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *SliceCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = rd.ReadSlice()
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type StatusCmd struct {
baseCmd
val string
}
var _ Cmder = (*StatusCmd)(nil)
func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
2024-02-18 10:42:21 +00:00
return &StatusCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *StatusCmd) SetVal(val string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *StatusCmd) Val() string {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *StatusCmd) Result() (string, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *StatusCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type IntCmd struct {
baseCmd
val int64
}
var _ Cmder = (*IntCmd)(nil)
func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
2024-02-18 10:42:21 +00:00
return &IntCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *IntCmd) SetVal(val int64) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *IntCmd) Val() int64 {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *IntCmd) Result() (int64, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *IntCmd) Uint64() (uint64, error) {
2024-02-18 10:42:21 +00:00
return uint64(cmd.val), cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *IntCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type IntSliceCmd struct {
baseCmd
val []int64
}
var _ Cmder = (*IntSliceCmd)(nil)
func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd {
2024-02-18 10:42:21 +00:00
return &IntSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *IntSliceCmd) SetVal(val []int64) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *IntSliceCmd) Val() []int64 {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *IntSliceCmd) Result() ([]int64, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *IntSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]int64, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
if cmd.val[i], err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type DurationCmd struct {
baseCmd
val time.Duration
2024-02-18 10:42:21 +00:00
precision time.Duration
}
var _ Cmder = (*DurationCmd)(nil)
func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd {
2024-02-18 10:42:21 +00:00
return &DurationCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
2024-02-18 10:42:21 +00:00
precision: precision,
}
2024-02-18 10:42:21 +00:00
}
func (cmd *DurationCmd) SetVal(val time.Duration) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *DurationCmd) Val() time.Duration {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *DurationCmd) Result() (time.Duration, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *DurationCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
switch n {
2024-02-18 10:42:21 +00:00
// -2 if the key does not exist
2024-02-18 10:42:21 +00:00
// -1 if the key exists but has no associated expire
2024-02-18 10:42:21 +00:00
case -2, -1:
2024-02-18 10:42:21 +00:00
cmd.val = time.Duration(n)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
cmd.val = time.Duration(n) * cmd.precision
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type TimeCmd struct {
baseCmd
val time.Time
}
var _ Cmder = (*TimeCmd)(nil)
func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
2024-02-18 10:42:21 +00:00
return &TimeCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *TimeCmd) SetVal(val time.Time) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *TimeCmd) Val() time.Time {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *TimeCmd) Result() (time.Time, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *TimeCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
if err := rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
second, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
microsecond, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = time.Unix(second, microsecond*1000)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type BoolCmd struct {
baseCmd
val bool
}
var _ Cmder = (*BoolCmd)(nil)
func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
2024-02-18 10:42:21 +00:00
return &BoolCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolCmd) SetVal(val bool) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolCmd) Val() bool {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolCmd) Result() (bool, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = rd.ReadBool()
// `SET key value NX` returns nil when key already exists. But
2024-02-18 10:42:21 +00:00
// `SETNX key value` returns bool (0/1). So convert nil to bool.
2024-02-18 10:42:21 +00:00
if err == Nil {
2024-02-18 10:42:21 +00:00
cmd.val = false
2024-02-18 10:42:21 +00:00
err = nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type StringCmd struct {
baseCmd
val string
}
var _ Cmder = (*StringCmd)(nil)
func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
2024-02-18 10:42:21 +00:00
return &StringCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) SetVal(val string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Val() string {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Result() (string, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Bytes() ([]byte, error) {
2024-02-18 10:42:21 +00:00
return util.StringToBytes(cmd.val), cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Bool() (bool, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return false, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return strconv.ParseBool(cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Int() (int, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return strconv.Atoi(cmd.Val())
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Int64() (int64, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return strconv.ParseInt(cmd.Val(), 10, 64)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Uint64() (uint64, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return strconv.ParseUint(cmd.Val(), 10, 64)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Float32() (float32, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
f, err := strconv.ParseFloat(cmd.Val(), 32)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return float32(f), nil
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Float64() (float64, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return 0, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return strconv.ParseFloat(cmd.Val(), 64)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Time() (time.Time, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return time.Time{}, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return time.Parse(time.RFC3339Nano, cmd.Val())
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) Scan(val interface{}) error {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return proto.Scan([]byte(cmd.val), val)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type FloatCmd struct {
baseCmd
val float64
}
var _ Cmder = (*FloatCmd)(nil)
func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
2024-02-18 10:42:21 +00:00
return &FloatCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatCmd) SetVal(val float64) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatCmd) Val() float64 {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatCmd) Result() (float64, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = rd.ReadFloat()
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type FloatSliceCmd struct {
baseCmd
val []float64
}
var _ Cmder = (*FloatSliceCmd)(nil)
func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSliceCmd {
2024-02-18 10:42:21 +00:00
return &FloatSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatSliceCmd) SetVal(val []float64) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatSliceCmd) Val() []float64 {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatSliceCmd) Result() ([]float64, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make([]float64, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
switch num, err := rd.ReadFloat(); {
2024-02-18 10:42:21 +00:00
case err == Nil:
2024-02-18 10:42:21 +00:00
cmd.val[i] = 0
2024-02-18 10:42:21 +00:00
case err != nil:
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
cmd.val[i] = num
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type StringSliceCmd struct {
baseCmd
val []string
}
var _ Cmder = (*StringSliceCmd)(nil)
func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd {
2024-02-18 10:42:21 +00:00
return &StringSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *StringSliceCmd) SetVal(val []string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *StringSliceCmd) Val() []string {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *StringSliceCmd) Result() ([]string, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *StringSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
2024-02-18 10:42:21 +00:00
return proto.ScanSlice(cmd.Val(), container)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]string, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
switch s, err := rd.ReadString(); {
2024-02-18 10:42:21 +00:00
case err == Nil:
2024-02-18 10:42:21 +00:00
cmd.val[i] = ""
2024-02-18 10:42:21 +00:00
case err != nil:
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
cmd.val[i] = s
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type KeyValue struct {
Key string
2024-02-18 10:42:21 +00:00
Value string
}
type KeyValueSliceCmd struct {
baseCmd
val []KeyValue
}
var _ Cmder = (*KeyValueSliceCmd)(nil)
func NewKeyValueSliceCmd(ctx context.Context, args ...interface{}) *KeyValueSliceCmd {
2024-02-18 10:42:21 +00:00
return &KeyValueSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValueSliceCmd) SetVal(val []KeyValue) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValueSliceCmd) Val() []KeyValue {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValueSliceCmd) Result() ([]KeyValue, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValueSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
// Many commands will respond to two formats:
2024-02-18 10:42:21 +00:00
// 1. 1) "one"
2024-02-18 10:42:21 +00:00
// 2. (double) 1
2024-02-18 10:42:21 +00:00
// 2. 1) "two"
2024-02-18 10:42:21 +00:00
// 2. (double) 2
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// OR:
2024-02-18 10:42:21 +00:00
// 1. "two"
2024-02-18 10:42:21 +00:00
// 2. (double) 2
2024-02-18 10:42:21 +00:00
// 3. "one"
2024-02-18 10:42:21 +00:00
// 4. (double) 1
2024-02-18 10:42:21 +00:00
func (cmd *KeyValueSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// If the n is 0, can't continue reading.
2024-02-18 10:42:21 +00:00
if n == 0 {
2024-02-18 10:42:21 +00:00
cmd.val = make([]KeyValue, 0)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
typ, err := rd.PeekReplyType()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
array := typ == proto.RespArray
if array {
2024-02-18 10:42:21 +00:00
cmd.val = make([]KeyValue, n)
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
cmd.val = make([]KeyValue, n/2)
2024-02-18 10:42:21 +00:00
}
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
if array {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Key, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Value, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type BoolSliceCmd struct {
baseCmd
val []bool
}
var _ Cmder = (*BoolSliceCmd)(nil)
func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd {
2024-02-18 10:42:21 +00:00
return &BoolSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolSliceCmd) SetVal(val []bool) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolSliceCmd) Val() []bool {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolSliceCmd) Result() ([]bool, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]bool, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
if cmd.val[i], err = rd.ReadBool(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type MapStringStringCmd struct {
baseCmd
val map[string]string
}
var _ Cmder = (*MapStringStringCmd)(nil)
func NewMapStringStringCmd(ctx context.Context, args ...interface{}) *MapStringStringCmd {
2024-02-18 10:42:21 +00:00
return &MapStringStringCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringCmd) Val() map[string]string {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringCmd) SetVal(val map[string]string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringCmd) Result() (map[string]string, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
// Scan scans the results from the map into a destination struct. The map keys
2024-02-18 10:42:21 +00:00
// are matched in the Redis struct fields by the `redis:"field"` tag.
2024-02-18 10:42:21 +00:00
func (cmd *MapStringStringCmd) Scan(dest interface{}) error {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return cmd.err
2024-02-18 10:42:21 +00:00
}
strct, err := hscan.Struct(dest)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
for k, v := range cmd.val {
2024-02-18 10:42:21 +00:00
if err := strct.Scan(k, v); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make(map[string]string, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
value, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val[key] = value
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type MapStringIntCmd struct {
baseCmd
val map[string]int64
}
var _ Cmder = (*MapStringIntCmd)(nil)
func NewMapStringIntCmd(ctx context.Context, args ...interface{}) *MapStringIntCmd {
2024-02-18 10:42:21 +00:00
return &MapStringIntCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringIntCmd) SetVal(val map[string]int64) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringIntCmd) Val() map[string]int64 {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringIntCmd) Result() (map[string]int64, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringIntCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringIntCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make(map[string]int64, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
nn, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[key] = nn
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
// ------------------------------------------------------------------------------
2024-02-18 10:42:21 +00:00
type MapStringSliceInterfaceCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val map[string][]interface{}
}
func NewMapStringSliceInterfaceCmd(ctx context.Context, args ...interface{}) *MapStringSliceInterfaceCmd {
2024-02-18 10:42:21 +00:00
return &MapStringSliceInterfaceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringSliceInterfaceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringSliceInterfaceCmd) SetVal(val map[string][]interface{}) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringSliceInterfaceCmd) Result() (map[string][]interface{}, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringSliceInterfaceCmd) Val() map[string][]interface{} {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make(map[string][]interface{}, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
k, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[k] = make([]interface{}, nn)
2024-02-18 10:42:21 +00:00
for j := 0; j < nn; j++ {
2024-02-18 10:42:21 +00:00
value, err := rd.ReadReply()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[k][j] = value
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type StringStructMapCmd struct {
baseCmd
val map[string]struct{}
}
var _ Cmder = (*StringStructMapCmd)(nil)
func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd {
2024-02-18 10:42:21 +00:00
return &StringStructMapCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *StringStructMapCmd) SetVal(val map[string]struct{}) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *StringStructMapCmd) Val() map[string]struct{} {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *StringStructMapCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make(map[string]struct{}, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[key] = struct{}{}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XMessage struct {
ID string
2024-02-18 10:42:21 +00:00
Values map[string]interface{}
}
type XMessageSliceCmd struct {
baseCmd
val []XMessage
}
var _ Cmder = (*XMessageSliceCmd)(nil)
func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd {
2024-02-18 10:42:21 +00:00
return &XMessageSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XMessageSliceCmd) SetVal(val []XMessage) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XMessageSliceCmd) Val() []XMessage {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XMessageSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
cmd.val, err = readXMessageSlice(rd)
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
msgs := make([]XMessage, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < len(msgs); i++ {
2024-02-18 10:42:21 +00:00
if msgs[i], err = readXMessage(rd); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return msgs, nil
2024-02-18 10:42:21 +00:00
}
func readXMessage(rd *proto.Reader) (XMessage, error) {
2024-02-18 10:42:21 +00:00
if err := rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return XMessage{}, err
2024-02-18 10:42:21 +00:00
}
id, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return XMessage{}, err
2024-02-18 10:42:21 +00:00
}
v, err := stringInterfaceMapParser(rd)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
if err != proto.Nil {
2024-02-18 10:42:21 +00:00
return XMessage{}, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return XMessage{
ID: id,
2024-02-18 10:42:21 +00:00
Values: v,
}, nil
2024-02-18 10:42:21 +00:00
}
func stringInterfaceMapParser(rd *proto.Reader) (map[string]interface{}, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
m := make(map[string]interface{}, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
value, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
m[key] = value
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return m, nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XStream struct {
Stream string
2024-02-18 10:42:21 +00:00
Messages []XMessage
}
type XStreamSliceCmd struct {
baseCmd
val []XStream
}
var _ Cmder = (*XStreamSliceCmd)(nil)
func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd {
2024-02-18 10:42:21 +00:00
return &XStreamSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XStreamSliceCmd) SetVal(val []XStream) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XStreamSliceCmd) Val() []XStream {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XStreamSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
typ, err := rd.PeekReplyType()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
var n int
2024-02-18 10:42:21 +00:00
if typ == proto.RespMap {
2024-02-18 10:42:21 +00:00
n, err = rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
n, err = rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]XStream, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
if typ != proto.RespMap {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.val[i].Stream, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.val[i].Messages, err = readXMessageSlice(rd); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XPending struct {
Count int64
Lower string
Higher string
2024-02-18 10:42:21 +00:00
Consumers map[string]int64
}
type XPendingCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val *XPending
}
var _ Cmder = (*XPendingCmd)(nil)
func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd {
2024-02-18 10:42:21 +00:00
return &XPendingCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingCmd) SetVal(val *XPending) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingCmd) Val() *XPending {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingCmd) Result() (*XPending, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
var err error
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(4); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = &XPending{}
if cmd.val.Count, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val.Lower, err = rd.ReadString(); err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val.Higher, err = rd.ReadString(); err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val.Consumers = make(map[string]int64, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
consumerName, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
consumerPending, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val.Consumers[consumerName] = consumerPending
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XPendingExt struct {
ID string
Consumer string
Idle time.Duration
2024-02-18 10:42:21 +00:00
RetryCount int64
}
type XPendingExtCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val []XPendingExt
}
var _ Cmder = (*XPendingExtCmd)(nil)
func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd {
2024-02-18 10:42:21 +00:00
return &XPendingExtCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingExtCmd) SetVal(val []XPendingExt) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingExtCmd) Val() []XPendingExt {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingExtCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]XPendingExt, n)
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(4); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].ID, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Consumer, err = rd.ReadString(); err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
idle, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i].Idle = time.Duration(idle) * time.Millisecond
if cmd.val[i].RetryCount, err = rd.ReadInt(); err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XAutoClaimCmd struct {
baseCmd
start string
val []XMessage
2024-02-18 10:42:21 +00:00
}
var _ Cmder = (*XAutoClaimCmd)(nil)
func NewXAutoClaimCmd(ctx context.Context, args ...interface{}) *XAutoClaimCmd {
2024-02-18 10:42:21 +00:00
return &XAutoClaimCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimCmd) SetVal(val []XMessage, start string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
cmd.start = start
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimCmd) Val() (messages []XMessage, start string) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.start
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimCmd) Result() (messages []XMessage, start string, err error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.start, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch n {
2024-02-18 10:42:21 +00:00
case 2, // Redis 6
2024-02-18 10:42:21 +00:00
3: // Redis 7:
2024-02-18 10:42:21 +00:00
// ok
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements in XAutoClaim reply, wanted 2/3", n)
2024-02-18 10:42:21 +00:00
}
cmd.start, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val, err = readXMessageSlice(rd)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if n >= 3 {
2024-02-18 10:42:21 +00:00
if err := rd.DiscardNext(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XAutoClaimJustIDCmd struct {
baseCmd
start string
val []string
2024-02-18 10:42:21 +00:00
}
var _ Cmder = (*XAutoClaimJustIDCmd)(nil)
func NewXAutoClaimJustIDCmd(ctx context.Context, args ...interface{}) *XAutoClaimJustIDCmd {
2024-02-18 10:42:21 +00:00
return &XAutoClaimJustIDCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimJustIDCmd) SetVal(val []string, start string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
cmd.start = start
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimJustIDCmd) Val() (ids []string, start string) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.start
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimJustIDCmd) Result() (ids []string, start string, err error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.start, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimJustIDCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XAutoClaimJustIDCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch n {
2024-02-18 10:42:21 +00:00
case 2, // Redis 6
2024-02-18 10:42:21 +00:00
3: // Redis 7:
2024-02-18 10:42:21 +00:00
// ok
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements in XAutoClaimJustID reply, wanted 2/3", n)
2024-02-18 10:42:21 +00:00
}
cmd.start, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
nn, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make([]string, nn)
2024-02-18 10:42:21 +00:00
for i := 0; i < nn; i++ {
2024-02-18 10:42:21 +00:00
cmd.val[i], err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if n >= 3 {
2024-02-18 10:42:21 +00:00
if err := rd.DiscardNext(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XInfoConsumersCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val []XInfoConsumer
}
type XInfoConsumer struct {
Name string
Pending int64
Idle time.Duration
2024-02-18 10:42:21 +00:00
Inactive time.Duration
}
var _ Cmder = (*XInfoConsumersCmd)(nil)
func NewXInfoConsumersCmd(ctx context.Context, stream string, group string) *XInfoConsumersCmd {
2024-02-18 10:42:21 +00:00
return &XInfoConsumersCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: []interface{}{"xinfo", "consumers", stream, group},
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoConsumersCmd) SetVal(val []XInfoConsumer) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoConsumersCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]XInfoConsumer, n)
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
var key string
2024-02-18 10:42:21 +00:00
for f := 0; f < nn; f++ {
2024-02-18 10:42:21 +00:00
key, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "name":
2024-02-18 10:42:21 +00:00
cmd.val[i].Name, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "pending":
2024-02-18 10:42:21 +00:00
cmd.val[i].Pending, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "idle":
2024-02-18 10:42:21 +00:00
var idle int64
2024-02-18 10:42:21 +00:00
idle, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
cmd.val[i].Idle = time.Duration(idle) * time.Millisecond
2024-02-18 10:42:21 +00:00
case "inactive":
2024-02-18 10:42:21 +00:00
var inactive int64
2024-02-18 10:42:21 +00:00
inactive, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
cmd.val[i].Inactive = time.Duration(inactive) * time.Millisecond
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected content %s in XINFO CONSUMERS reply", key)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XInfoGroupsCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val []XInfoGroup
}
type XInfoGroup struct {
Name string
Consumers int64
Pending int64
2024-02-18 10:42:21 +00:00
LastDeliveredID string
EntriesRead int64
Lag int64
2024-02-18 10:42:21 +00:00
}
var _ Cmder = (*XInfoGroupsCmd)(nil)
func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd {
2024-02-18 10:42:21 +00:00
return &XInfoGroupsCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: []interface{}{"xinfo", "groups", stream},
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoGroupsCmd) SetVal(val []XInfoGroup) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoGroupsCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]XInfoGroup, n)
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
group := &cmd.val[i]
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
var key string
2024-02-18 10:42:21 +00:00
for j := 0; j < nn; j++ {
2024-02-18 10:42:21 +00:00
key, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "name":
2024-02-18 10:42:21 +00:00
group.Name, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "consumers":
2024-02-18 10:42:21 +00:00
group.Consumers, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "pending":
2024-02-18 10:42:21 +00:00
group.Pending, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "last-delivered-id":
2024-02-18 10:42:21 +00:00
group.LastDeliveredID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "entries-read":
2024-02-18 10:42:21 +00:00
group.EntriesRead, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "lag":
2024-02-18 10:42:21 +00:00
group.Lag, err = rd.ReadInt()
// lag: the number of entries in the stream that are still waiting to be delivered
2024-02-18 10:42:21 +00:00
// to the group's consumers, or a NULL(Nil) when that number can't be determined.
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected key %q in XINFO GROUPS reply", key)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XInfoStreamCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val *XInfoStream
}
type XInfoStream struct {
Length int64
RadixTreeKeys int64
RadixTreeNodes int64
Groups int64
LastGeneratedID string
MaxDeletedEntryID string
EntriesAdded int64
FirstEntry XMessage
LastEntry XMessage
2024-02-18 10:42:21 +00:00
RecordedFirstEntryID string
}
var _ Cmder = (*XInfoStreamCmd)(nil)
func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd {
2024-02-18 10:42:21 +00:00
return &XInfoStreamCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: []interface{}{"xinfo", "stream", stream},
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamCmd) SetVal(val *XInfoStream) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamCmd) Val() *XInfoStream {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = &XInfoStream{}
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
switch key {
2024-02-18 10:42:21 +00:00
case "length":
2024-02-18 10:42:21 +00:00
cmd.val.Length, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "radix-tree-keys":
2024-02-18 10:42:21 +00:00
cmd.val.RadixTreeKeys, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "radix-tree-nodes":
2024-02-18 10:42:21 +00:00
cmd.val.RadixTreeNodes, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "groups":
2024-02-18 10:42:21 +00:00
cmd.val.Groups, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "last-generated-id":
2024-02-18 10:42:21 +00:00
cmd.val.LastGeneratedID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "max-deleted-entry-id":
2024-02-18 10:42:21 +00:00
cmd.val.MaxDeletedEntryID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "entries-added":
2024-02-18 10:42:21 +00:00
cmd.val.EntriesAdded, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "first-entry":
2024-02-18 10:42:21 +00:00
cmd.val.FirstEntry, err = readXMessage(rd)
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "last-entry":
2024-02-18 10:42:21 +00:00
cmd.val.LastEntry, err = readXMessage(rd)
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "recorded-first-entry-id":
2024-02-18 10:42:21 +00:00
cmd.val.RecordedFirstEntryID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected key %q in XINFO STREAM reply", key)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type XInfoStreamFullCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val *XInfoStreamFull
}
type XInfoStreamFull struct {
Length int64
RadixTreeKeys int64
RadixTreeNodes int64
LastGeneratedID string
MaxDeletedEntryID string
EntriesAdded int64
Entries []XMessage
Groups []XInfoStreamGroup
2024-02-18 10:42:21 +00:00
RecordedFirstEntryID string
}
type XInfoStreamGroup struct {
Name string
2024-02-18 10:42:21 +00:00
LastDeliveredID string
EntriesRead int64
Lag int64
PelCount int64
Pending []XInfoStreamGroupPending
Consumers []XInfoStreamConsumer
2024-02-18 10:42:21 +00:00
}
type XInfoStreamGroupPending struct {
ID string
Consumer string
DeliveryTime time.Time
2024-02-18 10:42:21 +00:00
DeliveryCount int64
}
type XInfoStreamConsumer struct {
Name string
SeenTime time.Time
2024-02-18 10:42:21 +00:00
ActiveTime time.Time
PelCount int64
Pending []XInfoStreamConsumerPending
2024-02-18 10:42:21 +00:00
}
type XInfoStreamConsumerPending struct {
ID string
DeliveryTime time.Time
2024-02-18 10:42:21 +00:00
DeliveryCount int64
}
var _ Cmder = (*XInfoStreamFullCmd)(nil)
func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XInfoStreamFullCmd {
2024-02-18 10:42:21 +00:00
return &XInfoStreamFullCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamFullCmd) SetVal(val *XInfoStreamFull) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamFullCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = &XInfoStreamFull{}
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "length":
2024-02-18 10:42:21 +00:00
cmd.val.Length, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "radix-tree-keys":
2024-02-18 10:42:21 +00:00
cmd.val.RadixTreeKeys, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "radix-tree-nodes":
2024-02-18 10:42:21 +00:00
cmd.val.RadixTreeNodes, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "last-generated-id":
2024-02-18 10:42:21 +00:00
cmd.val.LastGeneratedID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "entries-added":
2024-02-18 10:42:21 +00:00
cmd.val.EntriesAdded, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "entries":
2024-02-18 10:42:21 +00:00
cmd.val.Entries, err = readXMessageSlice(rd)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "groups":
2024-02-18 10:42:21 +00:00
cmd.val.Groups, err = readStreamGroups(rd)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "max-deleted-entry-id":
2024-02-18 10:42:21 +00:00
cmd.val.MaxDeletedEntryID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "recorded-first-entry-id":
2024-02-18 10:42:21 +00:00
cmd.val.RecordedFirstEntryID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
groups := make([]XInfoStreamGroup, 0, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
group := XInfoStreamGroup{}
for j := 0; j < nn; j++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "name":
2024-02-18 10:42:21 +00:00
group.Name, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "last-delivered-id":
2024-02-18 10:42:21 +00:00
group.LastDeliveredID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "entries-read":
2024-02-18 10:42:21 +00:00
group.EntriesRead, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "lag":
2024-02-18 10:42:21 +00:00
// lag: the number of entries in the stream that are still waiting to be delivered
2024-02-18 10:42:21 +00:00
// to the group's consumers, or a NULL(Nil) when that number can't be determined.
2024-02-18 10:42:21 +00:00
group.Lag, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "pel-count":
2024-02-18 10:42:21 +00:00
group.PelCount, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "pending":
2024-02-18 10:42:21 +00:00
group.Pending, err = readXInfoStreamGroupPending(rd)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "consumers":
2024-02-18 10:42:21 +00:00
group.Consumers, err = readXInfoStreamConsumers(rd)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: unexpected key %q in XINFO STREAM FULL reply", key)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
groups = append(groups, group)
2024-02-18 10:42:21 +00:00
}
return groups, nil
2024-02-18 10:42:21 +00:00
}
func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPending, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
pending := make([]XInfoStreamGroupPending, 0, n)
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(4); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
p := XInfoStreamGroupPending{}
p.ID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
p.Consumer, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
delivery, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
p.DeliveryCount, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
pending = append(pending, p)
2024-02-18 10:42:21 +00:00
}
return pending, nil
2024-02-18 10:42:21 +00:00
}
func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
consumers := make([]XInfoStreamConsumer, 0, n)
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
c := XInfoStreamConsumer{}
for f := 0; f < nn; f++ {
2024-02-18 10:42:21 +00:00
cKey, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
switch cKey {
2024-02-18 10:42:21 +00:00
case "name":
2024-02-18 10:42:21 +00:00
c.Name, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "seen-time":
2024-02-18 10:42:21 +00:00
seen, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
c.SeenTime = time.UnixMilli(seen)
2024-02-18 10:42:21 +00:00
case "active-time":
2024-02-18 10:42:21 +00:00
active, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
c.ActiveTime = time.UnixMilli(active)
2024-02-18 10:42:21 +00:00
case "pel-count":
2024-02-18 10:42:21 +00:00
c.PelCount, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "pending":
2024-02-18 10:42:21 +00:00
pendingNumber, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
c.Pending = make([]XInfoStreamConsumerPending, 0, pendingNumber)
for pn := 0; pn < pendingNumber; pn++ {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(3); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
p := XInfoStreamConsumerPending{}
p.ID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
delivery, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
p.DeliveryTime = time.Unix(delivery/1000, delivery%1000*int64(time.Millisecond))
p.DeliveryCount, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
c.Pending = append(c.Pending, p)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: unexpected content %s "+
2024-02-18 10:42:21 +00:00
"in XINFO STREAM FULL reply", cKey)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
consumers = append(consumers, c)
2024-02-18 10:42:21 +00:00
}
return consumers, nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type ZSliceCmd struct {
baseCmd
val []Z
}
var _ Cmder = (*ZSliceCmd)(nil)
func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
2024-02-18 10:42:21 +00:00
return &ZSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceCmd) SetVal(val []Z) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceCmd) Val() []Z {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceCmd) Result() ([]Z, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// If the n is 0, can't continue reading.
2024-02-18 10:42:21 +00:00
if n == 0 {
2024-02-18 10:42:21 +00:00
cmd.val = make([]Z, 0)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
typ, err := rd.PeekReplyType()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
array := typ == proto.RespArray
if array {
2024-02-18 10:42:21 +00:00
cmd.val = make([]Z, n)
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
cmd.val = make([]Z, n/2)
2024-02-18 10:42:21 +00:00
}
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
if array {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Member, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Score, err = rd.ReadFloat(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type ZWithKeyCmd struct {
baseCmd
val *ZWithKey
}
var _ Cmder = (*ZWithKeyCmd)(nil)
func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd {
2024-02-18 10:42:21 +00:00
return &ZWithKeyCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ZWithKeyCmd) SetVal(val *ZWithKey) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ZWithKeyCmd) Val() *ZWithKey {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ZWithKeyCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(3); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = &ZWithKey{}
if cmd.val.Key, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.val.Member, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.val.Score, err = rd.ReadFloat(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type ScanCmd struct {
baseCmd
page []string
2024-02-18 10:42:21 +00:00
cursor uint64
process cmdable
}
var _ Cmder = (*ScanCmd)(nil)
func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd {
2024-02-18 10:42:21 +00:00
return &ScanCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
2024-02-18 10:42:21 +00:00
process: process,
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ScanCmd) SetVal(page []string, cursor uint64) {
2024-02-18 10:42:21 +00:00
cmd.page = page
2024-02-18 10:42:21 +00:00
cmd.cursor = cursor
2024-02-18 10:42:21 +00:00
}
func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
2024-02-18 10:42:21 +00:00
return cmd.page, cmd.cursor
2024-02-18 10:42:21 +00:00
}
func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
2024-02-18 10:42:21 +00:00
return cmd.page, cmd.cursor, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ScanCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.page)
2024-02-18 10:42:21 +00:00
}
func (cmd *ScanCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
if err := rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cursor, err := rd.ReadUint()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.cursor = cursor
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.page = make([]string, n)
for i := 0; i < len(cmd.page); i++ {
2024-02-18 10:42:21 +00:00
if cmd.page[i], err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
// Iterator creates a new ScanIterator.
2024-02-18 10:42:21 +00:00
func (cmd *ScanCmd) Iterator() *ScanIterator {
2024-02-18 10:42:21 +00:00
return &ScanIterator{
2024-02-18 10:42:21 +00:00
cmd: cmd,
}
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type ClusterNode struct {
ID string
Addr string
2024-02-18 10:42:21 +00:00
NetworkingMetadata map[string]string
}
type ClusterSlot struct {
Start int
End int
2024-02-18 10:42:21 +00:00
Nodes []ClusterNode
}
type ClusterSlotsCmd struct {
baseCmd
val []ClusterSlot
}
var _ Cmder = (*ClusterSlotsCmd)(nil)
func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd {
2024-02-18 10:42:21 +00:00
return &ClusterSlotsCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterSlotsCmd) SetVal(val []ClusterSlot) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterSlotsCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]ClusterSlot, n)
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
n, err = rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if n < 2 {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
2024-02-18 10:42:21 +00:00
}
start, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
end, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// subtract start and end.
2024-02-18 10:42:21 +00:00
nodes := make([]ClusterNode, n-2)
for j := 0; j < len(nodes); j++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if nn < 2 || nn > 4 {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("got %d elements in cluster info address, expected 2, 3, or 4", n)
2024-02-18 10:42:21 +00:00
}
ip, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
port, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
nodes[j].Addr = net.JoinHostPort(ip, port)
if nn >= 3 {
2024-02-18 10:42:21 +00:00
id, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
nodes[j].ID = id
2024-02-18 10:42:21 +00:00
}
if nn >= 4 {
2024-02-18 10:42:21 +00:00
metadataLength, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
networkingMetadata := make(map[string]string, metadataLength)
for i := 0; i < metadataLength; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
value, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
networkingMetadata[key] = value
2024-02-18 10:42:21 +00:00
}
nodes[j].NetworkingMetadata = networkingMetadata
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
cmd.val[i] = ClusterSlot{
2024-02-18 10:42:21 +00:00
Start: int(start),
End: int(end),
2024-02-18 10:42:21 +00:00
Nodes: nodes,
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
// GeoLocation is used with GeoAdd to add geospatial location.
2024-02-18 10:42:21 +00:00
type GeoLocation struct {
Name string
2024-02-18 10:42:21 +00:00
Longitude, Latitude, Dist float64
GeoHash int64
2024-02-18 10:42:21 +00:00
}
// GeoRadiusQuery is used with GeoRadius to query geospatial index.
2024-02-18 10:42:21 +00:00
type GeoRadiusQuery struct {
Radius float64
2024-02-18 10:42:21 +00:00
// Can be m, km, ft, or mi. Default is km.
Unit string
WithCoord bool
WithDist bool
2024-02-18 10:42:21 +00:00
WithGeoHash bool
Count int
2024-02-18 10:42:21 +00:00
// Can be ASC or DESC. Default is no sort order.
Sort string
Store string
2024-02-18 10:42:21 +00:00
StoreDist string
// WithCoord+WithDist+WithGeoHash
2024-02-18 10:42:21 +00:00
withLen int
}
type GeoLocationCmd struct {
baseCmd
q *GeoRadiusQuery
2024-02-18 10:42:21 +00:00
locations []GeoLocation
}
var _ Cmder = (*GeoLocationCmd)(nil)
func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
2024-02-18 10:42:21 +00:00
return &GeoLocationCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: geoLocationArgs(q, args...),
},
2024-02-18 10:42:21 +00:00
q: q,
}
2024-02-18 10:42:21 +00:00
}
func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} {
2024-02-18 10:42:21 +00:00
args = append(args, q.Radius)
2024-02-18 10:42:21 +00:00
if q.Unit != "" {
2024-02-18 10:42:21 +00:00
args = append(args, q.Unit)
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
args = append(args, "km")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.WithCoord {
2024-02-18 10:42:21 +00:00
args = append(args, "withcoord")
2024-02-18 10:42:21 +00:00
q.withLen++
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.WithDist {
2024-02-18 10:42:21 +00:00
args = append(args, "withdist")
2024-02-18 10:42:21 +00:00
q.withLen++
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.WithGeoHash {
2024-02-18 10:42:21 +00:00
args = append(args, "withhash")
2024-02-18 10:42:21 +00:00
q.withLen++
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.Count > 0 {
2024-02-18 10:42:21 +00:00
args = append(args, "count", q.Count)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.Sort != "" {
2024-02-18 10:42:21 +00:00
args = append(args, q.Sort)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.Store != "" {
2024-02-18 10:42:21 +00:00
args = append(args, "store")
2024-02-18 10:42:21 +00:00
args = append(args, q.Store)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.StoreDist != "" {
2024-02-18 10:42:21 +00:00
args = append(args, "storedist")
2024-02-18 10:42:21 +00:00
args = append(args, q.StoreDist)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return args
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoLocationCmd) SetVal(locations []GeoLocation) {
2024-02-18 10:42:21 +00:00
cmd.locations = locations
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoLocationCmd) Val() []GeoLocation {
2024-02-18 10:42:21 +00:00
return cmd.locations
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
2024-02-18 10:42:21 +00:00
return cmd.locations, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoLocationCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.locations)
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.locations = make([]GeoLocation, n)
for i := 0; i < len(cmd.locations); i++ {
2024-02-18 10:42:21 +00:00
// only name
2024-02-18 10:42:21 +00:00
if cmd.q.withLen == 0 {
2024-02-18 10:42:21 +00:00
if cmd.locations[i].Name, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
continue
2024-02-18 10:42:21 +00:00
}
// +name
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(cmd.q.withLen + 1); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.locations[i].Name, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.q.WithDist {
2024-02-18 10:42:21 +00:00
if cmd.locations[i].Dist, err = rd.ReadFloat(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.q.WithGeoHash {
2024-02-18 10:42:21 +00:00
if cmd.locations[i].GeoHash, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.q.WithCoord {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.locations[i].Longitude, err = rd.ReadFloat(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.locations[i].Latitude, err = rd.ReadFloat(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
// GeoSearchQuery is used for GEOSearch/GEOSearchStore command query.
2024-02-18 10:42:21 +00:00
type GeoSearchQuery struct {
Member string
// Latitude and Longitude when using FromLonLat option.
2024-02-18 10:42:21 +00:00
Longitude float64
Latitude float64
2024-02-18 10:42:21 +00:00
// Distance and unit when using ByRadius option.
2024-02-18 10:42:21 +00:00
// Can use m, km, ft, or mi. Default is km.
Radius float64
2024-02-18 10:42:21 +00:00
RadiusUnit string
// Height, width and unit when using ByBox option.
2024-02-18 10:42:21 +00:00
// Can be m, km, ft, or mi. Default is km.
BoxWidth float64
2024-02-18 10:42:21 +00:00
BoxHeight float64
BoxUnit string
2024-02-18 10:42:21 +00:00
// Can be ASC or DESC. Default is no sort order.
Sort string
Count int
2024-02-18 10:42:21 +00:00
CountAny bool
}
type GeoSearchLocationQuery struct {
GeoSearchQuery
WithCoord bool
WithDist bool
WithHash bool
2024-02-18 10:42:21 +00:00
}
type GeoSearchStoreQuery struct {
GeoSearchQuery
// When using the StoreDist option, the command stores the items in a
2024-02-18 10:42:21 +00:00
// sorted set populated with their distance from the center of the circle or box,
2024-02-18 10:42:21 +00:00
// as a floating-point number, in the same unit specified for that shape.
2024-02-18 10:42:21 +00:00
StoreDist bool
}
func geoSearchLocationArgs(q *GeoSearchLocationQuery, args []interface{}) []interface{} {
2024-02-18 10:42:21 +00:00
args = geoSearchArgs(&q.GeoSearchQuery, args)
if q.WithCoord {
2024-02-18 10:42:21 +00:00
args = append(args, "withcoord")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.WithDist {
2024-02-18 10:42:21 +00:00
args = append(args, "withdist")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.WithHash {
2024-02-18 10:42:21 +00:00
args = append(args, "withhash")
2024-02-18 10:42:21 +00:00
}
return args
2024-02-18 10:42:21 +00:00
}
func geoSearchArgs(q *GeoSearchQuery, args []interface{}) []interface{} {
2024-02-18 10:42:21 +00:00
if q.Member != "" {
2024-02-18 10:42:21 +00:00
args = append(args, "frommember", q.Member)
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
args = append(args, "fromlonlat", q.Longitude, q.Latitude)
2024-02-18 10:42:21 +00:00
}
if q.Radius > 0 {
2024-02-18 10:42:21 +00:00
if q.RadiusUnit == "" {
2024-02-18 10:42:21 +00:00
q.RadiusUnit = "km"
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
args = append(args, "byradius", q.Radius, q.RadiusUnit)
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
if q.BoxUnit == "" {
2024-02-18 10:42:21 +00:00
q.BoxUnit = "km"
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
args = append(args, "bybox", q.BoxWidth, q.BoxHeight, q.BoxUnit)
2024-02-18 10:42:21 +00:00
}
if q.Sort != "" {
2024-02-18 10:42:21 +00:00
args = append(args, q.Sort)
2024-02-18 10:42:21 +00:00
}
if q.Count > 0 {
2024-02-18 10:42:21 +00:00
args = append(args, "count", q.Count)
2024-02-18 10:42:21 +00:00
if q.CountAny {
2024-02-18 10:42:21 +00:00
args = append(args, "any")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return args
2024-02-18 10:42:21 +00:00
}
type GeoSearchLocationCmd struct {
baseCmd
opt *GeoSearchLocationQuery
2024-02-18 10:42:21 +00:00
val []GeoLocation
}
var _ Cmder = (*GeoSearchLocationCmd)(nil)
func NewGeoSearchLocationCmd(
2024-02-18 10:42:21 +00:00
ctx context.Context, opt *GeoSearchLocationQuery, args ...interface{},
2024-02-18 10:42:21 +00:00
) *GeoSearchLocationCmd {
2024-02-18 10:42:21 +00:00
return &GeoSearchLocationCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
2024-02-18 10:42:21 +00:00
opt: opt,
}
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoSearchLocationCmd) SetVal(val []GeoLocation) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoSearchLocationCmd) Val() []GeoLocation {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoSearchLocationCmd) Result() ([]GeoLocation, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoSearchLocationCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoSearchLocationCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make([]GeoLocation, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
_, err = rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
var loc GeoLocation
loc.Name, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.opt.WithDist {
2024-02-18 10:42:21 +00:00
loc.Dist, err = rd.ReadFloat()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.opt.WithHash {
2024-02-18 10:42:21 +00:00
loc.GeoHash, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmd.opt.WithCoord {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
loc.Longitude, err = rd.ReadFloat()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
loc.Latitude, err = rd.ReadFloat()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
cmd.val[i] = loc
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type GeoPos struct {
Longitude, Latitude float64
}
type GeoPosCmd struct {
baseCmd
val []*GeoPos
}
var _ Cmder = (*GeoPosCmd)(nil)
func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
2024-02-18 10:42:21 +00:00
return &GeoPosCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoPosCmd) SetVal(val []*GeoPos) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoPosCmd) Val() []*GeoPos {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoPosCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]*GeoPos, n)
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
err = rd.ReadFixedArrayLen(2)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
if err == Nil {
2024-02-18 10:42:21 +00:00
cmd.val[i] = nil
2024-02-18 10:42:21 +00:00
continue
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
longitude, err := rd.ReadFloat()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
latitude, err := rd.ReadFloat()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val[i] = &GeoPos{
2024-02-18 10:42:21 +00:00
Longitude: longitude,
Latitude: latitude,
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type CommandInfo struct {
Name string
Arity int8
Flags []string
ACLFlags []string
2024-02-18 10:42:21 +00:00
FirstKeyPos int8
LastKeyPos int8
StepCount int8
ReadOnly bool
2024-02-18 10:42:21 +00:00
}
type CommandsInfoCmd struct {
baseCmd
val map[string]*CommandInfo
}
var _ Cmder = (*CommandsInfoCmd)(nil)
func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd {
2024-02-18 10:42:21 +00:00
return &CommandsInfoCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *CommandsInfoCmd) SetVal(val map[string]*CommandInfo) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *CommandsInfoCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
const numArgRedis5 = 6
2024-02-18 10:42:21 +00:00
const numArgRedis6 = 7
2024-02-18 10:42:21 +00:00
const numArgRedis7 = 10
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make(map[string]*CommandInfo, n)
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch nn {
2024-02-18 10:42:21 +00:00
case numArgRedis5, numArgRedis6, numArgRedis7:
2024-02-18 10:42:21 +00:00
// ok
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 6/7/10", nn)
2024-02-18 10:42:21 +00:00
}
cmdInfo := &CommandInfo{}
2024-02-18 10:42:21 +00:00
if cmdInfo.Name, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
arity, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmdInfo.Arity = int8(arity)
flagLen, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmdInfo.Flags = make([]string, flagLen)
2024-02-18 10:42:21 +00:00
for f := 0; f < len(cmdInfo.Flags); f++ {
2024-02-18 10:42:21 +00:00
switch s, err := rd.ReadString(); {
2024-02-18 10:42:21 +00:00
case err == Nil:
2024-02-18 10:42:21 +00:00
cmdInfo.Flags[f] = ""
2024-02-18 10:42:21 +00:00
case err != nil:
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
if !cmdInfo.ReadOnly && s == "readonly" {
2024-02-18 10:42:21 +00:00
cmdInfo.ReadOnly = true
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmdInfo.Flags[f] = s
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
firstKeyPos, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmdInfo.FirstKeyPos = int8(firstKeyPos)
lastKeyPos, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmdInfo.LastKeyPos = int8(lastKeyPos)
stepCount, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmdInfo.StepCount = int8(stepCount)
if nn >= numArgRedis6 {
2024-02-18 10:42:21 +00:00
aclFlagLen, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmdInfo.ACLFlags = make([]string, aclFlagLen)
2024-02-18 10:42:21 +00:00
for f := 0; f < len(cmdInfo.ACLFlags); f++ {
2024-02-18 10:42:21 +00:00
switch s, err := rd.ReadString(); {
2024-02-18 10:42:21 +00:00
case err == Nil:
2024-02-18 10:42:21 +00:00
cmdInfo.ACLFlags[f] = ""
2024-02-18 10:42:21 +00:00
case err != nil:
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
cmdInfo.ACLFlags[f] = s
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if nn >= numArgRedis7 {
2024-02-18 10:42:21 +00:00
if err := rd.DiscardNext(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if err := rd.DiscardNext(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if err := rd.DiscardNext(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
cmd.val[cmdInfo.Name] = cmdInfo
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type cmdsInfoCache struct {
fn func(ctx context.Context) (map[string]*CommandInfo, error)
once internal.Once
2024-02-18 10:42:21 +00:00
cmds map[string]*CommandInfo
}
func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache {
2024-02-18 10:42:21 +00:00
return &cmdsInfoCache{
2024-02-18 10:42:21 +00:00
fn: fn,
}
2024-02-18 10:42:21 +00:00
}
func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) {
2024-02-18 10:42:21 +00:00
err := c.once.Do(func() error {
2024-02-18 10:42:21 +00:00
cmds, err := c.fn(ctx)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// Extensions have cmd names in upper case. Convert them to lower case.
2024-02-18 10:42:21 +00:00
for k, v := range cmds {
2024-02-18 10:42:21 +00:00
lower := internal.ToLower(k)
2024-02-18 10:42:21 +00:00
if lower != k {
2024-02-18 10:42:21 +00:00
cmds[lower] = v
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
c.cmds = cmds
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
})
2024-02-18 10:42:21 +00:00
return c.cmds, err
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type SlowLog struct {
ID int64
Time time.Time
2024-02-18 10:42:21 +00:00
Duration time.Duration
Args []string
2024-02-18 10:42:21 +00:00
// These are also optional fields emitted only by Redis 4.0 or greater:
2024-02-18 10:42:21 +00:00
// https://redis.io/commands/slowlog#output-format
2024-02-18 10:42:21 +00:00
ClientAddr string
2024-02-18 10:42:21 +00:00
ClientName string
}
type SlowLogCmd struct {
baseCmd
val []SlowLog
}
var _ Cmder = (*SlowLogCmd)(nil)
func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
2024-02-18 10:42:21 +00:00
return &SlowLogCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *SlowLogCmd) SetVal(val []SlowLog) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *SlowLogCmd) Val() []SlowLog {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *SlowLogCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]SlowLog, n)
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if nn < 4 {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", nn)
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].ID, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
createdAt, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i].Time = time.Unix(createdAt, 0)
costs, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i].Duration = time.Duration(costs) * time.Microsecond
cmdLen, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cmdLen < 1 {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
2024-02-18 10:42:21 +00:00
}
cmd.val[i].Args = make([]string, cmdLen)
2024-02-18 10:42:21 +00:00
for f := 0; f < len(cmd.val[i].Args); f++ {
2024-02-18 10:42:21 +00:00
cmd.val[i].Args[f], err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if nn >= 5 {
2024-02-18 10:42:21 +00:00
if cmd.val[i].ClientAddr, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if nn >= 6 {
2024-02-18 10:42:21 +00:00
if cmd.val[i].ClientName, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//-----------------------------------------------------------------------
type MapStringInterfaceCmd struct {
baseCmd
val map[string]interface{}
}
var _ Cmder = (*MapStringInterfaceCmd)(nil)
func NewMapStringInterfaceCmd(ctx context.Context, args ...interface{}) *MapStringInterfaceCmd {
2024-02-18 10:42:21 +00:00
return &MapStringInterfaceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceCmd) SetVal(val map[string]interface{}) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceCmd) Val() map[string]interface{} {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceCmd) Result() (map[string]interface{}, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make(map[string]interface{}, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
k, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
v, err := rd.ReadReply()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
if err == Nil {
2024-02-18 10:42:21 +00:00
cmd.val[k] = Nil
2024-02-18 10:42:21 +00:00
continue
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if err, ok := err.(proto.RedisError); ok {
2024-02-18 10:42:21 +00:00
cmd.val[k] = err
2024-02-18 10:42:21 +00:00
continue
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[k] = v
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//-----------------------------------------------------------------------
type MapStringStringSliceCmd struct {
baseCmd
val []map[string]string
}
var _ Cmder = (*MapStringStringSliceCmd)(nil)
func NewMapStringStringSliceCmd(ctx context.Context, args ...interface{}) *MapStringStringSliceCmd {
2024-02-18 10:42:21 +00:00
return &MapStringStringSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringSliceCmd) SetVal(val []map[string]string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringSliceCmd) Val() []map[string]string {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringSliceCmd) Result() ([]map[string]string, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringStringSliceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make([]map[string]string, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i] = make(map[string]string, nn)
2024-02-18 10:42:21 +00:00
for f := 0; f < nn; f++ {
2024-02-18 10:42:21 +00:00
k, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
v, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i][k] = v
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//-----------------------------------------------------------------------
type MapStringInterfaceSliceCmd struct {
baseCmd
val []map[string]interface{}
}
var _ Cmder = (*MapStringInterfaceSliceCmd)(nil)
func NewMapStringInterfaceSliceCmd(ctx context.Context, args ...interface{}) *MapStringInterfaceSliceCmd {
2024-02-18 10:42:21 +00:00
return &MapStringInterfaceSliceCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceSliceCmd) SetVal(val []map[string]interface{}) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceSliceCmd) Val() []map[string]interface{} {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceSliceCmd) Result() ([]map[string]interface{}, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceSliceCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *MapStringInterfaceSliceCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make([]map[string]interface{}, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i] = make(map[string]interface{}, nn)
2024-02-18 10:42:21 +00:00
for f := 0; f < nn; f++ {
2024-02-18 10:42:21 +00:00
k, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
v, err := rd.ReadReply()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
if err != Nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i][k] = v
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type KeyValuesCmd struct {
baseCmd
key string
2024-02-18 10:42:21 +00:00
val []string
}
var _ Cmder = (*KeyValuesCmd)(nil)
func NewKeyValuesCmd(ctx context.Context, args ...interface{}) *KeyValuesCmd {
2024-02-18 10:42:21 +00:00
return &KeyValuesCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValuesCmd) SetVal(key string, val []string) {
2024-02-18 10:42:21 +00:00
cmd.key = key
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValuesCmd) Val() (string, []string) {
2024-02-18 10:42:21 +00:00
return cmd.key, cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValuesCmd) Result() (string, []string, error) {
2024-02-18 10:42:21 +00:00
return cmd.key, cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValuesCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyValuesCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.key, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]string, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
cmd.val[i], err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type ZSliceWithKeyCmd struct {
baseCmd
key string
2024-02-18 10:42:21 +00:00
val []Z
}
var _ Cmder = (*ZSliceWithKeyCmd)(nil)
func NewZSliceWithKeyCmd(ctx context.Context, args ...interface{}) *ZSliceWithKeyCmd {
2024-02-18 10:42:21 +00:00
return &ZSliceWithKeyCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceWithKeyCmd) SetVal(key string, val []Z) {
2024-02-18 10:42:21 +00:00
cmd.key = key
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceWithKeyCmd) Val() (string, []Z) {
2024-02-18 10:42:21 +00:00
return cmd.key, cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceWithKeyCmd) Result() (string, []Z, error) {
2024-02-18 10:42:21 +00:00
return cmd.key, cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceWithKeyCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ZSliceWithKeyCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.key, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
typ, err := rd.PeekReplyType()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
array := typ == proto.RespArray
if array {
2024-02-18 10:42:21 +00:00
cmd.val = make([]Z, n)
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
cmd.val = make([]Z, n/2)
2024-02-18 10:42:21 +00:00
}
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
if array {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Member, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Score, err = rd.ReadFloat(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
type Function struct {
Name string
2024-02-18 10:42:21 +00:00
Description string
Flags []string
2024-02-18 10:42:21 +00:00
}
type Library struct {
Name string
Engine string
2024-02-18 10:42:21 +00:00
Functions []Function
Code string
2024-02-18 10:42:21 +00:00
}
type FunctionListCmd struct {
baseCmd
val []Library
}
var _ Cmder = (*FunctionListCmd)(nil)
func NewFunctionListCmd(ctx context.Context, args ...interface{}) *FunctionListCmd {
2024-02-18 10:42:21 +00:00
return &FunctionListCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionListCmd) SetVal(val []Library) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionListCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionListCmd) Val() []Library {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionListCmd) Result() ([]Library, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionListCmd) First() (*Library, error) {
2024-02-18 10:42:21 +00:00
if cmd.err != nil {
2024-02-18 10:42:21 +00:00
return nil, cmd.err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if len(cmd.val) > 0 {
2024-02-18 10:42:21 +00:00
return &cmd.val[0], nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil, Nil
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionListCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
libraries := make([]Library, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
library := Library{}
2024-02-18 10:42:21 +00:00
for f := 0; f < nn; f++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "library_name":
2024-02-18 10:42:21 +00:00
library.Name, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "engine":
2024-02-18 10:42:21 +00:00
library.Engine, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "functions":
2024-02-18 10:42:21 +00:00
library.Functions, err = cmd.readFunctions(rd)
2024-02-18 10:42:21 +00:00
case "library_code":
2024-02-18 10:42:21 +00:00
library.Code, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: function list unexpected key %s", key)
2024-02-18 10:42:21 +00:00
}
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
libraries[i] = library
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = libraries
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionListCmd) readFunctions(rd *proto.Reader) ([]Function, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
functions := make([]Function, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
nn, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
function := Function{}
2024-02-18 10:42:21 +00:00
for f := 0; f < nn; f++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "name":
2024-02-18 10:42:21 +00:00
if function.Name, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "description":
2024-02-18 10:42:21 +00:00
if function.Description, err = rd.ReadString(); err != nil && err != Nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "flags":
2024-02-18 10:42:21 +00:00
// resp set
2024-02-18 10:42:21 +00:00
nx, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
function.Flags = make([]string, nx)
2024-02-18 10:42:21 +00:00
for j := 0; j < nx; j++ {
2024-02-18 10:42:21 +00:00
if function.Flags[j], err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: function list unexpected key %s", key)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
functions[i] = function
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return functions, nil
2024-02-18 10:42:21 +00:00
}
// FunctionStats contains information about the scripts currently executing on the server, and the available engines
2024-02-18 10:42:21 +00:00
// - Engines:
2024-02-18 10:42:21 +00:00
// Statistics about the engine like number of functions and number of libraries
2024-02-18 10:42:21 +00:00
// - RunningScript:
2024-02-18 10:42:21 +00:00
// The script currently running on the shard we're connecting to.
2024-02-18 10:42:21 +00:00
// For Redis Enterprise and Redis Cloud, this represents the
2024-02-18 10:42:21 +00:00
// function with the longest running time, across all the running functions, on all shards
2024-02-18 10:42:21 +00:00
// - RunningScripts
2024-02-18 10:42:21 +00:00
// All scripts currently running in a Redis Enterprise clustered database.
2024-02-18 10:42:21 +00:00
// Only available on Redis Enterprise
2024-02-18 10:42:21 +00:00
type FunctionStats struct {
Engines []Engine
2024-02-18 10:42:21 +00:00
isRunning bool
rs RunningScript
allrs []RunningScript
2024-02-18 10:42:21 +00:00
}
func (fs *FunctionStats) Running() bool {
2024-02-18 10:42:21 +00:00
return fs.isRunning
2024-02-18 10:42:21 +00:00
}
func (fs *FunctionStats) RunningScript() (RunningScript, bool) {
2024-02-18 10:42:21 +00:00
return fs.rs, fs.isRunning
2024-02-18 10:42:21 +00:00
}
// AllRunningScripts returns all scripts currently running in a Redis Enterprise clustered database.
2024-02-18 10:42:21 +00:00
// Only available on Redis Enterprise
2024-02-18 10:42:21 +00:00
func (fs *FunctionStats) AllRunningScripts() []RunningScript {
2024-02-18 10:42:21 +00:00
return fs.allrs
2024-02-18 10:42:21 +00:00
}
type RunningScript struct {
Name string
Command []string
2024-02-18 10:42:21 +00:00
Duration time.Duration
}
type Engine struct {
Language string
2024-02-18 10:42:21 +00:00
LibrariesCount int64
2024-02-18 10:42:21 +00:00
FunctionsCount int64
}
type FunctionStatsCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val FunctionStats
}
var _ Cmder = (*FunctionStatsCmd)(nil)
func NewFunctionStatsCmd(ctx context.Context, args ...interface{}) *FunctionStatsCmd {
2024-02-18 10:42:21 +00:00
return &FunctionStatsCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) SetVal(val FunctionStats) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) Val() FunctionStats {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) Result() (FunctionStats, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
var key string
2024-02-18 10:42:21 +00:00
var result FunctionStats
2024-02-18 10:42:21 +00:00
for f := 0; f < n; f++ {
2024-02-18 10:42:21 +00:00
key, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "running_script":
2024-02-18 10:42:21 +00:00
result.rs, result.isRunning, err = cmd.readRunningScript(rd)
2024-02-18 10:42:21 +00:00
case "engines":
2024-02-18 10:42:21 +00:00
result.Engines, err = cmd.readEngines(rd)
2024-02-18 10:42:21 +00:00
case "all_running_scripts": // Redis Enterprise only
2024-02-18 10:42:21 +00:00
result.allrs, result.isRunning, err = cmd.readRunningScripts(rd)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: function stats unexpected key %s", key)
2024-02-18 10:42:21 +00:00
}
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
cmd.val = result
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) readRunningScript(rd *proto.Reader) (RunningScript, bool, error) {
2024-02-18 10:42:21 +00:00
err := rd.ReadFixedMapLen(3)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
if err == Nil {
2024-02-18 10:42:21 +00:00
return RunningScript{}, false, nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return RunningScript{}, false, err
2024-02-18 10:42:21 +00:00
}
var runningScript RunningScript
2024-02-18 10:42:21 +00:00
for i := 0; i < 3; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return RunningScript{}, false, err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "name":
2024-02-18 10:42:21 +00:00
runningScript.Name, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "duration_ms":
2024-02-18 10:42:21 +00:00
runningScript.Duration, err = cmd.readDuration(rd)
2024-02-18 10:42:21 +00:00
case "command":
2024-02-18 10:42:21 +00:00
runningScript.Command, err = cmd.readCommand(rd)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return RunningScript{}, false, fmt.Errorf("redis: function stats unexpected running_script key %s", key)
2024-02-18 10:42:21 +00:00
}
if err != nil {
2024-02-18 10:42:21 +00:00
return RunningScript{}, false, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return runningScript, true, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) readEngines(rd *proto.Reader) ([]Engine, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
engines := make([]Engine, 0, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
engine := Engine{}
2024-02-18 10:42:21 +00:00
engine.Language, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
err = rd.ReadFixedMapLen(2)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: function stats unexpected %s engine map length", engine.Language)
2024-02-18 10:42:21 +00:00
}
for i := 0; i < 2; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
switch key {
2024-02-18 10:42:21 +00:00
case "libraries_count":
2024-02-18 10:42:21 +00:00
engine.LibrariesCount, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "functions_count":
2024-02-18 10:42:21 +00:00
engine.FunctionsCount, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
engines = append(engines, engine)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return engines, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) readDuration(rd *proto.Reader) (time.Duration, error) {
2024-02-18 10:42:21 +00:00
t, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return time.Duration(0), err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return time.Duration(t) * time.Millisecond, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) readCommand(rd *proto.Reader) ([]string, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
command := make([]string, 0, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
x, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
command = append(command, x)
2024-02-18 10:42:21 +00:00
}
return command, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *FunctionStatsCmd) readRunningScripts(rd *proto.Reader) ([]RunningScript, bool, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, false, err
2024-02-18 10:42:21 +00:00
}
runningScripts := make([]RunningScript, 0, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
rs, _, err := cmd.readRunningScript(rd)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, false, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
runningScripts = append(runningScripts, rs)
2024-02-18 10:42:21 +00:00
}
return runningScripts, len(runningScripts) > 0, nil
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
// LCSQuery is a parameter used for the LCS command
2024-02-18 10:42:21 +00:00
type LCSQuery struct {
Key1 string
Key2 string
Len bool
Idx bool
MinMatchLen int
2024-02-18 10:42:21 +00:00
WithMatchLen bool
}
// LCSMatch is the result set of the LCS command.
2024-02-18 10:42:21 +00:00
type LCSMatch struct {
MatchString string
Matches []LCSMatchedPosition
Len int64
2024-02-18 10:42:21 +00:00
}
type LCSMatchedPosition struct {
Key1 LCSPosition
2024-02-18 10:42:21 +00:00
Key2 LCSPosition
// only for withMatchLen is true
2024-02-18 10:42:21 +00:00
MatchLen int64
}
type LCSPosition struct {
Start int64
End int64
2024-02-18 10:42:21 +00:00
}
type LCSCmd struct {
baseCmd
// 1: match string
2024-02-18 10:42:21 +00:00
// 2: match len
2024-02-18 10:42:21 +00:00
// 3: match idx LCSMatch
2024-02-18 10:42:21 +00:00
readType uint8
val *LCSMatch
2024-02-18 10:42:21 +00:00
}
func NewLCSCmd(ctx context.Context, q *LCSQuery) *LCSCmd {
2024-02-18 10:42:21 +00:00
args := make([]interface{}, 3, 7)
2024-02-18 10:42:21 +00:00
args[0] = "lcs"
2024-02-18 10:42:21 +00:00
args[1] = q.Key1
2024-02-18 10:42:21 +00:00
args[2] = q.Key2
cmd := &LCSCmd{readType: 1}
2024-02-18 10:42:21 +00:00
if q.Len {
2024-02-18 10:42:21 +00:00
cmd.readType = 2
2024-02-18 10:42:21 +00:00
args = append(args, "len")
2024-02-18 10:42:21 +00:00
} else if q.Idx {
2024-02-18 10:42:21 +00:00
cmd.readType = 3
2024-02-18 10:42:21 +00:00
args = append(args, "idx")
2024-02-18 10:42:21 +00:00
if q.MinMatchLen != 0 {
2024-02-18 10:42:21 +00:00
args = append(args, "minmatchlen", q.MinMatchLen)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if q.WithMatchLen {
2024-02-18 10:42:21 +00:00
args = append(args, "withmatchlen")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.baseCmd = baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
}
return cmd
2024-02-18 10:42:21 +00:00
}
func (cmd *LCSCmd) SetVal(val *LCSMatch) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *LCSCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *LCSCmd) Val() *LCSMatch {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *LCSCmd) Result() (*LCSMatch, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *LCSCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
lcs := &LCSMatch{}
2024-02-18 10:42:21 +00:00
switch cmd.readType {
2024-02-18 10:42:21 +00:00
case 1:
2024-02-18 10:42:21 +00:00
// match string
2024-02-18 10:42:21 +00:00
if lcs.MatchString, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case 2:
2024-02-18 10:42:21 +00:00
// match len
2024-02-18 10:42:21 +00:00
if lcs.Len, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case 3:
2024-02-18 10:42:21 +00:00
// read LCSMatch
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedMapLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// read matches or len field
2024-02-18 10:42:21 +00:00
for i := 0; i < 2; i++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "matches":
2024-02-18 10:42:21 +00:00
// read array of matched positions
2024-02-18 10:42:21 +00:00
if lcs.Matches, err = cmd.readMatchedPositions(rd); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "len":
2024-02-18 10:42:21 +00:00
// read match length
2024-02-18 10:42:21 +00:00
if lcs.Len, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
cmd.val = lcs
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func (cmd *LCSCmd) readMatchedPositions(rd *proto.Reader) ([]LCSMatchedPosition, error) {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
positions := make([]LCSMatchedPosition, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
pn, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
if positions[i].Key1, err = cmd.readPosition(rd); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if positions[i].Key2, err = cmd.readPosition(rd); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
// read match length if WithMatchLen is true
2024-02-18 10:42:21 +00:00
if pn > 2 {
2024-02-18 10:42:21 +00:00
if positions[i].MatchLen, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return positions, nil
2024-02-18 10:42:21 +00:00
}
func (cmd *LCSCmd) readPosition(rd *proto.Reader) (pos LCSPosition, err error) {
2024-02-18 10:42:21 +00:00
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return pos, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if pos.Start, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return pos, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if pos.End, err = rd.ReadInt(); err != nil {
2024-02-18 10:42:21 +00:00
return pos, err
2024-02-18 10:42:21 +00:00
}
return pos, nil
2024-02-18 10:42:21 +00:00
}
// ------------------------------------------------------------------------
type KeyFlags struct {
Key string
2024-02-18 10:42:21 +00:00
Flags []string
}
type KeyFlagsCmd struct {
baseCmd
val []KeyFlags
}
var _ Cmder = (*KeyFlagsCmd)(nil)
func NewKeyFlagsCmd(ctx context.Context, args ...interface{}) *KeyFlagsCmd {
2024-02-18 10:42:21 +00:00
return &KeyFlagsCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyFlagsCmd) SetVal(val []KeyFlags) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyFlagsCmd) Val() []KeyFlags {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyFlagsCmd) Result() ([]KeyFlags, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyFlagsCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *KeyFlagsCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if n == 0 {
2024-02-18 10:42:21 +00:00
cmd.val = make([]KeyFlags, 0)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
cmd.val = make([]KeyFlags, n)
for i := 0; i < len(cmd.val); i++ {
if err = rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
if cmd.val[i].Key, err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
flagsLen, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i].Flags = make([]string, flagsLen)
for j := 0; j < flagsLen; j++ {
2024-02-18 10:42:21 +00:00
if cmd.val[i].Flags[j], err = rd.ReadString(); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
// ---------------------------------------------------------------------------------------------------
type ClusterLink struct {
Direction string
Node string
CreateTime int64
Events string
2024-02-18 10:42:21 +00:00
SendBufferAllocated int64
SendBufferUsed int64
2024-02-18 10:42:21 +00:00
}
type ClusterLinksCmd struct {
baseCmd
val []ClusterLink
}
var _ Cmder = (*ClusterLinksCmd)(nil)
func NewClusterLinksCmd(ctx context.Context, args ...interface{}) *ClusterLinksCmd {
2024-02-18 10:42:21 +00:00
return &ClusterLinksCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterLinksCmd) SetVal(val []ClusterLink) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterLinksCmd) Val() []ClusterLink {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterLinksCmd) Result() ([]ClusterLink, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterLinksCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterLinksCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]ClusterLink, n)
for i := 0; i < len(cmd.val); i++ {
2024-02-18 10:42:21 +00:00
m, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
for j := 0; j < m; j++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "direction":
2024-02-18 10:42:21 +00:00
cmd.val[i].Direction, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "node":
2024-02-18 10:42:21 +00:00
cmd.val[i].Node, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "create-time":
2024-02-18 10:42:21 +00:00
cmd.val[i].CreateTime, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "events":
2024-02-18 10:42:21 +00:00
cmd.val[i].Events, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "send-buffer-allocated":
2024-02-18 10:42:21 +00:00
cmd.val[i].SendBufferAllocated, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "send-buffer-used":
2024-02-18 10:42:21 +00:00
cmd.val[i].SendBufferUsed, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected key %q in CLUSTER LINKS reply", key)
2024-02-18 10:42:21 +00:00
}
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
// ------------------------------------------------------------------------------------------------------------------
type SlotRange struct {
Start int64
End int64
2024-02-18 10:42:21 +00:00
}
type Node struct {
ID string
Endpoint string
IP string
Hostname string
Port int64
TLSPort int64
Role string
2024-02-18 10:42:21 +00:00
ReplicationOffset int64
Health string
2024-02-18 10:42:21 +00:00
}
type ClusterShard struct {
Slots []SlotRange
2024-02-18 10:42:21 +00:00
Nodes []Node
}
type ClusterShardsCmd struct {
baseCmd
val []ClusterShard
}
var _ Cmder = (*ClusterShardsCmd)(nil)
func NewClusterShardsCmd(ctx context.Context, args ...interface{}) *ClusterShardsCmd {
2024-02-18 10:42:21 +00:00
return &ClusterShardsCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterShardsCmd) SetVal(val []ClusterShard) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterShardsCmd) Val() []ClusterShard {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterShardsCmd) Result() ([]ClusterShard, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterShardsCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ClusterShardsCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val = make([]ClusterShard, n)
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
m, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
for j := 0; j < m; j++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "slots":
2024-02-18 10:42:21 +00:00
l, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
for k := 0; k < l; k += 2 {
2024-02-18 10:42:21 +00:00
start, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
end, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val[i].Slots = append(cmd.val[i].Slots, SlotRange{Start: start, End: end})
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "nodes":
2024-02-18 10:42:21 +00:00
nodesLen, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes = make([]Node, nodesLen)
2024-02-18 10:42:21 +00:00
for k := 0; k < nodesLen; k++ {
2024-02-18 10:42:21 +00:00
nodeMapLen, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
for l := 0; l < nodeMapLen; l++ {
2024-02-18 10:42:21 +00:00
nodeKey, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch nodeKey {
2024-02-18 10:42:21 +00:00
case "id":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].ID, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "endpoint":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].Endpoint, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "ip":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].IP, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "hostname":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].Hostname, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "port":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].Port, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "tls-port":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].TLSPort, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "role":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].Role, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "replication-offset":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].ReplicationOffset, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "health":
2024-02-18 10:42:21 +00:00
cmd.val[i].Nodes[k].Health, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS node reply", nodeKey)
2024-02-18 10:42:21 +00:00
}
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected key %q in CLUSTER SHARDS reply", key)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
// -----------------------------------------
type RankScore struct {
Rank int64
2024-02-18 10:42:21 +00:00
Score float64
}
type RankWithScoreCmd struct {
baseCmd
val RankScore
}
var _ Cmder = (*RankWithScoreCmd)(nil)
func NewRankWithScoreCmd(ctx context.Context, args ...interface{}) *RankWithScoreCmd {
2024-02-18 10:42:21 +00:00
return &RankWithScoreCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *RankWithScoreCmd) SetVal(val RankScore) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *RankWithScoreCmd) Val() RankScore {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *RankWithScoreCmd) Result() (RankScore, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *RankWithScoreCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *RankWithScoreCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
if err := rd.ReadFixedArrayLen(2); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
rank, err := rd.ReadInt()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
score, err := rd.ReadFloat()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = RankScore{Rank: rank, Score: score}
return nil
2024-02-18 10:42:21 +00:00
}
// --------------------------------------------------------------------------------------------------
// ClientFlags is redis-server client flags, copy from redis/src/server.h (redis 7.0)
2024-02-18 10:42:21 +00:00
type ClientFlags uint64
const (
ClientSlave ClientFlags = 1 << 0 /* This client is a replica */
ClientMaster ClientFlags = 1 << 1 /* This client is a master */
ClientMonitor ClientFlags = 1 << 2 /* This client is a slave monitor, see MONITOR */
ClientMulti ClientFlags = 1 << 3 /* This client is in a MULTI context */
ClientBlocked ClientFlags = 1 << 4 /* The client is waiting in a blocking operation */
ClientDirtyCAS ClientFlags = 1 << 5 /* Watched keys modified. EXEC will fail. */
ClientCloseAfterReply ClientFlags = 1 << 6 /* Close after writing entire reply. */
ClientUnBlocked ClientFlags = 1 << 7 /* This client was unblocked and is stored in server.unblocked_clients */
ClientScript ClientFlags = 1 << 8 /* This is a non-connected client used by Lua */
ClientAsking ClientFlags = 1 << 9 /* Client issued the ASKING command */
ClientCloseASAP ClientFlags = 1 << 10 /* Close this client ASAP */
ClientUnixSocket ClientFlags = 1 << 11 /* Client connected via Unix domain socket */
ClientDirtyExec ClientFlags = 1 << 12 /* EXEC will fail for errors while queueing */
2024-02-18 10:42:21 +00:00
ClientMasterForceReply ClientFlags = 1 << 13 /* Queue replies even if is master */
ClientForceAOF ClientFlags = 1 << 14 /* Force AOF propagation of current cmd. */
ClientForceRepl ClientFlags = 1 << 15 /* Force replication of current cmd. */
ClientPrePSync ClientFlags = 1 << 16 /* Instance don't understand PSYNC. */
ClientReadOnly ClientFlags = 1 << 17 /* Cluster client is in read-only state. */
ClientPubSub ClientFlags = 1 << 18 /* Client is in Pub/Sub mode. */
ClientPreventAOFProp ClientFlags = 1 << 19 /* Don't propagate to AOF. */
ClientPreventReplProp ClientFlags = 1 << 20 /* Don't propagate to slaves. */
ClientPreventProp ClientFlags = ClientPreventAOFProp | ClientPreventReplProp
ClientPendingWrite ClientFlags = 1 << 21 /* Client has output to send but a-write handler is yet not installed. */
ClientReplyOff ClientFlags = 1 << 22 /* Don't send replies to client. */
ClientReplySkipNext ClientFlags = 1 << 23 /* Set ClientREPLY_SKIP for next cmd */
ClientReplySkip ClientFlags = 1 << 24 /* Don't send just this reply. */
ClientLuaDebug ClientFlags = 1 << 25 /* Run EVAL in debug mode. */
ClientLuaDebugSync ClientFlags = 1 << 26 /* EVAL debugging without fork() */
ClientModule ClientFlags = 1 << 27 /* Non connected client used by some module. */
ClientProtected ClientFlags = 1 << 28 /* Client should not be freed for now. */
2024-02-18 10:42:21 +00:00
ClientExecutingCommand ClientFlags = 1 << 29 /* Indicates that the client is currently in the process of handling
2024-02-18 10:42:21 +00:00
a command. usually this will be marked only during call()
2024-02-18 10:42:21 +00:00
however, blocked clients might have this flag kept until they
2024-02-18 10:42:21 +00:00
will try to reprocess the command. */
ClientPendingCommand ClientFlags = 1 << 30 /* Indicates the client has a fully * parsed command ready for execution. */
ClientTracking ClientFlags = 1 << 31 /* Client enabled keys tracking in order to perform client side caching. */
2024-02-18 10:42:21 +00:00
ClientTrackingBrokenRedir ClientFlags = 1 << 32 /* Target client is invalid. */
ClientTrackingBCAST ClientFlags = 1 << 33 /* Tracking in BCAST mode. */
ClientTrackingOptIn ClientFlags = 1 << 34 /* Tracking in opt-in mode. */
ClientTrackingOptOut ClientFlags = 1 << 35 /* Tracking in opt-out mode. */
ClientTrackingCaching ClientFlags = 1 << 36 /* CACHING yes/no was given, depending on optin/optout mode. */
ClientTrackingNoLoop ClientFlags = 1 << 37 /* Don't send invalidation messages about writes performed by myself.*/
ClientInTimeoutTable ClientFlags = 1 << 38 /* This client is in the timeout table. */
ClientProtocolError ClientFlags = 1 << 39 /* Protocol error chatting with it. */
ClientCloseAfterCommand ClientFlags = 1 << 40 /* Close after executing commands * and writing entire reply. */
ClientDenyBlocking ClientFlags = 1 << 41 /* Indicate that the client should not be blocked. currently, turned on inside MULTI, Lua, RM_Call, and AOF client */
ClientReplRDBOnly ClientFlags = 1 << 42 /* This client is a replica that only wants RDB without replication buffer. */
ClientNoEvict ClientFlags = 1 << 43 /* This client is protected against client memory eviction. */
ClientAllowOOM ClientFlags = 1 << 44 /* Client used by RM_Call is allowed to fully execute scripts even when in OOM */
ClientNoTouch ClientFlags = 1 << 45 /* This client will not touch LFU/LRU stats. */
ClientPushing ClientFlags = 1 << 46 /* This client is pushing notifications. */
2024-02-18 10:42:21 +00:00
)
// ClientInfo is redis-server ClientInfo, not go-redis *Client
2024-02-18 10:42:21 +00:00
type ClientInfo struct {
ID int64 // redis version 2.8.12, a unique 64-bit client ID
Addr string // address/port of the client
LAddr string // address/port of local address client connected to (bind address)
FD int64 // file descriptor corresponding to the socket
Name string // the name set by the client with CLIENT SETNAME
Age time.Duration // total duration of the connection in seconds
Idle time.Duration // idle time of the connection in seconds
Flags ClientFlags // client flags (see below)
DB int // current database ID
Sub int // number of channel subscriptions
PSub int // number of pattern matching subscriptions
SSub int // redis version 7.0.3, number of shard channel subscriptions
Multi int // number of commands in a MULTI/EXEC context
QueryBuf int // qbuf, query buffer length (0 means no query pending)
QueryBufFree int // qbuf-free, free space of the query buffer (0 means the buffer is full)
ArgvMem int // incomplete arguments for the next command (already extracted from query buffer)
MultiMem int // redis version 7.0, memory is used up by buffered multi commands
BufferSize int // rbs, usable size of buffer
BufferPeak int // rbp, peak used size of buffer in last 5 sec interval
OutputBufferLength int // obl, output buffer length
OutputListLength int // oll, output list length (replies are queued in this list when the buffer is full)
OutputMemory int // omem, output buffer memory usage
TotalMemory int // tot-mem, total memory consumed by this client in its various buffers
Events string // file descriptor events (see below)
LastCmd string // cmd, last command played
User string // the authenticated username of the client
Redir int64 // client id of current client tracking redirection
Resp int // redis version 7.0, client RESP protocol version
LibName string // redis version 7.2, client library name
LibVer string // redis version 7.2, client library version
2024-02-18 10:42:21 +00:00
}
type ClientInfoCmd struct {
baseCmd
val *ClientInfo
}
var _ Cmder = (*ClientInfoCmd)(nil)
func NewClientInfoCmd(ctx context.Context, args ...interface{}) *ClientInfoCmd {
2024-02-18 10:42:21 +00:00
return &ClientInfoCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ClientInfoCmd) SetVal(val *ClientInfo) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClientInfoCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ClientInfoCmd) Val() *ClientInfo {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ClientInfoCmd) Result() (*ClientInfo, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ClientInfoCmd) readReply(rd *proto.Reader) (err error) {
2024-02-18 10:42:21 +00:00
txt, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// sds o = catClientInfoString(sdsempty(), c);
2024-02-18 10:42:21 +00:00
// o = sdscatlen(o,"\n",1);
2024-02-18 10:42:21 +00:00
// addReplyVerbatim(c,o,sdslen(o),"txt");
2024-02-18 10:42:21 +00:00
// sdsfree(o);
2024-02-18 10:42:21 +00:00
cmd.val, err = parseClientInfo(strings.TrimSpace(txt))
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// fmt.Sscanf() cannot handle null values
2024-02-18 10:42:21 +00:00
func parseClientInfo(txt string) (info *ClientInfo, err error) {
2024-02-18 10:42:21 +00:00
info = &ClientInfo{}
2024-02-18 10:42:21 +00:00
for _, s := range strings.Split(txt, " ") {
2024-02-18 10:42:21 +00:00
kv := strings.Split(s, "=")
2024-02-18 10:42:21 +00:00
if len(kv) != 2 {
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: unexpected client info data (%s)", s)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
key, val := kv[0], kv[1]
switch key {
2024-02-18 10:42:21 +00:00
case "id":
2024-02-18 10:42:21 +00:00
info.ID, err = strconv.ParseInt(val, 10, 64)
2024-02-18 10:42:21 +00:00
case "addr":
2024-02-18 10:42:21 +00:00
info.Addr = val
2024-02-18 10:42:21 +00:00
case "laddr":
2024-02-18 10:42:21 +00:00
info.LAddr = val
2024-02-18 10:42:21 +00:00
case "fd":
2024-02-18 10:42:21 +00:00
info.FD, err = strconv.ParseInt(val, 10, 64)
2024-02-18 10:42:21 +00:00
case "name":
2024-02-18 10:42:21 +00:00
info.Name = val
2024-02-18 10:42:21 +00:00
case "age":
2024-02-18 10:42:21 +00:00
var age int
2024-02-18 10:42:21 +00:00
if age, err = strconv.Atoi(val); err == nil {
2024-02-18 10:42:21 +00:00
info.Age = time.Duration(age) * time.Second
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "idle":
2024-02-18 10:42:21 +00:00
var idle int
2024-02-18 10:42:21 +00:00
if idle, err = strconv.Atoi(val); err == nil {
2024-02-18 10:42:21 +00:00
info.Idle = time.Duration(idle) * time.Second
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "flags":
2024-02-18 10:42:21 +00:00
if val == "N" {
2024-02-18 10:42:21 +00:00
break
2024-02-18 10:42:21 +00:00
}
for i := 0; i < len(val); i++ {
2024-02-18 10:42:21 +00:00
switch val[i] {
2024-02-18 10:42:21 +00:00
case 'S':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientSlave
2024-02-18 10:42:21 +00:00
case 'O':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientSlave | ClientMonitor
2024-02-18 10:42:21 +00:00
case 'M':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientMaster
2024-02-18 10:42:21 +00:00
case 'P':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientPubSub
2024-02-18 10:42:21 +00:00
case 'x':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientMulti
2024-02-18 10:42:21 +00:00
case 'b':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientBlocked
2024-02-18 10:42:21 +00:00
case 't':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientTracking
2024-02-18 10:42:21 +00:00
case 'R':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientTrackingBrokenRedir
2024-02-18 10:42:21 +00:00
case 'B':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientTrackingBCAST
2024-02-18 10:42:21 +00:00
case 'd':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientDirtyCAS
2024-02-18 10:42:21 +00:00
case 'c':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientCloseAfterCommand
2024-02-18 10:42:21 +00:00
case 'u':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientUnBlocked
2024-02-18 10:42:21 +00:00
case 'A':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientCloseASAP
2024-02-18 10:42:21 +00:00
case 'U':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientUnixSocket
2024-02-18 10:42:21 +00:00
case 'r':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientReadOnly
2024-02-18 10:42:21 +00:00
case 'e':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientNoEvict
2024-02-18 10:42:21 +00:00
case 'T':
2024-02-18 10:42:21 +00:00
info.Flags |= ClientNoTouch
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: unexpected client info flags(%s)", string(val[i]))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "db":
2024-02-18 10:42:21 +00:00
info.DB, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "sub":
2024-02-18 10:42:21 +00:00
info.Sub, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "psub":
2024-02-18 10:42:21 +00:00
info.PSub, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "ssub":
2024-02-18 10:42:21 +00:00
info.SSub, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "multi":
2024-02-18 10:42:21 +00:00
info.Multi, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "qbuf":
2024-02-18 10:42:21 +00:00
info.QueryBuf, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "qbuf-free":
2024-02-18 10:42:21 +00:00
info.QueryBufFree, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "argv-mem":
2024-02-18 10:42:21 +00:00
info.ArgvMem, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "multi-mem":
2024-02-18 10:42:21 +00:00
info.MultiMem, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "rbs":
2024-02-18 10:42:21 +00:00
info.BufferSize, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "rbp":
2024-02-18 10:42:21 +00:00
info.BufferPeak, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "obl":
2024-02-18 10:42:21 +00:00
info.OutputBufferLength, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "oll":
2024-02-18 10:42:21 +00:00
info.OutputListLength, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "omem":
2024-02-18 10:42:21 +00:00
info.OutputMemory, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "tot-mem":
2024-02-18 10:42:21 +00:00
info.TotalMemory, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "events":
2024-02-18 10:42:21 +00:00
info.Events = val
2024-02-18 10:42:21 +00:00
case "cmd":
2024-02-18 10:42:21 +00:00
info.LastCmd = val
2024-02-18 10:42:21 +00:00
case "user":
2024-02-18 10:42:21 +00:00
info.User = val
2024-02-18 10:42:21 +00:00
case "redir":
2024-02-18 10:42:21 +00:00
info.Redir, err = strconv.ParseInt(val, 10, 64)
2024-02-18 10:42:21 +00:00
case "resp":
2024-02-18 10:42:21 +00:00
info.Resp, err = strconv.Atoi(val)
2024-02-18 10:42:21 +00:00
case "lib-name":
2024-02-18 10:42:21 +00:00
info.LibName = val
2024-02-18 10:42:21 +00:00
case "lib-ver":
2024-02-18 10:42:21 +00:00
info.LibVer = val
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: unexpected client info key(%s)", key)
2024-02-18 10:42:21 +00:00
}
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return info, nil
2024-02-18 10:42:21 +00:00
}
// -------------------------------------------
type ACLLogEntry struct {
Count int64
Reason string
Context string
Object string
Username string
AgeSeconds float64
ClientInfo *ClientInfo
EntryID int64
TimestampCreated int64
2024-02-18 10:42:21 +00:00
TimestampLastUpdated int64
}
type ACLLogCmd struct {
baseCmd
val []*ACLLogEntry
}
var _ Cmder = (*ACLLogCmd)(nil)
func NewACLLogCmd(ctx context.Context, args ...interface{}) *ACLLogCmd {
2024-02-18 10:42:21 +00:00
return &ACLLogCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *ACLLogCmd) SetVal(val []*ACLLogEntry) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *ACLLogCmd) Val() []*ACLLogEntry {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *ACLLogCmd) Result() ([]*ACLLogEntry, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *ACLLogCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *ACLLogCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
n, err := rd.ReadArrayLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
cmd.val = make([]*ACLLogEntry, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
cmd.val[i] = &ACLLogEntry{}
2024-02-18 10:42:21 +00:00
entry := cmd.val[i]
2024-02-18 10:42:21 +00:00
respLen, err := rd.ReadMapLen()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
for j := 0; j < respLen; j++ {
2024-02-18 10:42:21 +00:00
key, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
switch key {
2024-02-18 10:42:21 +00:00
case "count":
2024-02-18 10:42:21 +00:00
entry.Count, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "reason":
2024-02-18 10:42:21 +00:00
entry.Reason, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "context":
2024-02-18 10:42:21 +00:00
entry.Context, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "object":
2024-02-18 10:42:21 +00:00
entry.Object, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "username":
2024-02-18 10:42:21 +00:00
entry.Username, err = rd.ReadString()
2024-02-18 10:42:21 +00:00
case "age-seconds":
2024-02-18 10:42:21 +00:00
entry.AgeSeconds, err = rd.ReadFloat()
2024-02-18 10:42:21 +00:00
case "client-info":
2024-02-18 10:42:21 +00:00
txt, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
entry.ClientInfo, err = parseClientInfo(strings.TrimSpace(txt))
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
case "entry-id":
2024-02-18 10:42:21 +00:00
entry.EntryID, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "timestamp-created":
2024-02-18 10:42:21 +00:00
entry.TimestampCreated, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
case "timestamp-last-updated":
2024-02-18 10:42:21 +00:00
entry.TimestampLastUpdated, err = rd.ReadInt()
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: unexpected key %q in ACL LOG reply", key)
2024-02-18 10:42:21 +00:00
}
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
// LibraryInfo holds the library info.
2024-02-18 10:42:21 +00:00
type LibraryInfo struct {
LibName *string
LibVer *string
2024-02-18 10:42:21 +00:00
}
// -------------------------------------------
type InfoCmd struct {
baseCmd
2024-02-18 10:42:21 +00:00
val map[string]map[string]string
}
var _ Cmder = (*InfoCmd)(nil)
func NewInfoCmd(ctx context.Context, args ...interface{}) *InfoCmd {
2024-02-18 10:42:21 +00:00
return &InfoCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: args,
},
}
2024-02-18 10:42:21 +00:00
}
func (cmd *InfoCmd) SetVal(val map[string]map[string]string) {
2024-02-18 10:42:21 +00:00
cmd.val = val
2024-02-18 10:42:21 +00:00
}
func (cmd *InfoCmd) Val() map[string]map[string]string {
2024-02-18 10:42:21 +00:00
return cmd.val
2024-02-18 10:42:21 +00:00
}
func (cmd *InfoCmd) Result() (map[string]map[string]string, error) {
2024-02-18 10:42:21 +00:00
return cmd.val, cmd.err
2024-02-18 10:42:21 +00:00
}
func (cmd *InfoCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, cmd.val)
2024-02-18 10:42:21 +00:00
}
func (cmd *InfoCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
val, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
section := ""
2024-02-18 10:42:21 +00:00
scanner := bufio.NewScanner(strings.NewReader(val))
2024-02-18 10:42:21 +00:00
moduleRe := regexp.MustCompile(`module:name=(.+?),(.+)$`)
for scanner.Scan() {
2024-02-18 10:42:21 +00:00
line := scanner.Text()
2024-02-18 10:42:21 +00:00
if strings.HasPrefix(line, "#") {
2024-02-18 10:42:21 +00:00
if cmd.val == nil {
2024-02-18 10:42:21 +00:00
cmd.val = make(map[string]map[string]string)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
section = strings.TrimPrefix(line, "# ")
2024-02-18 10:42:21 +00:00
cmd.val[section] = make(map[string]string)
2024-02-18 10:42:21 +00:00
} else if line != "" {
2024-02-18 10:42:21 +00:00
if section == "Modules" {
2024-02-18 10:42:21 +00:00
kv := moduleRe.FindStringSubmatch(line)
2024-02-18 10:42:21 +00:00
if len(kv) == 3 {
2024-02-18 10:42:21 +00:00
cmd.val[section][kv[1]] = kv[2]
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
kv := strings.SplitN(line, ":", 2)
2024-02-18 10:42:21 +00:00
if len(kv) == 2 {
2024-02-18 10:42:21 +00:00
cmd.val[section][kv[0]] = kv[1]
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
func (cmd *InfoCmd) Item(section, key string) string {
2024-02-18 10:42:21 +00:00
if cmd.val == nil {
2024-02-18 10:42:21 +00:00
return ""
2024-02-18 10:42:21 +00:00
} else if cmd.val[section] == nil {
2024-02-18 10:42:21 +00:00
return ""
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
return cmd.val[section][key]
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
type MonitorStatus int
const (
monitorStatusIdle MonitorStatus = iota
2024-02-18 10:42:21 +00:00
monitorStatusStart
2024-02-18 10:42:21 +00:00
monitorStatusStop
)
type MonitorCmd struct {
baseCmd
ch chan string
2024-02-18 10:42:21 +00:00
status MonitorStatus
mu sync.Mutex
2024-02-18 10:42:21 +00:00
}
func newMonitorCmd(ctx context.Context, ch chan string) *MonitorCmd {
2024-02-18 10:42:21 +00:00
return &MonitorCmd{
2024-02-18 10:42:21 +00:00
baseCmd: baseCmd{
ctx: ctx,
2024-02-18 10:42:21 +00:00
args: []interface{}{"monitor"},
},
ch: ch,
2024-02-18 10:42:21 +00:00
status: monitorStatusIdle,
mu: sync.Mutex{},
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func (cmd *MonitorCmd) String() string {
2024-02-18 10:42:21 +00:00
return cmdString(cmd, nil)
2024-02-18 10:42:21 +00:00
}
func (cmd *MonitorCmd) readReply(rd *proto.Reader) error {
2024-02-18 10:42:21 +00:00
ctx, cancel := context.WithCancel(cmd.ctx)
2024-02-18 10:42:21 +00:00
go func(ctx context.Context) {
2024-02-18 10:42:21 +00:00
for {
2024-02-18 10:42:21 +00:00
select {
2024-02-18 10:42:21 +00:00
case <-ctx.Done():
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
err := cmd.readMonitor(rd, cancel)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
cmd.err = err
2024-02-18 10:42:21 +00:00
return
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}(ctx)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func (cmd *MonitorCmd) readMonitor(rd *proto.Reader, cancel context.CancelFunc) error {
2024-02-18 10:42:21 +00:00
for {
2024-02-18 10:42:21 +00:00
cmd.mu.Lock()
2024-02-18 10:42:21 +00:00
st := cmd.status
2024-02-18 10:42:21 +00:00
cmd.mu.Unlock()
2024-02-18 10:42:21 +00:00
if pk, _ := rd.Peek(1); len(pk) != 0 && st == monitorStatusStart {
2024-02-18 10:42:21 +00:00
line, err := rd.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
cmd.ch <- line
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if st == monitorStatusStop {
2024-02-18 10:42:21 +00:00
cancel()
2024-02-18 10:42:21 +00:00
break
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func (cmd *MonitorCmd) Start() {
2024-02-18 10:42:21 +00:00
cmd.mu.Lock()
2024-02-18 10:42:21 +00:00
defer cmd.mu.Unlock()
2024-02-18 10:42:21 +00:00
cmd.status = monitorStatusStart
2024-02-18 10:42:21 +00:00
}
func (cmd *MonitorCmd) Stop() {
2024-02-18 10:42:21 +00:00
cmd.mu.Lock()
2024-02-18 10:42:21 +00:00
defer cmd.mu.Unlock()
2024-02-18 10:42:21 +00:00
cmd.status = monitorStatusStop
2024-02-18 10:42:21 +00:00
}