1package redis 2 3import ( 4 "context" 5 "fmt" 6 "net" 7 "strconv" 8 "time" 9 10 "github.com/go-redis/redis/v8/internal" 11 "github.com/go-redis/redis/v8/internal/proto" 12 "github.com/go-redis/redis/v8/internal/util" 13) 14 15type Cmder interface { 16 Name() string 17 FullName() string 18 Args() []interface{} 19 String() string 20 stringArg(int) string 21 firstKeyPos() int8 22 setFirstKeyPos(int8) 23 24 readTimeout() *time.Duration 25 readReply(rd *proto.Reader) error 26 27 SetErr(error) 28 Err() error 29} 30 31func setCmdsErr(cmds []Cmder, e error) { 32 for _, cmd := range cmds { 33 if cmd.Err() == nil { 34 cmd.SetErr(e) 35 } 36 } 37} 38 39func cmdsFirstErr(cmds []Cmder) error { 40 for _, cmd := range cmds { 41 if err := cmd.Err(); err != nil { 42 return err 43 } 44 } 45 return nil 46} 47 48func writeCmds(wr *proto.Writer, cmds []Cmder) error { 49 for _, cmd := range cmds { 50 if err := writeCmd(wr, cmd); err != nil { 51 return err 52 } 53 } 54 return nil 55} 56 57func writeCmd(wr *proto.Writer, cmd Cmder) error { 58 return wr.WriteArgs(cmd.Args()) 59} 60 61func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int { 62 if pos := cmd.firstKeyPos(); pos != 0 { 63 return int(pos) 64 } 65 66 switch cmd.Name() { 67 case "eval", "evalsha": 68 if cmd.stringArg(2) != "0" { 69 return 3 70 } 71 72 return 0 73 case "publish": 74 return 1 75 case "memory": 76 // https://github.com/redis/redis/issues/7493 77 if cmd.stringArg(1) == "usage" { 78 return 2 79 } 80 } 81 82 if info != nil { 83 return int(info.FirstKeyPos) 84 } 85 return 0 86} 87 88func cmdString(cmd Cmder, val interface{}) string { 89 b := make([]byte, 0, 64) 90 91 for i, arg := range cmd.Args() { 92 if i > 0 { 93 b = append(b, ' ') 94 } 95 b = internal.AppendArg(b, arg) 96 } 97 98 if err := cmd.Err(); err != nil { 99 b = append(b, ": "...) 100 b = append(b, err.Error()...) 101 } else if val != nil { 102 b = append(b, ": "...) 103 b = internal.AppendArg(b, val) 104 } 105 106 return internal.String(b) 107} 108 109//------------------------------------------------------------------------------ 110 111type baseCmd struct { 112 ctx context.Context 113 args []interface{} 114 err error 115 keyPos int8 116 117 _readTimeout *time.Duration 118} 119 120var _ Cmder = (*Cmd)(nil) 121 122func (cmd *baseCmd) Name() string { 123 if len(cmd.args) == 0 { 124 return "" 125 } 126 // Cmd name must be lower cased. 127 return internal.ToLower(cmd.stringArg(0)) 128} 129 130func (cmd *baseCmd) FullName() string { 131 switch name := cmd.Name(); name { 132 case "cluster", "command": 133 if len(cmd.args) == 1 { 134 return name 135 } 136 if s2, ok := cmd.args[1].(string); ok { 137 return name + " " + s2 138 } 139 return name 140 default: 141 return name 142 } 143} 144 145func (cmd *baseCmd) Args() []interface{} { 146 return cmd.args 147} 148 149func (cmd *baseCmd) stringArg(pos int) string { 150 if pos < 0 || pos >= len(cmd.args) { 151 return "" 152 } 153 s, _ := cmd.args[pos].(string) 154 return s 155} 156 157func (cmd *baseCmd) firstKeyPos() int8 { 158 return cmd.keyPos 159} 160 161func (cmd *baseCmd) setFirstKeyPos(keyPos int8) { 162 cmd.keyPos = keyPos 163} 164 165func (cmd *baseCmd) SetErr(e error) { 166 cmd.err = e 167} 168 169func (cmd *baseCmd) Err() error { 170 return cmd.err 171} 172 173func (cmd *baseCmd) readTimeout() *time.Duration { 174 return cmd._readTimeout 175} 176 177func (cmd *baseCmd) setReadTimeout(d time.Duration) { 178 cmd._readTimeout = &d 179} 180 181//------------------------------------------------------------------------------ 182 183type Cmd struct { 184 baseCmd 185 186 val interface{} 187} 188 189func NewCmd(ctx context.Context, args ...interface{}) *Cmd { 190 return &Cmd{ 191 baseCmd: baseCmd{ 192 ctx: ctx, 193 args: args, 194 }, 195 } 196} 197 198func (cmd *Cmd) String() string { 199 return cmdString(cmd, cmd.val) 200} 201 202func (cmd *Cmd) Val() interface{} { 203 return cmd.val 204} 205 206func (cmd *Cmd) Result() (interface{}, error) { 207 return cmd.val, cmd.err 208} 209 210func (cmd *Cmd) Text() (string, error) { 211 if cmd.err != nil { 212 return "", cmd.err 213 } 214 switch val := cmd.val.(type) { 215 case string: 216 return val, nil 217 default: 218 err := fmt.Errorf("redis: unexpected type=%T for String", val) 219 return "", err 220 } 221} 222 223func (cmd *Cmd) Int() (int, error) { 224 if cmd.err != nil { 225 return 0, cmd.err 226 } 227 switch val := cmd.val.(type) { 228 case int64: 229 return int(val), nil 230 case string: 231 return strconv.Atoi(val) 232 default: 233 err := fmt.Errorf("redis: unexpected type=%T for Int", val) 234 return 0, err 235 } 236} 237 238func (cmd *Cmd) Int64() (int64, error) { 239 if cmd.err != nil { 240 return 0, cmd.err 241 } 242 switch val := cmd.val.(type) { 243 case int64: 244 return val, nil 245 case string: 246 return strconv.ParseInt(val, 10, 64) 247 default: 248 err := fmt.Errorf("redis: unexpected type=%T for Int64", val) 249 return 0, err 250 } 251} 252 253func (cmd *Cmd) Uint64() (uint64, error) { 254 if cmd.err != nil { 255 return 0, cmd.err 256 } 257 switch val := cmd.val.(type) { 258 case int64: 259 return uint64(val), nil 260 case string: 261 return strconv.ParseUint(val, 10, 64) 262 default: 263 err := fmt.Errorf("redis: unexpected type=%T for Uint64", val) 264 return 0, err 265 } 266} 267 268func (cmd *Cmd) Float32() (float32, error) { 269 if cmd.err != nil { 270 return 0, cmd.err 271 } 272 switch val := cmd.val.(type) { 273 case int64: 274 return float32(val), nil 275 case string: 276 f, err := strconv.ParseFloat(val, 32) 277 if err != nil { 278 return 0, err 279 } 280 return float32(f), nil 281 default: 282 err := fmt.Errorf("redis: unexpected type=%T for Float32", val) 283 return 0, err 284 } 285} 286 287func (cmd *Cmd) Float64() (float64, error) { 288 if cmd.err != nil { 289 return 0, cmd.err 290 } 291 switch val := cmd.val.(type) { 292 case int64: 293 return float64(val), nil 294 case string: 295 return strconv.ParseFloat(val, 64) 296 default: 297 err := fmt.Errorf("redis: unexpected type=%T for Float64", val) 298 return 0, err 299 } 300} 301 302func (cmd *Cmd) Bool() (bool, error) { 303 if cmd.err != nil { 304 return false, cmd.err 305 } 306 switch val := cmd.val.(type) { 307 case int64: 308 return val != 0, nil 309 case string: 310 return strconv.ParseBool(val) 311 default: 312 err := fmt.Errorf("redis: unexpected type=%T for Bool", val) 313 return false, err 314 } 315} 316 317func (cmd *Cmd) readReply(rd *proto.Reader) (err error) { 318 cmd.val, err = rd.ReadReply(sliceParser) 319 return err 320} 321 322// sliceParser implements proto.MultiBulkParse. 323func sliceParser(rd *proto.Reader, n int64) (interface{}, error) { 324 vals := make([]interface{}, n) 325 for i := 0; i < len(vals); i++ { 326 v, err := rd.ReadReply(sliceParser) 327 if err != nil { 328 if err == Nil { 329 vals[i] = nil 330 continue 331 } 332 if err, ok := err.(proto.RedisError); ok { 333 vals[i] = err 334 continue 335 } 336 return nil, err 337 } 338 vals[i] = v 339 } 340 return vals, nil 341} 342 343//------------------------------------------------------------------------------ 344 345type SliceCmd struct { 346 baseCmd 347 348 val []interface{} 349} 350 351var _ Cmder = (*SliceCmd)(nil) 352 353func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd { 354 return &SliceCmd{ 355 baseCmd: baseCmd{ 356 ctx: ctx, 357 args: args, 358 }, 359 } 360} 361 362func (cmd *SliceCmd) Val() []interface{} { 363 return cmd.val 364} 365 366func (cmd *SliceCmd) Result() ([]interface{}, error) { 367 return cmd.val, cmd.err 368} 369 370func (cmd *SliceCmd) String() string { 371 return cmdString(cmd, cmd.val) 372} 373 374func (cmd *SliceCmd) readReply(rd *proto.Reader) error { 375 v, err := rd.ReadArrayReply(sliceParser) 376 if err != nil { 377 return err 378 } 379 cmd.val = v.([]interface{}) 380 return nil 381} 382 383//------------------------------------------------------------------------------ 384 385type StatusCmd struct { 386 baseCmd 387 388 val string 389} 390 391var _ Cmder = (*StatusCmd)(nil) 392 393func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd { 394 return &StatusCmd{ 395 baseCmd: baseCmd{ 396 ctx: ctx, 397 args: args, 398 }, 399 } 400} 401 402func (cmd *StatusCmd) Val() string { 403 return cmd.val 404} 405 406func (cmd *StatusCmd) Result() (string, error) { 407 return cmd.val, cmd.err 408} 409 410func (cmd *StatusCmd) String() string { 411 return cmdString(cmd, cmd.val) 412} 413 414func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) { 415 cmd.val, err = rd.ReadString() 416 return err 417} 418 419//------------------------------------------------------------------------------ 420 421type IntCmd struct { 422 baseCmd 423 424 val int64 425} 426 427var _ Cmder = (*IntCmd)(nil) 428 429func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd { 430 return &IntCmd{ 431 baseCmd: baseCmd{ 432 ctx: ctx, 433 args: args, 434 }, 435 } 436} 437 438func (cmd *IntCmd) Val() int64 { 439 return cmd.val 440} 441 442func (cmd *IntCmd) Result() (int64, error) { 443 return cmd.val, cmd.err 444} 445 446func (cmd *IntCmd) Uint64() (uint64, error) { 447 return uint64(cmd.val), cmd.err 448} 449 450func (cmd *IntCmd) String() string { 451 return cmdString(cmd, cmd.val) 452} 453 454func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) { 455 cmd.val, err = rd.ReadIntReply() 456 return err 457} 458 459//------------------------------------------------------------------------------ 460 461type IntSliceCmd struct { 462 baseCmd 463 464 val []int64 465} 466 467var _ Cmder = (*IntSliceCmd)(nil) 468 469func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd { 470 return &IntSliceCmd{ 471 baseCmd: baseCmd{ 472 ctx: ctx, 473 args: args, 474 }, 475 } 476} 477 478func (cmd *IntSliceCmd) Val() []int64 { 479 return cmd.val 480} 481 482func (cmd *IntSliceCmd) Result() ([]int64, error) { 483 return cmd.val, cmd.err 484} 485 486func (cmd *IntSliceCmd) String() string { 487 return cmdString(cmd, cmd.val) 488} 489 490func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error { 491 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 492 cmd.val = make([]int64, n) 493 for i := 0; i < len(cmd.val); i++ { 494 num, err := rd.ReadIntReply() 495 if err != nil { 496 return nil, err 497 } 498 cmd.val[i] = num 499 } 500 return nil, nil 501 }) 502 return err 503} 504 505//------------------------------------------------------------------------------ 506 507type DurationCmd struct { 508 baseCmd 509 510 val time.Duration 511 precision time.Duration 512} 513 514var _ Cmder = (*DurationCmd)(nil) 515 516func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd { 517 return &DurationCmd{ 518 baseCmd: baseCmd{ 519 ctx: ctx, 520 args: args, 521 }, 522 precision: precision, 523 } 524} 525 526func (cmd *DurationCmd) Val() time.Duration { 527 return cmd.val 528} 529 530func (cmd *DurationCmd) Result() (time.Duration, error) { 531 return cmd.val, cmd.err 532} 533 534func (cmd *DurationCmd) String() string { 535 return cmdString(cmd, cmd.val) 536} 537 538func (cmd *DurationCmd) readReply(rd *proto.Reader) error { 539 n, err := rd.ReadIntReply() 540 if err != nil { 541 return err 542 } 543 switch n { 544 // -2 if the key does not exist 545 // -1 if the key exists but has no associated expire 546 case -2, -1: 547 cmd.val = time.Duration(n) 548 default: 549 cmd.val = time.Duration(n) * cmd.precision 550 } 551 return nil 552} 553 554//------------------------------------------------------------------------------ 555 556type TimeCmd struct { 557 baseCmd 558 559 val time.Time 560} 561 562var _ Cmder = (*TimeCmd)(nil) 563 564func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd { 565 return &TimeCmd{ 566 baseCmd: baseCmd{ 567 ctx: ctx, 568 args: args, 569 }, 570 } 571} 572 573func (cmd *TimeCmd) Val() time.Time { 574 return cmd.val 575} 576 577func (cmd *TimeCmd) Result() (time.Time, error) { 578 return cmd.val, cmd.err 579} 580 581func (cmd *TimeCmd) String() string { 582 return cmdString(cmd, cmd.val) 583} 584 585func (cmd *TimeCmd) readReply(rd *proto.Reader) error { 586 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 587 if n != 2 { 588 return nil, fmt.Errorf("got %d elements, expected 2", n) 589 } 590 591 sec, err := rd.ReadInt() 592 if err != nil { 593 return nil, err 594 } 595 596 microsec, err := rd.ReadInt() 597 if err != nil { 598 return nil, err 599 } 600 601 cmd.val = time.Unix(sec, microsec*1000) 602 return nil, nil 603 }) 604 return err 605} 606 607//------------------------------------------------------------------------------ 608 609type BoolCmd struct { 610 baseCmd 611 612 val bool 613} 614 615var _ Cmder = (*BoolCmd)(nil) 616 617func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd { 618 return &BoolCmd{ 619 baseCmd: baseCmd{ 620 ctx: ctx, 621 args: args, 622 }, 623 } 624} 625 626func (cmd *BoolCmd) Val() bool { 627 return cmd.val 628} 629 630func (cmd *BoolCmd) Result() (bool, error) { 631 return cmd.val, cmd.err 632} 633 634func (cmd *BoolCmd) String() string { 635 return cmdString(cmd, cmd.val) 636} 637 638func (cmd *BoolCmd) readReply(rd *proto.Reader) error { 639 v, err := rd.ReadReply(nil) 640 // `SET key value NX` returns nil when key already exists. But 641 // `SETNX key value` returns bool (0/1). So convert nil to bool. 642 if err == Nil { 643 cmd.val = false 644 return nil 645 } 646 if err != nil { 647 return err 648 } 649 switch v := v.(type) { 650 case int64: 651 cmd.val = v == 1 652 return nil 653 case string: 654 cmd.val = v == "OK" 655 return nil 656 default: 657 return fmt.Errorf("got %T, wanted int64 or string", v) 658 } 659} 660 661//------------------------------------------------------------------------------ 662 663type StringCmd struct { 664 baseCmd 665 666 val string 667} 668 669var _ Cmder = (*StringCmd)(nil) 670 671func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd { 672 return &StringCmd{ 673 baseCmd: baseCmd{ 674 ctx: ctx, 675 args: args, 676 }, 677 } 678} 679 680func (cmd *StringCmd) Val() string { 681 return cmd.val 682} 683 684func (cmd *StringCmd) Result() (string, error) { 685 return cmd.Val(), cmd.err 686} 687 688func (cmd *StringCmd) Bytes() ([]byte, error) { 689 return util.StringToBytes(cmd.val), cmd.err 690} 691 692func (cmd *StringCmd) Int() (int, error) { 693 if cmd.err != nil { 694 return 0, cmd.err 695 } 696 return strconv.Atoi(cmd.Val()) 697} 698 699func (cmd *StringCmd) Int64() (int64, error) { 700 if cmd.err != nil { 701 return 0, cmd.err 702 } 703 return strconv.ParseInt(cmd.Val(), 10, 64) 704} 705 706func (cmd *StringCmd) Uint64() (uint64, error) { 707 if cmd.err != nil { 708 return 0, cmd.err 709 } 710 return strconv.ParseUint(cmd.Val(), 10, 64) 711} 712 713func (cmd *StringCmd) Float32() (float32, error) { 714 if cmd.err != nil { 715 return 0, cmd.err 716 } 717 f, err := strconv.ParseFloat(cmd.Val(), 32) 718 if err != nil { 719 return 0, err 720 } 721 return float32(f), nil 722} 723 724func (cmd *StringCmd) Float64() (float64, error) { 725 if cmd.err != nil { 726 return 0, cmd.err 727 } 728 return strconv.ParseFloat(cmd.Val(), 64) 729} 730 731func (cmd *StringCmd) Time() (time.Time, error) { 732 if cmd.err != nil { 733 return time.Time{}, cmd.err 734 } 735 return time.Parse(time.RFC3339Nano, cmd.Val()) 736} 737 738func (cmd *StringCmd) Scan(val interface{}) error { 739 if cmd.err != nil { 740 return cmd.err 741 } 742 return proto.Scan([]byte(cmd.val), val) 743} 744 745func (cmd *StringCmd) String() string { 746 return cmdString(cmd, cmd.val) 747} 748 749func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) { 750 cmd.val, err = rd.ReadString() 751 return err 752} 753 754//------------------------------------------------------------------------------ 755 756type FloatCmd struct { 757 baseCmd 758 759 val float64 760} 761 762var _ Cmder = (*FloatCmd)(nil) 763 764func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd { 765 return &FloatCmd{ 766 baseCmd: baseCmd{ 767 ctx: ctx, 768 args: args, 769 }, 770 } 771} 772 773func (cmd *FloatCmd) Val() float64 { 774 return cmd.val 775} 776 777func (cmd *FloatCmd) Result() (float64, error) { 778 return cmd.Val(), cmd.Err() 779} 780 781func (cmd *FloatCmd) String() string { 782 return cmdString(cmd, cmd.val) 783} 784 785func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) { 786 cmd.val, err = rd.ReadFloatReply() 787 return err 788} 789 790//------------------------------------------------------------------------------ 791 792type StringSliceCmd struct { 793 baseCmd 794 795 val []string 796} 797 798var _ Cmder = (*StringSliceCmd)(nil) 799 800func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd { 801 return &StringSliceCmd{ 802 baseCmd: baseCmd{ 803 ctx: ctx, 804 args: args, 805 }, 806 } 807} 808 809func (cmd *StringSliceCmd) Val() []string { 810 return cmd.val 811} 812 813func (cmd *StringSliceCmd) Result() ([]string, error) { 814 return cmd.Val(), cmd.Err() 815} 816 817func (cmd *StringSliceCmd) String() string { 818 return cmdString(cmd, cmd.val) 819} 820 821func (cmd *StringSliceCmd) ScanSlice(container interface{}) error { 822 return proto.ScanSlice(cmd.Val(), container) 823} 824 825func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error { 826 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 827 cmd.val = make([]string, n) 828 for i := 0; i < len(cmd.val); i++ { 829 switch s, err := rd.ReadString(); { 830 case err == Nil: 831 cmd.val[i] = "" 832 case err != nil: 833 return nil, err 834 default: 835 cmd.val[i] = s 836 } 837 } 838 return nil, nil 839 }) 840 return err 841} 842 843//------------------------------------------------------------------------------ 844 845type BoolSliceCmd struct { 846 baseCmd 847 848 val []bool 849} 850 851var _ Cmder = (*BoolSliceCmd)(nil) 852 853func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd { 854 return &BoolSliceCmd{ 855 baseCmd: baseCmd{ 856 ctx: ctx, 857 args: args, 858 }, 859 } 860} 861 862func (cmd *BoolSliceCmd) Val() []bool { 863 return cmd.val 864} 865 866func (cmd *BoolSliceCmd) Result() ([]bool, error) { 867 return cmd.val, cmd.err 868} 869 870func (cmd *BoolSliceCmd) String() string { 871 return cmdString(cmd, cmd.val) 872} 873 874func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error { 875 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 876 cmd.val = make([]bool, n) 877 for i := 0; i < len(cmd.val); i++ { 878 n, err := rd.ReadIntReply() 879 if err != nil { 880 return nil, err 881 } 882 cmd.val[i] = n == 1 883 } 884 return nil, nil 885 }) 886 return err 887} 888 889//------------------------------------------------------------------------------ 890 891type StringStringMapCmd struct { 892 baseCmd 893 894 val map[string]string 895} 896 897var _ Cmder = (*StringStringMapCmd)(nil) 898 899func NewStringStringMapCmd(ctx context.Context, args ...interface{}) *StringStringMapCmd { 900 return &StringStringMapCmd{ 901 baseCmd: baseCmd{ 902 ctx: ctx, 903 args: args, 904 }, 905 } 906} 907 908func (cmd *StringStringMapCmd) Val() map[string]string { 909 return cmd.val 910} 911 912func (cmd *StringStringMapCmd) Result() (map[string]string, error) { 913 return cmd.val, cmd.err 914} 915 916func (cmd *StringStringMapCmd) String() string { 917 return cmdString(cmd, cmd.val) 918} 919 920func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error { 921 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 922 cmd.val = make(map[string]string, n/2) 923 for i := int64(0); i < n; i += 2 { 924 key, err := rd.ReadString() 925 if err != nil { 926 return nil, err 927 } 928 929 value, err := rd.ReadString() 930 if err != nil { 931 return nil, err 932 } 933 934 cmd.val[key] = value 935 } 936 return nil, nil 937 }) 938 return err 939} 940 941//------------------------------------------------------------------------------ 942 943type StringIntMapCmd struct { 944 baseCmd 945 946 val map[string]int64 947} 948 949var _ Cmder = (*StringIntMapCmd)(nil) 950 951func NewStringIntMapCmd(ctx context.Context, args ...interface{}) *StringIntMapCmd { 952 return &StringIntMapCmd{ 953 baseCmd: baseCmd{ 954 ctx: ctx, 955 args: args, 956 }, 957 } 958} 959 960func (cmd *StringIntMapCmd) Val() map[string]int64 { 961 return cmd.val 962} 963 964func (cmd *StringIntMapCmd) Result() (map[string]int64, error) { 965 return cmd.val, cmd.err 966} 967 968func (cmd *StringIntMapCmd) String() string { 969 return cmdString(cmd, cmd.val) 970} 971 972func (cmd *StringIntMapCmd) readReply(rd *proto.Reader) error { 973 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 974 cmd.val = make(map[string]int64, n/2) 975 for i := int64(0); i < n; i += 2 { 976 key, err := rd.ReadString() 977 if err != nil { 978 return nil, err 979 } 980 981 n, err := rd.ReadIntReply() 982 if err != nil { 983 return nil, err 984 } 985 986 cmd.val[key] = n 987 } 988 return nil, nil 989 }) 990 return err 991} 992 993//------------------------------------------------------------------------------ 994 995type StringStructMapCmd struct { 996 baseCmd 997 998 val map[string]struct{} 999} 1000 1001var _ Cmder = (*StringStructMapCmd)(nil) 1002 1003func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd { 1004 return &StringStructMapCmd{ 1005 baseCmd: baseCmd{ 1006 ctx: ctx, 1007 args: args, 1008 }, 1009 } 1010} 1011 1012func (cmd *StringStructMapCmd) Val() map[string]struct{} { 1013 return cmd.val 1014} 1015 1016func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) { 1017 return cmd.val, cmd.err 1018} 1019 1020func (cmd *StringStructMapCmd) String() string { 1021 return cmdString(cmd, cmd.val) 1022} 1023 1024func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error { 1025 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1026 cmd.val = make(map[string]struct{}, n) 1027 for i := int64(0); i < n; i++ { 1028 key, err := rd.ReadString() 1029 if err != nil { 1030 return nil, err 1031 } 1032 cmd.val[key] = struct{}{} 1033 } 1034 return nil, nil 1035 }) 1036 return err 1037} 1038 1039//------------------------------------------------------------------------------ 1040 1041type XMessage struct { 1042 ID string 1043 Values map[string]interface{} 1044} 1045 1046type XMessageSliceCmd struct { 1047 baseCmd 1048 1049 val []XMessage 1050} 1051 1052var _ Cmder = (*XMessageSliceCmd)(nil) 1053 1054func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd { 1055 return &XMessageSliceCmd{ 1056 baseCmd: baseCmd{ 1057 ctx: ctx, 1058 args: args, 1059 }, 1060 } 1061} 1062 1063func (cmd *XMessageSliceCmd) Val() []XMessage { 1064 return cmd.val 1065} 1066 1067func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) { 1068 return cmd.val, cmd.err 1069} 1070 1071func (cmd *XMessageSliceCmd) String() string { 1072 return cmdString(cmd, cmd.val) 1073} 1074 1075func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) error { 1076 var err error 1077 cmd.val, err = readXMessageSlice(rd) 1078 return err 1079} 1080 1081func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) { 1082 n, err := rd.ReadArrayLen() 1083 if err != nil { 1084 return nil, err 1085 } 1086 1087 msgs := make([]XMessage, n) 1088 for i := 0; i < n; i++ { 1089 var err error 1090 msgs[i], err = readXMessage(rd) 1091 if err != nil { 1092 return nil, err 1093 } 1094 } 1095 return msgs, nil 1096} 1097 1098func readXMessage(rd *proto.Reader) (XMessage, error) { 1099 n, err := rd.ReadArrayLen() 1100 if err != nil { 1101 return XMessage{}, err 1102 } 1103 if n != 2 { 1104 return XMessage{}, fmt.Errorf("got %d, wanted 2", n) 1105 } 1106 1107 id, err := rd.ReadString() 1108 if err != nil { 1109 return XMessage{}, err 1110 } 1111 1112 var values map[string]interface{} 1113 1114 v, err := rd.ReadArrayReply(stringInterfaceMapParser) 1115 if err != nil { 1116 if err != proto.Nil { 1117 return XMessage{}, err 1118 } 1119 } else { 1120 values = v.(map[string]interface{}) 1121 } 1122 1123 return XMessage{ 1124 ID: id, 1125 Values: values, 1126 }, nil 1127} 1128 1129// stringInterfaceMapParser implements proto.MultiBulkParse. 1130func stringInterfaceMapParser(rd *proto.Reader, n int64) (interface{}, error) { 1131 m := make(map[string]interface{}, n/2) 1132 for i := int64(0); i < n; i += 2 { 1133 key, err := rd.ReadString() 1134 if err != nil { 1135 return nil, err 1136 } 1137 1138 value, err := rd.ReadString() 1139 if err != nil { 1140 return nil, err 1141 } 1142 1143 m[key] = value 1144 } 1145 return m, nil 1146} 1147 1148//------------------------------------------------------------------------------ 1149 1150type XStream struct { 1151 Stream string 1152 Messages []XMessage 1153} 1154 1155type XStreamSliceCmd struct { 1156 baseCmd 1157 1158 val []XStream 1159} 1160 1161var _ Cmder = (*XStreamSliceCmd)(nil) 1162 1163func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd { 1164 return &XStreamSliceCmd{ 1165 baseCmd: baseCmd{ 1166 ctx: ctx, 1167 args: args, 1168 }, 1169 } 1170} 1171 1172func (cmd *XStreamSliceCmd) Val() []XStream { 1173 return cmd.val 1174} 1175 1176func (cmd *XStreamSliceCmd) Result() ([]XStream, error) { 1177 return cmd.val, cmd.err 1178} 1179 1180func (cmd *XStreamSliceCmd) String() string { 1181 return cmdString(cmd, cmd.val) 1182} 1183 1184func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error { 1185 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1186 cmd.val = make([]XStream, n) 1187 for i := 0; i < len(cmd.val); i++ { 1188 i := i 1189 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1190 if n != 2 { 1191 return nil, fmt.Errorf("got %d, wanted 2", n) 1192 } 1193 1194 stream, err := rd.ReadString() 1195 if err != nil { 1196 return nil, err 1197 } 1198 1199 msgs, err := readXMessageSlice(rd) 1200 if err != nil { 1201 return nil, err 1202 } 1203 1204 cmd.val[i] = XStream{ 1205 Stream: stream, 1206 Messages: msgs, 1207 } 1208 return nil, nil 1209 }) 1210 if err != nil { 1211 return nil, err 1212 } 1213 } 1214 return nil, nil 1215 }) 1216 return err 1217} 1218 1219//------------------------------------------------------------------------------ 1220 1221type XPending struct { 1222 Count int64 1223 Lower string 1224 Higher string 1225 Consumers map[string]int64 1226} 1227 1228type XPendingCmd struct { 1229 baseCmd 1230 val *XPending 1231} 1232 1233var _ Cmder = (*XPendingCmd)(nil) 1234 1235func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd { 1236 return &XPendingCmd{ 1237 baseCmd: baseCmd{ 1238 ctx: ctx, 1239 args: args, 1240 }, 1241 } 1242} 1243 1244func (cmd *XPendingCmd) Val() *XPending { 1245 return cmd.val 1246} 1247 1248func (cmd *XPendingCmd) Result() (*XPending, error) { 1249 return cmd.val, cmd.err 1250} 1251 1252func (cmd *XPendingCmd) String() string { 1253 return cmdString(cmd, cmd.val) 1254} 1255 1256func (cmd *XPendingCmd) readReply(rd *proto.Reader) error { 1257 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1258 if n != 4 { 1259 return nil, fmt.Errorf("got %d, wanted 4", n) 1260 } 1261 1262 count, err := rd.ReadIntReply() 1263 if err != nil { 1264 return nil, err 1265 } 1266 1267 lower, err := rd.ReadString() 1268 if err != nil && err != Nil { 1269 return nil, err 1270 } 1271 1272 higher, err := rd.ReadString() 1273 if err != nil && err != Nil { 1274 return nil, err 1275 } 1276 1277 cmd.val = &XPending{ 1278 Count: count, 1279 Lower: lower, 1280 Higher: higher, 1281 } 1282 _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1283 for i := int64(0); i < n; i++ { 1284 _, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1285 if n != 2 { 1286 return nil, fmt.Errorf("got %d, wanted 2", n) 1287 } 1288 1289 consumerName, err := rd.ReadString() 1290 if err != nil { 1291 return nil, err 1292 } 1293 1294 consumerPending, err := rd.ReadInt() 1295 if err != nil { 1296 return nil, err 1297 } 1298 1299 if cmd.val.Consumers == nil { 1300 cmd.val.Consumers = make(map[string]int64) 1301 } 1302 cmd.val.Consumers[consumerName] = consumerPending 1303 1304 return nil, nil 1305 }) 1306 if err != nil { 1307 return nil, err 1308 } 1309 } 1310 return nil, nil 1311 }) 1312 if err != nil && err != Nil { 1313 return nil, err 1314 } 1315 1316 return nil, nil 1317 }) 1318 return err 1319} 1320 1321//------------------------------------------------------------------------------ 1322 1323type XPendingExt struct { 1324 ID string 1325 Consumer string 1326 Idle time.Duration 1327 RetryCount int64 1328} 1329 1330type XPendingExtCmd struct { 1331 baseCmd 1332 val []XPendingExt 1333} 1334 1335var _ Cmder = (*XPendingExtCmd)(nil) 1336 1337func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd { 1338 return &XPendingExtCmd{ 1339 baseCmd: baseCmd{ 1340 ctx: ctx, 1341 args: args, 1342 }, 1343 } 1344} 1345 1346func (cmd *XPendingExtCmd) Val() []XPendingExt { 1347 return cmd.val 1348} 1349 1350func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) { 1351 return cmd.val, cmd.err 1352} 1353 1354func (cmd *XPendingExtCmd) String() string { 1355 return cmdString(cmd, cmd.val) 1356} 1357 1358func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error { 1359 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1360 cmd.val = make([]XPendingExt, 0, n) 1361 for i := int64(0); i < n; i++ { 1362 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1363 if n != 4 { 1364 return nil, fmt.Errorf("got %d, wanted 4", n) 1365 } 1366 1367 id, err := rd.ReadString() 1368 if err != nil { 1369 return nil, err 1370 } 1371 1372 consumer, err := rd.ReadString() 1373 if err != nil && err != Nil { 1374 return nil, err 1375 } 1376 1377 idle, err := rd.ReadIntReply() 1378 if err != nil && err != Nil { 1379 return nil, err 1380 } 1381 1382 retryCount, err := rd.ReadIntReply() 1383 if err != nil && err != Nil { 1384 return nil, err 1385 } 1386 1387 cmd.val = append(cmd.val, XPendingExt{ 1388 ID: id, 1389 Consumer: consumer, 1390 Idle: time.Duration(idle) * time.Millisecond, 1391 RetryCount: retryCount, 1392 }) 1393 return nil, nil 1394 }) 1395 if err != nil { 1396 return nil, err 1397 } 1398 } 1399 return nil, nil 1400 }) 1401 return err 1402} 1403 1404//------------------------------------------------------------------------------ 1405 1406type XInfoGroupsCmd struct { 1407 baseCmd 1408 val []XInfoGroup 1409} 1410 1411type XInfoGroup struct { 1412 Name string 1413 Consumers int64 1414 Pending int64 1415 LastDeliveredID string 1416} 1417 1418var _ Cmder = (*XInfoGroupsCmd)(nil) 1419 1420func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd { 1421 return &XInfoGroupsCmd{ 1422 baseCmd: baseCmd{ 1423 ctx: ctx, 1424 args: []interface{}{"xinfo", "groups", stream}, 1425 }, 1426 } 1427} 1428 1429func (cmd *XInfoGroupsCmd) Val() []XInfoGroup { 1430 return cmd.val 1431} 1432 1433func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) { 1434 return cmd.val, cmd.err 1435} 1436 1437func (cmd *XInfoGroupsCmd) String() string { 1438 return cmdString(cmd, cmd.val) 1439} 1440 1441func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error { 1442 n, err := rd.ReadArrayLen() 1443 if err != nil { 1444 return err 1445 } 1446 1447 cmd.val = make([]XInfoGroup, n) 1448 1449 for i := 0; i < n; i++ { 1450 cmd.val[i], err = readXGroupInfo(rd) 1451 if err != nil { 1452 return err 1453 } 1454 } 1455 1456 return nil 1457} 1458 1459func readXGroupInfo(rd *proto.Reader) (XInfoGroup, error) { 1460 var group XInfoGroup 1461 1462 n, err := rd.ReadArrayLen() 1463 if err != nil { 1464 return group, err 1465 } 1466 if n != 8 { 1467 return group, fmt.Errorf("redis: got %d elements in XINFO GROUPS reply, wanted 8", n) 1468 } 1469 1470 for i := 0; i < 4; i++ { 1471 key, err := rd.ReadString() 1472 if err != nil { 1473 return group, err 1474 } 1475 1476 val, err := rd.ReadString() 1477 if err != nil { 1478 return group, err 1479 } 1480 1481 switch key { 1482 case "name": 1483 group.Name = val 1484 case "consumers": 1485 group.Consumers, err = strconv.ParseInt(val, 0, 64) 1486 if err != nil { 1487 return group, err 1488 } 1489 case "pending": 1490 group.Pending, err = strconv.ParseInt(val, 0, 64) 1491 if err != nil { 1492 return group, err 1493 } 1494 case "last-delivered-id": 1495 group.LastDeliveredID = val 1496 default: 1497 return group, fmt.Errorf("redis: unexpected content %s in XINFO GROUPS reply", key) 1498 } 1499 } 1500 1501 return group, nil 1502} 1503 1504//------------------------------------------------------------------------------ 1505 1506type XInfoStreamCmd struct { 1507 baseCmd 1508 val *XInfoStream 1509} 1510 1511type XInfoStream struct { 1512 Length int64 1513 RadixTreeKeys int64 1514 RadixTreeNodes int64 1515 Groups int64 1516 LastGeneratedID string 1517 FirstEntry XMessage 1518 LastEntry XMessage 1519} 1520 1521var _ Cmder = (*XInfoStreamCmd)(nil) 1522 1523func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd { 1524 return &XInfoStreamCmd{ 1525 baseCmd: baseCmd{ 1526 ctx: ctx, 1527 args: []interface{}{"xinfo", "stream", stream}, 1528 }, 1529 } 1530} 1531 1532func (cmd *XInfoStreamCmd) Val() *XInfoStream { 1533 return cmd.val 1534} 1535 1536func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) { 1537 return cmd.val, cmd.err 1538} 1539 1540func (cmd *XInfoStreamCmd) String() string { 1541 return cmdString(cmd, cmd.val) 1542} 1543 1544func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error { 1545 v, err := rd.ReadReply(xStreamInfoParser) 1546 if err != nil { 1547 return err 1548 } 1549 cmd.val = v.(*XInfoStream) 1550 return nil 1551} 1552 1553func xStreamInfoParser(rd *proto.Reader, n int64) (interface{}, error) { 1554 if n != 14 { 1555 return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+ 1556 "wanted 14", n) 1557 } 1558 var info XInfoStream 1559 for i := 0; i < 7; i++ { 1560 key, err := rd.ReadString() 1561 if err != nil { 1562 return nil, err 1563 } 1564 switch key { 1565 case "length": 1566 info.Length, err = rd.ReadIntReply() 1567 case "radix-tree-keys": 1568 info.RadixTreeKeys, err = rd.ReadIntReply() 1569 case "radix-tree-nodes": 1570 info.RadixTreeNodes, err = rd.ReadIntReply() 1571 case "groups": 1572 info.Groups, err = rd.ReadIntReply() 1573 case "last-generated-id": 1574 info.LastGeneratedID, err = rd.ReadString() 1575 case "first-entry": 1576 info.FirstEntry, err = readXMessage(rd) 1577 case "last-entry": 1578 info.LastEntry, err = readXMessage(rd) 1579 default: 1580 return nil, fmt.Errorf("redis: unexpected content %s "+ 1581 "in XINFO STREAM reply", key) 1582 } 1583 if err != nil { 1584 return nil, err 1585 } 1586 } 1587 return &info, nil 1588} 1589 1590//------------------------------------------------------------------------------ 1591 1592type ZSliceCmd struct { 1593 baseCmd 1594 1595 val []Z 1596} 1597 1598var _ Cmder = (*ZSliceCmd)(nil) 1599 1600func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd { 1601 return &ZSliceCmd{ 1602 baseCmd: baseCmd{ 1603 ctx: ctx, 1604 args: args, 1605 }, 1606 } 1607} 1608 1609func (cmd *ZSliceCmd) Val() []Z { 1610 return cmd.val 1611} 1612 1613func (cmd *ZSliceCmd) Result() ([]Z, error) { 1614 return cmd.val, cmd.err 1615} 1616 1617func (cmd *ZSliceCmd) String() string { 1618 return cmdString(cmd, cmd.val) 1619} 1620 1621func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error { 1622 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1623 cmd.val = make([]Z, n/2) 1624 for i := 0; i < len(cmd.val); i++ { 1625 member, err := rd.ReadString() 1626 if err != nil { 1627 return nil, err 1628 } 1629 1630 score, err := rd.ReadFloatReply() 1631 if err != nil { 1632 return nil, err 1633 } 1634 1635 cmd.val[i] = Z{ 1636 Member: member, 1637 Score: score, 1638 } 1639 } 1640 return nil, nil 1641 }) 1642 return err 1643} 1644 1645//------------------------------------------------------------------------------ 1646 1647type ZWithKeyCmd struct { 1648 baseCmd 1649 1650 val *ZWithKey 1651} 1652 1653var _ Cmder = (*ZWithKeyCmd)(nil) 1654 1655func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd { 1656 return &ZWithKeyCmd{ 1657 baseCmd: baseCmd{ 1658 ctx: ctx, 1659 args: args, 1660 }, 1661 } 1662} 1663 1664func (cmd *ZWithKeyCmd) Val() *ZWithKey { 1665 return cmd.val 1666} 1667 1668func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) { 1669 return cmd.Val(), cmd.Err() 1670} 1671 1672func (cmd *ZWithKeyCmd) String() string { 1673 return cmdString(cmd, cmd.val) 1674} 1675 1676func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) error { 1677 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1678 if n != 3 { 1679 return nil, fmt.Errorf("got %d elements, expected 3", n) 1680 } 1681 1682 cmd.val = &ZWithKey{} 1683 var err error 1684 1685 cmd.val.Key, err = rd.ReadString() 1686 if err != nil { 1687 return nil, err 1688 } 1689 1690 cmd.val.Member, err = rd.ReadString() 1691 if err != nil { 1692 return nil, err 1693 } 1694 1695 cmd.val.Score, err = rd.ReadFloatReply() 1696 if err != nil { 1697 return nil, err 1698 } 1699 1700 return nil, nil 1701 }) 1702 return err 1703} 1704 1705//------------------------------------------------------------------------------ 1706 1707type ScanCmd struct { 1708 baseCmd 1709 1710 page []string 1711 cursor uint64 1712 1713 process cmdable 1714} 1715 1716var _ Cmder = (*ScanCmd)(nil) 1717 1718func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd { 1719 return &ScanCmd{ 1720 baseCmd: baseCmd{ 1721 ctx: ctx, 1722 args: args, 1723 }, 1724 process: process, 1725 } 1726} 1727 1728func (cmd *ScanCmd) Val() (keys []string, cursor uint64) { 1729 return cmd.page, cmd.cursor 1730} 1731 1732func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) { 1733 return cmd.page, cmd.cursor, cmd.err 1734} 1735 1736func (cmd *ScanCmd) String() string { 1737 return cmdString(cmd, cmd.page) 1738} 1739 1740func (cmd *ScanCmd) readReply(rd *proto.Reader) (err error) { 1741 cmd.page, cmd.cursor, err = rd.ReadScanReply() 1742 return err 1743} 1744 1745// Iterator creates a new ScanIterator. 1746func (cmd *ScanCmd) Iterator() *ScanIterator { 1747 return &ScanIterator{ 1748 cmd: cmd, 1749 } 1750} 1751 1752//------------------------------------------------------------------------------ 1753 1754type ClusterNode struct { 1755 ID string 1756 Addr string 1757} 1758 1759type ClusterSlot struct { 1760 Start int 1761 End int 1762 Nodes []ClusterNode 1763} 1764 1765type ClusterSlotsCmd struct { 1766 baseCmd 1767 1768 val []ClusterSlot 1769} 1770 1771var _ Cmder = (*ClusterSlotsCmd)(nil) 1772 1773func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd { 1774 return &ClusterSlotsCmd{ 1775 baseCmd: baseCmd{ 1776 ctx: ctx, 1777 args: args, 1778 }, 1779 } 1780} 1781 1782func (cmd *ClusterSlotsCmd) Val() []ClusterSlot { 1783 return cmd.val 1784} 1785 1786func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) { 1787 return cmd.Val(), cmd.Err() 1788} 1789 1790func (cmd *ClusterSlotsCmd) String() string { 1791 return cmdString(cmd, cmd.val) 1792} 1793 1794func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error { 1795 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 1796 cmd.val = make([]ClusterSlot, n) 1797 for i := 0; i < len(cmd.val); i++ { 1798 n, err := rd.ReadArrayLen() 1799 if err != nil { 1800 return nil, err 1801 } 1802 if n < 2 { 1803 err := fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n) 1804 return nil, err 1805 } 1806 1807 start, err := rd.ReadIntReply() 1808 if err != nil { 1809 return nil, err 1810 } 1811 1812 end, err := rd.ReadIntReply() 1813 if err != nil { 1814 return nil, err 1815 } 1816 1817 nodes := make([]ClusterNode, n-2) 1818 for j := 0; j < len(nodes); j++ { 1819 n, err := rd.ReadArrayLen() 1820 if err != nil { 1821 return nil, err 1822 } 1823 if n != 2 && n != 3 { 1824 err := fmt.Errorf("got %d elements in cluster info address, expected 2 or 3", n) 1825 return nil, err 1826 } 1827 1828 ip, err := rd.ReadString() 1829 if err != nil { 1830 return nil, err 1831 } 1832 1833 port, err := rd.ReadString() 1834 if err != nil { 1835 return nil, err 1836 } 1837 1838 nodes[j].Addr = net.JoinHostPort(ip, port) 1839 1840 if n == 3 { 1841 id, err := rd.ReadString() 1842 if err != nil { 1843 return nil, err 1844 } 1845 nodes[j].ID = id 1846 } 1847 } 1848 1849 cmd.val[i] = ClusterSlot{ 1850 Start: int(start), 1851 End: int(end), 1852 Nodes: nodes, 1853 } 1854 } 1855 return nil, nil 1856 }) 1857 return err 1858} 1859 1860//------------------------------------------------------------------------------ 1861 1862// GeoLocation is used with GeoAdd to add geospatial location. 1863type GeoLocation struct { 1864 Name string 1865 Longitude, Latitude, Dist float64 1866 GeoHash int64 1867} 1868 1869// GeoRadiusQuery is used with GeoRadius to query geospatial index. 1870type GeoRadiusQuery struct { 1871 Radius float64 1872 // Can be m, km, ft, or mi. Default is km. 1873 Unit string 1874 WithCoord bool 1875 WithDist bool 1876 WithGeoHash bool 1877 Count int 1878 // Can be ASC or DESC. Default is no sort order. 1879 Sort string 1880 Store string 1881 StoreDist string 1882} 1883 1884type GeoLocationCmd struct { 1885 baseCmd 1886 1887 q *GeoRadiusQuery 1888 locations []GeoLocation 1889} 1890 1891var _ Cmder = (*GeoLocationCmd)(nil) 1892 1893func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd { 1894 return &GeoLocationCmd{ 1895 baseCmd: baseCmd{ 1896 ctx: ctx, 1897 args: geoLocationArgs(q, args...), 1898 }, 1899 q: q, 1900 } 1901} 1902 1903func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} { 1904 args = append(args, q.Radius) 1905 if q.Unit != "" { 1906 args = append(args, q.Unit) 1907 } else { 1908 args = append(args, "km") 1909 } 1910 if q.WithCoord { 1911 args = append(args, "withcoord") 1912 } 1913 if q.WithDist { 1914 args = append(args, "withdist") 1915 } 1916 if q.WithGeoHash { 1917 args = append(args, "withhash") 1918 } 1919 if q.Count > 0 { 1920 args = append(args, "count", q.Count) 1921 } 1922 if q.Sort != "" { 1923 args = append(args, q.Sort) 1924 } 1925 if q.Store != "" { 1926 args = append(args, "store") 1927 args = append(args, q.Store) 1928 } 1929 if q.StoreDist != "" { 1930 args = append(args, "storedist") 1931 args = append(args, q.StoreDist) 1932 } 1933 return args 1934} 1935 1936func (cmd *GeoLocationCmd) Val() []GeoLocation { 1937 return cmd.locations 1938} 1939 1940func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) { 1941 return cmd.locations, cmd.err 1942} 1943 1944func (cmd *GeoLocationCmd) String() string { 1945 return cmdString(cmd, cmd.locations) 1946} 1947 1948func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error { 1949 v, err := rd.ReadArrayReply(newGeoLocationSliceParser(cmd.q)) 1950 if err != nil { 1951 return err 1952 } 1953 cmd.locations = v.([]GeoLocation) 1954 return nil 1955} 1956 1957func newGeoLocationSliceParser(q *GeoRadiusQuery) proto.MultiBulkParse { 1958 return func(rd *proto.Reader, n int64) (interface{}, error) { 1959 locs := make([]GeoLocation, 0, n) 1960 for i := int64(0); i < n; i++ { 1961 v, err := rd.ReadReply(newGeoLocationParser(q)) 1962 if err != nil { 1963 return nil, err 1964 } 1965 switch vv := v.(type) { 1966 case string: 1967 locs = append(locs, GeoLocation{ 1968 Name: vv, 1969 }) 1970 case *GeoLocation: 1971 // TODO: avoid copying 1972 locs = append(locs, *vv) 1973 default: 1974 return nil, fmt.Errorf("got %T, expected string or *GeoLocation", v) 1975 } 1976 } 1977 return locs, nil 1978 } 1979} 1980 1981func newGeoLocationParser(q *GeoRadiusQuery) proto.MultiBulkParse { 1982 return func(rd *proto.Reader, n int64) (interface{}, error) { 1983 var loc GeoLocation 1984 var err error 1985 1986 loc.Name, err = rd.ReadString() 1987 if err != nil { 1988 return nil, err 1989 } 1990 if q.WithDist { 1991 loc.Dist, err = rd.ReadFloatReply() 1992 if err != nil { 1993 return nil, err 1994 } 1995 } 1996 if q.WithGeoHash { 1997 loc.GeoHash, err = rd.ReadIntReply() 1998 if err != nil { 1999 return nil, err 2000 } 2001 } 2002 if q.WithCoord { 2003 n, err := rd.ReadArrayLen() 2004 if err != nil { 2005 return nil, err 2006 } 2007 if n != 2 { 2008 return nil, fmt.Errorf("got %d coordinates, expected 2", n) 2009 } 2010 2011 loc.Longitude, err = rd.ReadFloatReply() 2012 if err != nil { 2013 return nil, err 2014 } 2015 loc.Latitude, err = rd.ReadFloatReply() 2016 if err != nil { 2017 return nil, err 2018 } 2019 } 2020 2021 return &loc, nil 2022 } 2023} 2024 2025//------------------------------------------------------------------------------ 2026 2027type GeoPos struct { 2028 Longitude, Latitude float64 2029} 2030 2031type GeoPosCmd struct { 2032 baseCmd 2033 2034 val []*GeoPos 2035} 2036 2037var _ Cmder = (*GeoPosCmd)(nil) 2038 2039func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd { 2040 return &GeoPosCmd{ 2041 baseCmd: baseCmd{ 2042 ctx: ctx, 2043 args: args, 2044 }, 2045 } 2046} 2047 2048func (cmd *GeoPosCmd) Val() []*GeoPos { 2049 return cmd.val 2050} 2051 2052func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) { 2053 return cmd.Val(), cmd.Err() 2054} 2055 2056func (cmd *GeoPosCmd) String() string { 2057 return cmdString(cmd, cmd.val) 2058} 2059 2060func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error { 2061 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 2062 cmd.val = make([]*GeoPos, n) 2063 for i := 0; i < len(cmd.val); i++ { 2064 i := i 2065 _, err := rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) { 2066 longitude, err := rd.ReadFloatReply() 2067 if err != nil { 2068 return nil, err 2069 } 2070 2071 latitude, err := rd.ReadFloatReply() 2072 if err != nil { 2073 return nil, err 2074 } 2075 2076 cmd.val[i] = &GeoPos{ 2077 Longitude: longitude, 2078 Latitude: latitude, 2079 } 2080 return nil, nil 2081 }) 2082 if err != nil { 2083 if err == Nil { 2084 cmd.val[i] = nil 2085 continue 2086 } 2087 return nil, err 2088 } 2089 } 2090 return nil, nil 2091 }) 2092 return err 2093} 2094 2095//------------------------------------------------------------------------------ 2096 2097type CommandInfo struct { 2098 Name string 2099 Arity int8 2100 Flags []string 2101 ACLFlags []string 2102 FirstKeyPos int8 2103 LastKeyPos int8 2104 StepCount int8 2105 ReadOnly bool 2106} 2107 2108type CommandsInfoCmd struct { 2109 baseCmd 2110 2111 val map[string]*CommandInfo 2112} 2113 2114var _ Cmder = (*CommandsInfoCmd)(nil) 2115 2116func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd { 2117 return &CommandsInfoCmd{ 2118 baseCmd: baseCmd{ 2119 ctx: ctx, 2120 args: args, 2121 }, 2122 } 2123} 2124 2125func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo { 2126 return cmd.val 2127} 2128 2129func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) { 2130 return cmd.Val(), cmd.Err() 2131} 2132 2133func (cmd *CommandsInfoCmd) String() string { 2134 return cmdString(cmd, cmd.val) 2135} 2136 2137func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error { 2138 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 2139 cmd.val = make(map[string]*CommandInfo, n) 2140 for i := int64(0); i < n; i++ { 2141 v, err := rd.ReadReply(commandInfoParser) 2142 if err != nil { 2143 return nil, err 2144 } 2145 vv := v.(*CommandInfo) 2146 cmd.val[vv.Name] = vv 2147 } 2148 return nil, nil 2149 }) 2150 return err 2151} 2152 2153func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) { 2154 const numArgRedis5 = 6 2155 const numArgRedis6 = 7 2156 2157 switch n { 2158 case numArgRedis5, numArgRedis6: 2159 // continue 2160 default: 2161 return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 7", n) 2162 } 2163 2164 var cmd CommandInfo 2165 var err error 2166 2167 cmd.Name, err = rd.ReadString() 2168 if err != nil { 2169 return nil, err 2170 } 2171 2172 arity, err := rd.ReadIntReply() 2173 if err != nil { 2174 return nil, err 2175 } 2176 cmd.Arity = int8(arity) 2177 2178 _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) { 2179 cmd.Flags = make([]string, n) 2180 for i := 0; i < len(cmd.Flags); i++ { 2181 switch s, err := rd.ReadString(); { 2182 case err == Nil: 2183 cmd.Flags[i] = "" 2184 case err != nil: 2185 return nil, err 2186 default: 2187 cmd.Flags[i] = s 2188 } 2189 } 2190 return nil, nil 2191 }) 2192 if err != nil { 2193 return nil, err 2194 } 2195 2196 firstKeyPos, err := rd.ReadIntReply() 2197 if err != nil { 2198 return nil, err 2199 } 2200 cmd.FirstKeyPos = int8(firstKeyPos) 2201 2202 lastKeyPos, err := rd.ReadIntReply() 2203 if err != nil { 2204 return nil, err 2205 } 2206 cmd.LastKeyPos = int8(lastKeyPos) 2207 2208 stepCount, err := rd.ReadIntReply() 2209 if err != nil { 2210 return nil, err 2211 } 2212 cmd.StepCount = int8(stepCount) 2213 2214 for _, flag := range cmd.Flags { 2215 if flag == "readonly" { 2216 cmd.ReadOnly = true 2217 break 2218 } 2219 } 2220 2221 if n == numArgRedis5 { 2222 return &cmd, nil 2223 } 2224 2225 _, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) { 2226 cmd.ACLFlags = make([]string, n) 2227 for i := 0; i < len(cmd.ACLFlags); i++ { 2228 switch s, err := rd.ReadString(); { 2229 case err == Nil: 2230 cmd.ACLFlags[i] = "" 2231 case err != nil: 2232 return nil, err 2233 default: 2234 cmd.ACLFlags[i] = s 2235 } 2236 } 2237 return nil, nil 2238 }) 2239 if err != nil { 2240 return nil, err 2241 } 2242 2243 return &cmd, nil 2244} 2245 2246//------------------------------------------------------------------------------ 2247 2248type cmdsInfoCache struct { 2249 fn func(ctx context.Context) (map[string]*CommandInfo, error) 2250 2251 once internal.Once 2252 cmds map[string]*CommandInfo 2253} 2254 2255func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache { 2256 return &cmdsInfoCache{ 2257 fn: fn, 2258 } 2259} 2260 2261func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) { 2262 err := c.once.Do(func() error { 2263 cmds, err := c.fn(ctx) 2264 if err != nil { 2265 return err 2266 } 2267 2268 // Extensions have cmd names in upper case. Convert them to lower case. 2269 for k, v := range cmds { 2270 lower := internal.ToLower(k) 2271 if lower != k { 2272 cmds[lower] = v 2273 } 2274 } 2275 2276 c.cmds = cmds 2277 return nil 2278 }) 2279 return c.cmds, err 2280} 2281 2282//------------------------------------------------------------------------------ 2283 2284type SlowLog struct { 2285 ID int64 2286 Time time.Time 2287 Duration time.Duration 2288 Args []string 2289 // These are also optional fields emitted only by Redis 4.0 or greater: 2290 // https://redis.io/commands/slowlog#output-format 2291 ClientAddr string 2292 ClientName string 2293} 2294 2295type SlowLogCmd struct { 2296 baseCmd 2297 2298 val []SlowLog 2299} 2300 2301var _ Cmder = (*SlowLogCmd)(nil) 2302 2303func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd { 2304 return &SlowLogCmd{ 2305 baseCmd: baseCmd{ 2306 ctx: ctx, 2307 args: args, 2308 }, 2309 } 2310} 2311 2312func (cmd *SlowLogCmd) Val() []SlowLog { 2313 return cmd.val 2314} 2315 2316func (cmd *SlowLogCmd) Result() ([]SlowLog, error) { 2317 return cmd.Val(), cmd.Err() 2318} 2319 2320func (cmd *SlowLogCmd) String() string { 2321 return cmdString(cmd, cmd.val) 2322} 2323 2324func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error { 2325 _, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) { 2326 cmd.val = make([]SlowLog, n) 2327 for i := 0; i < len(cmd.val); i++ { 2328 n, err := rd.ReadArrayLen() 2329 if err != nil { 2330 return nil, err 2331 } 2332 if n < 4 { 2333 err := fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", n) 2334 return nil, err 2335 } 2336 2337 id, err := rd.ReadIntReply() 2338 if err != nil { 2339 return nil, err 2340 } 2341 2342 createdAt, err := rd.ReadIntReply() 2343 if err != nil { 2344 return nil, err 2345 } 2346 createdAtTime := time.Unix(createdAt, 0) 2347 2348 costs, err := rd.ReadIntReply() 2349 if err != nil { 2350 return nil, err 2351 } 2352 costsDuration := time.Duration(costs) * time.Microsecond 2353 2354 cmdLen, err := rd.ReadArrayLen() 2355 if err != nil { 2356 return nil, err 2357 } 2358 if cmdLen < 1 { 2359 err := fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen) 2360 return nil, err 2361 } 2362 2363 cmdString := make([]string, cmdLen) 2364 for i := 0; i < cmdLen; i++ { 2365 cmdString[i], err = rd.ReadString() 2366 if err != nil { 2367 return nil, err 2368 } 2369 } 2370 2371 var address, name string 2372 for i := 4; i < n; i++ { 2373 str, err := rd.ReadString() 2374 if err != nil { 2375 return nil, err 2376 } 2377 if i == 4 { 2378 address = str 2379 } else if i == 5 { 2380 name = str 2381 } 2382 } 2383 2384 cmd.val[i] = SlowLog{ 2385 ID: id, 2386 Time: createdAtTime, 2387 Duration: costsDuration, 2388 Args: cmdString, 2389 ClientAddr: address, 2390 ClientName: name, 2391 } 2392 } 2393 return nil, nil 2394 }) 2395 return err 2396} 2397