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

974 lines
12 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
package proto
import (
"bufio"
"errors"
"fmt"
"io"
"math"
"math/big"
"strconv"
"github.com/redis/go-redis/v9/internal/util"
)
// redis resp protocol data type.
2024-02-18 10:42:21 +00:00
const (
RespStatus = '+' // +<string>\r\n
RespError = '-' // -<string>\r\n
RespString = '$' // $<length>\r\n<bytes>\r\n
RespInt = ':' // :<number>\r\n
RespNil = '_' // _\r\n
RespFloat = ',' // ,<floating-point-number>\r\n (golang float)
RespBool = '#' // true: #t\r\n false: #f\r\n
2024-02-18 10:42:21 +00:00
RespBlobError = '!' // !<length>\r\n<bytes>\r\n
RespVerbatim = '=' // =<length>\r\nFORMAT:<bytes>\r\n
RespBigInt = '(' // (<big number>\r\n
RespArray = '*' // *<len>\r\n... (same as resp2)
RespMap = '%' // %<len>\r\n(key)\r\n(value)\r\n... (golang map)
RespSet = '~' // ~<len>\r\n... (same as Array)
RespAttr = '|' // |<len>\r\n(key)\r\n(value)\r\n... + command reply
RespPush = '>' // ><len>\r\n... (same as Array)
2024-02-18 10:42:21 +00:00
)
// Not used temporarily.
2024-02-18 10:42:21 +00:00
// Redis has not used these two data types for the time being, and will implement them later.
2024-02-18 10:42:21 +00:00
// Streamed = "EOF:"
2024-02-18 10:42:21 +00:00
// StreamedAggregated = '?'
//------------------------------------------------------------------------------
const Nil = RedisError("redis: nil") // nolint:errname
type RedisError string
func (e RedisError) Error() string { return string(e) }
func (RedisError) RedisError() {}
func ParseErrorReply(line []byte) error {
2024-02-18 10:42:21 +00:00
return RedisError(line[1:])
2024-02-18 10:42:21 +00:00
}
//------------------------------------------------------------------------------
type Reader struct {
rd *bufio.Reader
}
func NewReader(rd io.Reader) *Reader {
2024-02-18 10:42:21 +00:00
return &Reader{
2024-02-18 10:42:21 +00:00
rd: bufio.NewReader(rd),
}
2024-02-18 10:42:21 +00:00
}
func (r *Reader) Buffered() int {
2024-02-18 10:42:21 +00:00
return r.rd.Buffered()
2024-02-18 10:42:21 +00:00
}
func (r *Reader) Peek(n int) ([]byte, error) {
2024-02-18 10:42:21 +00:00
return r.rd.Peek(n)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) Reset(rd io.Reader) {
2024-02-18 10:42:21 +00:00
r.rd.Reset(rd)
2024-02-18 10:42:21 +00:00
}
// PeekReplyType returns the data type of the next response without advancing the Reader,
2024-02-18 10:42:21 +00:00
// and discard the attribute type.
2024-02-18 10:42:21 +00:00
func (r *Reader) PeekReplyType() (byte, error) {
2024-02-18 10:42:21 +00:00
b, err := r.rd.Peek(1)
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
if b[0] == RespAttr {
2024-02-18 10:42:21 +00:00
if err = r.DiscardNext(); 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 r.PeekReplyType()
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return b[0], nil
2024-02-18 10:42:21 +00:00
}
// ReadLine Return a valid reply, it will check the protocol or redis error,
2024-02-18 10:42:21 +00:00
// and discard the attribute type.
2024-02-18 10:42:21 +00:00
func (r *Reader) ReadLine() ([]byte, error) {
2024-02-18 10:42:21 +00:00
line, err := r.readLine()
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
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespError:
2024-02-18 10:42:21 +00:00
return nil, ParseErrorReply(line)
2024-02-18 10:42:21 +00:00
case RespNil:
2024-02-18 10:42:21 +00:00
return nil, Nil
2024-02-18 10:42:21 +00:00
case RespBlobError:
2024-02-18 10:42:21 +00:00
var blobErr string
2024-02-18 10:42:21 +00:00
blobErr, err = r.readStringReply(line)
2024-02-18 10:42:21 +00:00
if err == nil {
2024-02-18 10:42:21 +00:00
err = RedisError(blobErr)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
case RespAttr:
2024-02-18 10:42:21 +00:00
if err = r.Discard(line); 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 r.ReadLine()
2024-02-18 10:42:21 +00:00
}
// Compatible with RESP2
2024-02-18 10:42:21 +00:00
if IsNilReply(line) {
2024-02-18 10:42:21 +00:00
return nil, Nil
2024-02-18 10:42:21 +00:00
}
return line, nil
2024-02-18 10:42:21 +00:00
}
// readLine returns an error if:
2024-02-18 10:42:21 +00:00
// - there is a pending read error;
2024-02-18 10:42:21 +00:00
// - or line does not end with \r\n.
2024-02-18 10:42:21 +00:00
func (r *Reader) readLine() ([]byte, error) {
2024-02-18 10:42:21 +00:00
b, err := r.rd.ReadSlice('\n')
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
if err != bufio.ErrBufferFull {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
full := make([]byte, len(b))
2024-02-18 10:42:21 +00:00
copy(full, b)
b, err = r.rd.ReadBytes('\n')
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
}
full = append(full, b...) //nolint:makezero
2024-02-18 10:42:21 +00:00
b = full
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' {
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: invalid reply: %q", b)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return b[:len(b)-2], nil
2024-02-18 10:42:21 +00:00
}
func (r *Reader) ReadReply() (interface{}, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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 line[0] {
2024-02-18 10:42:21 +00:00
case RespStatus:
2024-02-18 10:42:21 +00:00
return string(line[1:]), nil
2024-02-18 10:42:21 +00:00
case RespInt:
2024-02-18 10:42:21 +00:00
return util.ParseInt(line[1:], 10, 64)
2024-02-18 10:42:21 +00:00
case RespFloat:
2024-02-18 10:42:21 +00:00
return r.readFloat(line)
2024-02-18 10:42:21 +00:00
case RespBool:
2024-02-18 10:42:21 +00:00
return r.readBool(line)
2024-02-18 10:42:21 +00:00
case RespBigInt:
2024-02-18 10:42:21 +00:00
return r.readBigInt(line)
case RespString:
2024-02-18 10:42:21 +00:00
return r.readStringReply(line)
2024-02-18 10:42:21 +00:00
case RespVerbatim:
2024-02-18 10:42:21 +00:00
return r.readVerb(line)
case RespArray, RespSet, RespPush:
2024-02-18 10:42:21 +00:00
return r.readSlice(line)
2024-02-18 10:42:21 +00:00
case RespMap:
2024-02-18 10:42:21 +00:00
return r.readMap(line)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: can't parse %.100q", line)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) readFloat(line []byte) (float64, error) {
2024-02-18 10:42:21 +00:00
v := string(line[1:])
2024-02-18 10:42:21 +00:00
switch string(line[1:]) {
2024-02-18 10:42:21 +00:00
case "inf":
2024-02-18 10:42:21 +00:00
return math.Inf(1), nil
2024-02-18 10:42:21 +00:00
case "-inf":
2024-02-18 10:42:21 +00:00
return math.Inf(-1), nil
2024-02-18 10:42:21 +00:00
case "nan", "-nan":
2024-02-18 10:42:21 +00:00
return math.NaN(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return strconv.ParseFloat(v, 64)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) readBool(line []byte) (bool, error) {
2024-02-18 10:42:21 +00:00
switch string(line[1:]) {
2024-02-18 10:42:21 +00:00
case "t":
2024-02-18 10:42:21 +00:00
return true, nil
2024-02-18 10:42:21 +00:00
case "f":
2024-02-18 10:42:21 +00:00
return false, nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return false, fmt.Errorf("redis: can't parse bool reply: %q", line)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) readBigInt(line []byte) (*big.Int, error) {
2024-02-18 10:42:21 +00:00
i := new(big.Int)
2024-02-18 10:42:21 +00:00
if i, ok := i.SetString(string(line[1:]), 10); ok {
2024-02-18 10:42:21 +00:00
return i, nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil, fmt.Errorf("redis: can't parse bigInt reply: %q", line)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) readStringReply(line []byte) (string, error) {
2024-02-18 10:42:21 +00:00
n, err := replyLen(line)
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
}
b := make([]byte, n+2)
2024-02-18 10:42:21 +00:00
_, err = io.ReadFull(r.rd, b)
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
}
return util.BytesToString(b[:n]), nil
2024-02-18 10:42:21 +00:00
}
func (r *Reader) readVerb(line []byte) (string, error) {
2024-02-18 10:42:21 +00:00
s, err := r.readStringReply(line)
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 len(s) < 4 || s[3] != ':' {
2024-02-18 10:42:21 +00:00
return "", fmt.Errorf("redis: can't parse verbatim string reply: %q", line)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return s[4:], nil
2024-02-18 10:42:21 +00:00
}
func (r *Reader) readSlice(line []byte) ([]interface{}, error) {
2024-02-18 10:42:21 +00:00
n, err := replyLen(line)
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
}
val := make([]interface{}, n)
2024-02-18 10:42:21 +00:00
for i := 0; i < len(val); i++ {
2024-02-18 10:42:21 +00:00
v, err := r.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
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
if err, ok := err.(RedisError); ok {
2024-02-18 10:42:21 +00:00
val[i] = 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 nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
val[i] = v
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return val, nil
2024-02-18 10:42:21 +00:00
}
func (r *Reader) readMap(line []byte) (map[interface{}]interface{}, error) {
2024-02-18 10:42:21 +00:00
n, err := replyLen(line)
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
m := make(map[interface{}]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 := r.ReadReply()
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
v, err := r.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
m[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.(RedisError); ok {
2024-02-18 10:42:21 +00:00
m[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 nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
m[k] = v
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
}
// -------------------------------
func (r *Reader) ReadInt() (int64, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespInt, RespStatus:
2024-02-18 10:42:21 +00:00
return util.ParseInt(line[1:], 10, 64)
2024-02-18 10:42:21 +00:00
case RespString:
2024-02-18 10:42:21 +00:00
s, err := r.readStringReply(line)
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 util.ParseInt([]byte(s), 10, 64)
2024-02-18 10:42:21 +00:00
case RespBigInt:
2024-02-18 10:42:21 +00:00
b, err := r.readBigInt(line)
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
if !b.IsInt64() {
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("bigInt(%s) value out of range", b.String())
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return b.Int64(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("redis: can't parse int reply: %.100q", line)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) ReadUint() (uint64, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespInt, RespStatus:
2024-02-18 10:42:21 +00:00
return util.ParseUint(line[1:], 10, 64)
2024-02-18 10:42:21 +00:00
case RespString:
2024-02-18 10:42:21 +00:00
s, err := r.readStringReply(line)
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 util.ParseUint([]byte(s), 10, 64)
2024-02-18 10:42:21 +00:00
case RespBigInt:
2024-02-18 10:42:21 +00:00
b, err := r.readBigInt(line)
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
if !b.IsUint64() {
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("bigInt(%s) value out of range", b.String())
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return b.Uint64(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("redis: can't parse uint reply: %.100q", line)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) ReadFloat() (float64, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespFloat:
2024-02-18 10:42:21 +00:00
return r.readFloat(line)
2024-02-18 10:42:21 +00:00
case RespStatus:
2024-02-18 10:42:21 +00:00
return strconv.ParseFloat(string(line[1:]), 64)
2024-02-18 10:42:21 +00:00
case RespString:
2024-02-18 10:42:21 +00:00
s, err := r.readStringReply(line)
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 strconv.ParseFloat(s, 64)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("redis: can't parse float reply: %.100q", line)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) ReadString() (string, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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 line[0] {
2024-02-18 10:42:21 +00:00
case RespStatus, RespInt, RespFloat:
2024-02-18 10:42:21 +00:00
return string(line[1:]), nil
2024-02-18 10:42:21 +00:00
case RespString:
2024-02-18 10:42:21 +00:00
return r.readStringReply(line)
2024-02-18 10:42:21 +00:00
case RespBool:
2024-02-18 10:42:21 +00:00
b, err := r.readBool(line)
2024-02-18 10:42:21 +00:00
return strconv.FormatBool(b), err
2024-02-18 10:42:21 +00:00
case RespVerbatim:
2024-02-18 10:42:21 +00:00
return r.readVerb(line)
2024-02-18 10:42:21 +00:00
case RespBigInt:
2024-02-18 10:42:21 +00:00
b, err := r.readBigInt(line)
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 b.String(), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
2024-02-18 10:42:21 +00:00
}
func (r *Reader) ReadBool() (bool, error) {
2024-02-18 10:42:21 +00:00
s, err := r.ReadString()
2024-02-18 10:42:21 +00:00
if err != nil {
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
return s == "OK" || s == "1" || s == "true", nil
2024-02-18 10:42:21 +00:00
}
func (r *Reader) ReadSlice() ([]interface{}, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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 r.readSlice(line)
2024-02-18 10:42:21 +00:00
}
// ReadFixedArrayLen read fixed array length.
2024-02-18 10:42:21 +00:00
func (r *Reader) ReadFixedArrayLen(fixedLen int) error {
2024-02-18 10:42:21 +00:00
n, err := r.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 != fixedLen {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements in the array, wanted %d", n, fixedLen)
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
}
// ReadArrayLen Read and return the length of the array.
2024-02-18 10:42:21 +00:00
func (r *Reader) ReadArrayLen() (int, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespArray, RespSet, RespPush:
2024-02-18 10:42:21 +00:00
return replyLen(line)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("redis: can't parse array/set/push reply: %.100q", line)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
// ReadFixedMapLen reads fixed map length.
2024-02-18 10:42:21 +00:00
func (r *Reader) ReadFixedMapLen(fixedLen int) error {
2024-02-18 10:42:21 +00:00
n, err := r.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
if n != fixedLen {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis: got %d elements in the map, wanted %d", n, fixedLen)
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
}
// ReadMapLen reads the length of the map type.
2024-02-18 10:42:21 +00:00
// If responding to the array type (RespArray/RespSet/RespPush),
2024-02-18 10:42:21 +00:00
// it must be a multiple of 2 and return n/2.
2024-02-18 10:42:21 +00:00
// Other types will return an error.
2024-02-18 10:42:21 +00:00
func (r *Reader) ReadMapLen() (int, error) {
2024-02-18 10:42:21 +00:00
line, err := r.ReadLine()
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
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespMap:
2024-02-18 10:42:21 +00:00
return replyLen(line)
2024-02-18 10:42:21 +00:00
case RespArray, RespSet, RespPush:
2024-02-18 10:42:21 +00:00
// Some commands and RESP2 protocol may respond to array types.
2024-02-18 10:42:21 +00:00
n, err := replyLen(line)
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
if n%2 != 0 {
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("redis: the length of the array must be a multiple of 2, got: %d", n)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return n / 2, nil
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("redis: can't parse map reply: %.100q", line)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
// DiscardNext read and discard the data represented by the next line.
2024-02-18 10:42:21 +00:00
func (r *Reader) DiscardNext() error {
2024-02-18 10:42:21 +00:00
line, err := r.readLine()
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 r.Discard(line)
2024-02-18 10:42:21 +00:00
}
// Discard the data represented by line.
2024-02-18 10:42:21 +00:00
func (r *Reader) Discard(line []byte) (err error) {
2024-02-18 10:42:21 +00:00
if len(line) == 0 {
2024-02-18 10:42:21 +00:00
return errors.New("redis: invalid line")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespStatus, RespError, RespInt, RespNil, RespFloat, RespBool, RespBigInt:
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
n, err := replyLen(line)
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
}
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespBlobError, RespString, RespVerbatim:
2024-02-18 10:42:21 +00:00
// +\r\n
2024-02-18 10:42:21 +00:00
_, err = r.rd.Discard(n + 2)
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
case RespArray, RespSet, RespPush:
2024-02-18 10:42:21 +00:00
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
if err = r.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
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
case RespMap, RespAttr:
2024-02-18 10:42:21 +00:00
// Read key & value.
2024-02-18 10:42:21 +00:00
for i := 0; i < n*2; i++ {
2024-02-18 10:42:21 +00:00
if err = r.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
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
return fmt.Errorf("redis: can't parse %.100q", line)
2024-02-18 10:42:21 +00:00
}
func replyLen(line []byte) (n int, err error) {
2024-02-18 10:42:21 +00:00
n, err = util.Atoi(line[1:])
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
}
if n < -1 {
2024-02-18 10:42:21 +00:00
return 0, fmt.Errorf("redis: invalid reply: %q", line)
2024-02-18 10:42:21 +00:00
}
switch line[0] {
2024-02-18 10:42:21 +00:00
case RespString, RespVerbatim, RespBlobError,
2024-02-18 10:42:21 +00:00
RespArray, RespSet, RespPush, RespMap, RespAttr:
2024-02-18 10:42:21 +00:00
if n == -1 {
2024-02-18 10:42:21 +00:00
return 0, Nil
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 n, nil
2024-02-18 10:42:21 +00:00
}
// IsNilReply detects redis.Nil of RESP2.
2024-02-18 10:42:21 +00:00
func IsNilReply(line []byte) bool {
2024-02-18 10:42:21 +00:00
return len(line) == 3 &&
2024-02-18 10:42:21 +00:00
(line[0] == RespString || line[0] == RespArray) &&
2024-02-18 10:42:21 +00:00
line[1] == '-' && line[2] == '1'
2024-02-18 10:42:21 +00:00
}