...

Source file src/github.com/go-redis/redis/internal/proto/reader.go

Documentation: github.com/go-redis/redis/internal/proto

     1  package proto
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io"
     7  	"strconv"
     8  
     9  	"github.com/go-redis/redis/internal/util"
    10  )
    11  
    12  const (
    13  	ErrorReply  = '-'
    14  	StatusReply = '+'
    15  	IntReply    = ':'
    16  	StringReply = '$'
    17  	ArrayReply  = '*'
    18  )
    19  
    20  //------------------------------------------------------------------------------
    21  
    22  const Nil = RedisError("redis: nil")
    23  
    24  type RedisError string
    25  
    26  func (e RedisError) Error() string { return string(e) }
    27  
    28  //------------------------------------------------------------------------------
    29  
    30  type MultiBulkParse func(*Reader, int64) (interface{}, error)
    31  
    32  type Reader struct {
    33  	rd   *bufio.Reader
    34  	_buf []byte
    35  }
    36  
    37  func NewReader(rd io.Reader) *Reader {
    38  	return &Reader{
    39  		rd:   bufio.NewReader(rd),
    40  		_buf: make([]byte, 64),
    41  	}
    42  }
    43  
    44  func (r *Reader) Reset(rd io.Reader) {
    45  	r.rd.Reset(rd)
    46  }
    47  
    48  func (r *Reader) ReadLine() ([]byte, error) {
    49  	line, isPrefix, err := r.rd.ReadLine()
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	if isPrefix {
    54  		return nil, bufio.ErrBufferFull
    55  	}
    56  	if len(line) == 0 {
    57  		return nil, fmt.Errorf("redis: reply is empty")
    58  	}
    59  	if isNilReply(line) {
    60  		return nil, Nil
    61  	}
    62  	return line, nil
    63  }
    64  
    65  func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) {
    66  	line, err := r.ReadLine()
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	switch line[0] {
    72  	case ErrorReply:
    73  		return nil, ParseErrorReply(line)
    74  	case StatusReply:
    75  		return string(line[1:]), nil
    76  	case IntReply:
    77  		return util.ParseInt(line[1:], 10, 64)
    78  	case StringReply:
    79  		return r.readStringReply(line)
    80  	case ArrayReply:
    81  		n, err := parseArrayLen(line)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  		return m(r, n)
    86  	}
    87  	return nil, fmt.Errorf("redis: can't parse %.100q", line)
    88  }
    89  
    90  func (r *Reader) ReadIntReply() (int64, error) {
    91  	line, err := r.ReadLine()
    92  	if err != nil {
    93  		return 0, err
    94  	}
    95  	switch line[0] {
    96  	case ErrorReply:
    97  		return 0, ParseErrorReply(line)
    98  	case IntReply:
    99  		return util.ParseInt(line[1:], 10, 64)
   100  	default:
   101  		return 0, fmt.Errorf("redis: can't parse int reply: %.100q", line)
   102  	}
   103  }
   104  
   105  func (r *Reader) ReadString() (string, error) {
   106  	line, err := r.ReadLine()
   107  	if err != nil {
   108  		return "", err
   109  	}
   110  	switch line[0] {
   111  	case ErrorReply:
   112  		return "", ParseErrorReply(line)
   113  	case StringReply:
   114  		return r.readStringReply(line)
   115  	case StatusReply:
   116  		return string(line[1:]), nil
   117  	case IntReply:
   118  		return string(line[1:]), nil
   119  	default:
   120  		return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
   121  	}
   122  }
   123  
   124  func (r *Reader) readStringReply(line []byte) (string, error) {
   125  	if isNilReply(line) {
   126  		return "", Nil
   127  	}
   128  
   129  	replyLen, err := strconv.Atoi(string(line[1:]))
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  
   134  	b := make([]byte, replyLen+2)
   135  	_, err = io.ReadFull(r.rd, b)
   136  	if err != nil {
   137  		return "", err
   138  	}
   139  
   140  	return util.BytesToString(b[:replyLen]), nil
   141  }
   142  
   143  func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) {
   144  	line, err := r.ReadLine()
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	switch line[0] {
   149  	case ErrorReply:
   150  		return nil, ParseErrorReply(line)
   151  	case ArrayReply:
   152  		n, err := parseArrayLen(line)
   153  		if err != nil {
   154  			return nil, err
   155  		}
   156  		return m(r, n)
   157  	default:
   158  		return nil, fmt.Errorf("redis: can't parse array reply: %.100q", line)
   159  	}
   160  }
   161  
   162  func (r *Reader) ReadArrayLen() (int64, error) {
   163  	line, err := r.ReadLine()
   164  	if err != nil {
   165  		return 0, err
   166  	}
   167  	switch line[0] {
   168  	case ErrorReply:
   169  		return 0, ParseErrorReply(line)
   170  	case ArrayReply:
   171  		return parseArrayLen(line)
   172  	default:
   173  		return 0, fmt.Errorf("redis: can't parse array reply: %.100q", line)
   174  	}
   175  }
   176  
   177  func (r *Reader) ReadScanReply() ([]string, uint64, error) {
   178  	n, err := r.ReadArrayLen()
   179  	if err != nil {
   180  		return nil, 0, err
   181  	}
   182  	if n != 2 {
   183  		return nil, 0, fmt.Errorf("redis: got %d elements in scan reply, expected 2", n)
   184  	}
   185  
   186  	cursor, err := r.ReadUint()
   187  	if err != nil {
   188  		return nil, 0, err
   189  	}
   190  
   191  	n, err = r.ReadArrayLen()
   192  	if err != nil {
   193  		return nil, 0, err
   194  	}
   195  
   196  	keys := make([]string, n)
   197  	for i := int64(0); i < n; i++ {
   198  		key, err := r.ReadString()
   199  		if err != nil {
   200  			return nil, 0, err
   201  		}
   202  		keys[i] = key
   203  	}
   204  
   205  	return keys, cursor, err
   206  }
   207  
   208  func (r *Reader) ReadInt() (int64, error) {
   209  	b, err := r.readTmpBytesReply()
   210  	if err != nil {
   211  		return 0, err
   212  	}
   213  	return util.ParseInt(b, 10, 64)
   214  }
   215  
   216  func (r *Reader) ReadUint() (uint64, error) {
   217  	b, err := r.readTmpBytesReply()
   218  	if err != nil {
   219  		return 0, err
   220  	}
   221  	return util.ParseUint(b, 10, 64)
   222  }
   223  
   224  func (r *Reader) ReadFloatReply() (float64, error) {
   225  	b, err := r.readTmpBytesReply()
   226  	if err != nil {
   227  		return 0, err
   228  	}
   229  	return util.ParseFloat(b, 64)
   230  }
   231  
   232  func (r *Reader) readTmpBytesReply() ([]byte, error) {
   233  	line, err := r.ReadLine()
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  	switch line[0] {
   238  	case ErrorReply:
   239  		return nil, ParseErrorReply(line)
   240  	case StringReply:
   241  		return r._readTmpBytesReply(line)
   242  	case StatusReply:
   243  		return line[1:], nil
   244  	default:
   245  		return nil, fmt.Errorf("redis: can't parse string reply: %.100q", line)
   246  	}
   247  }
   248  
   249  func (r *Reader) _readTmpBytesReply(line []byte) ([]byte, error) {
   250  	if isNilReply(line) {
   251  		return nil, Nil
   252  	}
   253  
   254  	replyLen, err := strconv.Atoi(string(line[1:]))
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  
   259  	buf := r.buf(replyLen + 2)
   260  	_, err = io.ReadFull(r.rd, buf)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  
   265  	return buf[:replyLen], nil
   266  }
   267  
   268  func (r *Reader) buf(n int) []byte {
   269  	if d := n - cap(r._buf); d > 0 {
   270  		r._buf = append(r._buf, make([]byte, d)...)
   271  	}
   272  	return r._buf[:n]
   273  }
   274  
   275  func isNilReply(b []byte) bool {
   276  	return len(b) == 3 &&
   277  		(b[0] == StringReply || b[0] == ArrayReply) &&
   278  		b[1] == '-' && b[2] == '1'
   279  }
   280  
   281  func ParseErrorReply(line []byte) error {
   282  	return RedisError(string(line[1:]))
   283  }
   284  
   285  func parseArrayLen(line []byte) (int64, error) {
   286  	if isNilReply(line) {
   287  		return 0, Nil
   288  	}
   289  	return util.ParseInt(line[1:], 10, 64)
   290  }
   291  

View as plain text