Read a single command, returning it raw. Used to read replies from redis. Understands RESP3 proto.
(r *bufio.Reader)
| 145 | // Read a single command, returning it raw. Used to read replies from redis. |
| 146 | // Understands RESP3 proto. |
| 147 | func Read(r *bufio.Reader) (string, error) { |
| 148 | line, err := readLine(r) |
| 149 | if err != nil { |
| 150 | return "", err |
| 151 | } |
| 152 | |
| 153 | switch line[0] { |
| 154 | default: |
| 155 | return "", ErrProtocol |
| 156 | case '+', '-', ':', ',', '_': |
| 157 | // +: inline string |
| 158 | // -: errors |
| 159 | // :: integer |
| 160 | // ,: float |
| 161 | // _: null |
| 162 | // Simple line based replies. |
| 163 | return line, nil |
| 164 | case '$': |
| 165 | // bulk strings are: `$5\r\nhello\r\n` |
| 166 | length, err := strconv.Atoi(line[1 : len(line)-2]) |
| 167 | if err != nil { |
| 168 | return "", err |
| 169 | } |
| 170 | if length < 0 { |
| 171 | // -1 is a nil response |
| 172 | return line, nil |
| 173 | } |
| 174 | var ( |
| 175 | buf = make([]byte, length+2) |
| 176 | pos = 0 |
| 177 | ) |
| 178 | for pos < length+2 { |
| 179 | n, err := r.Read(buf[pos:]) |
| 180 | if err != nil { |
| 181 | return "", err |
| 182 | } |
| 183 | pos += n |
| 184 | } |
| 185 | return line + string(buf), nil |
| 186 | case '*', '>', '~': |
| 187 | // arrays are: `*6\r\n...` |
| 188 | // pushdata is: `>6\r\n...` |
| 189 | // sets are: `~6\r\n...` |
| 190 | length, err := strconv.Atoi(line[1 : len(line)-2]) |
| 191 | if err != nil { |
| 192 | return "", err |
| 193 | } |
| 194 | for i := 0; i < length; i++ { |
| 195 | next, err := Read(r) |
| 196 | if err != nil { |
| 197 | return "", err |
| 198 | } |
| 199 | line += next |
| 200 | } |
| 201 | return line, nil |
| 202 | case '%': |
| 203 | // maps are: `%3\r\n...` |
| 204 | length, err := strconv.Atoi(line[1 : len(line)-2]) |