redis-client 0.2.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/Gemfile +1 -2
  4. data/Gemfile.lock +2 -3
  5. data/README.md +71 -8
  6. data/Rakefile +43 -23
  7. data/lib/redis_client/command_builder.rb +91 -0
  8. data/lib/redis_client/config.rb +19 -50
  9. data/lib/redis_client/connection_mixin.rb +40 -0
  10. data/lib/redis_client/decorator.rb +84 -0
  11. data/lib/redis_client/pooled.rb +38 -30
  12. data/lib/redis_client/ruby_connection/buffered_io.rb +153 -0
  13. data/lib/redis_client/{resp3.rb → ruby_connection/resp3.rb} +0 -26
  14. data/lib/redis_client/{connection.rb → ruby_connection.rb} +26 -31
  15. data/lib/redis_client/version.rb +1 -1
  16. data/lib/redis_client.rb +183 -36
  17. data/redis-client.gemspec +2 -4
  18. metadata +12 -59
  19. data/.rubocop.yml +0 -190
  20. data/ext/redis_client/hiredis/export.clang +0 -2
  21. data/ext/redis_client/hiredis/export.gcc +0 -7
  22. data/ext/redis_client/hiredis/extconf.rb +0 -61
  23. data/ext/redis_client/hiredis/hiredis_connection.c +0 -708
  24. data/ext/redis_client/hiredis/vendor/.gitignore +0 -9
  25. data/ext/redis_client/hiredis/vendor/.travis.yml +0 -131
  26. data/ext/redis_client/hiredis/vendor/CHANGELOG.md +0 -364
  27. data/ext/redis_client/hiredis/vendor/CMakeLists.txt +0 -165
  28. data/ext/redis_client/hiredis/vendor/COPYING +0 -29
  29. data/ext/redis_client/hiredis/vendor/Makefile +0 -308
  30. data/ext/redis_client/hiredis/vendor/README.md +0 -664
  31. data/ext/redis_client/hiredis/vendor/adapters/ae.h +0 -130
  32. data/ext/redis_client/hiredis/vendor/adapters/glib.h +0 -156
  33. data/ext/redis_client/hiredis/vendor/adapters/ivykis.h +0 -84
  34. data/ext/redis_client/hiredis/vendor/adapters/libev.h +0 -179
  35. data/ext/redis_client/hiredis/vendor/adapters/libevent.h +0 -175
  36. data/ext/redis_client/hiredis/vendor/adapters/libuv.h +0 -117
  37. data/ext/redis_client/hiredis/vendor/adapters/macosx.h +0 -115
  38. data/ext/redis_client/hiredis/vendor/adapters/qt.h +0 -135
  39. data/ext/redis_client/hiredis/vendor/alloc.c +0 -86
  40. data/ext/redis_client/hiredis/vendor/alloc.h +0 -91
  41. data/ext/redis_client/hiredis/vendor/appveyor.yml +0 -24
  42. data/ext/redis_client/hiredis/vendor/async.c +0 -887
  43. data/ext/redis_client/hiredis/vendor/async.h +0 -147
  44. data/ext/redis_client/hiredis/vendor/async_private.h +0 -75
  45. data/ext/redis_client/hiredis/vendor/dict.c +0 -352
  46. data/ext/redis_client/hiredis/vendor/dict.h +0 -126
  47. data/ext/redis_client/hiredis/vendor/fmacros.h +0 -12
  48. data/ext/redis_client/hiredis/vendor/hiredis-config.cmake.in +0 -13
  49. data/ext/redis_client/hiredis/vendor/hiredis.c +0 -1174
  50. data/ext/redis_client/hiredis/vendor/hiredis.h +0 -336
  51. data/ext/redis_client/hiredis/vendor/hiredis.pc.in +0 -12
  52. data/ext/redis_client/hiredis/vendor/hiredis_ssl-config.cmake.in +0 -13
  53. data/ext/redis_client/hiredis/vendor/hiredis_ssl.h +0 -157
  54. data/ext/redis_client/hiredis/vendor/hiredis_ssl.pc.in +0 -12
  55. data/ext/redis_client/hiredis/vendor/net.c +0 -612
  56. data/ext/redis_client/hiredis/vendor/net.h +0 -56
  57. data/ext/redis_client/hiredis/vendor/read.c +0 -739
  58. data/ext/redis_client/hiredis/vendor/read.h +0 -129
  59. data/ext/redis_client/hiredis/vendor/sds.c +0 -1289
  60. data/ext/redis_client/hiredis/vendor/sds.h +0 -278
  61. data/ext/redis_client/hiredis/vendor/sdsalloc.h +0 -44
  62. data/ext/redis_client/hiredis/vendor/sockcompat.c +0 -248
  63. data/ext/redis_client/hiredis/vendor/sockcompat.h +0 -92
  64. data/ext/redis_client/hiredis/vendor/ssl.c +0 -544
  65. data/ext/redis_client/hiredis/vendor/test.c +0 -1401
  66. data/ext/redis_client/hiredis/vendor/test.sh +0 -78
  67. data/ext/redis_client/hiredis/vendor/win32.h +0 -56
  68. data/lib/redis_client/buffered_io.rb +0 -151
  69. data/lib/redis_client/hiredis_connection.rb +0 -80
@@ -1,739 +0,0 @@
1
- /*
2
- * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
- * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4
- *
5
- * All rights reserved.
6
- *
7
- * Redistribution and use in source and binary forms, with or without
8
- * modification, are permitted provided that the following conditions are met:
9
- *
10
- * * Redistributions of source code must retain the above copyright notice,
11
- * this list of conditions and the following disclaimer.
12
- * * Redistributions in binary form must reproduce the above copyright
13
- * notice, this list of conditions and the following disclaimer in the
14
- * documentation and/or other materials provided with the distribution.
15
- * * Neither the name of Redis nor the names of its contributors may be used
16
- * to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
- * POSSIBILITY OF SUCH DAMAGE.
30
- */
31
-
32
- #include "fmacros.h"
33
- #include <string.h>
34
- #include <stdlib.h>
35
- #ifndef _MSC_VER
36
- #include <unistd.h>
37
- #include <strings.h>
38
- #endif
39
- #include <assert.h>
40
- #include <errno.h>
41
- #include <ctype.h>
42
- #include <limits.h>
43
- #include <math.h>
44
-
45
- #include "alloc.h"
46
- #include "read.h"
47
- #include "sds.h"
48
- #include "win32.h"
49
-
50
- /* Initial size of our nested reply stack and how much we grow it when needd */
51
- #define REDIS_READER_STACK_SIZE 9
52
-
53
- static void __redisReaderSetError(redisReader *r, int type, const char *str) {
54
- size_t len;
55
-
56
- if (r->reply != NULL && r->fn && r->fn->freeObject) {
57
- r->fn->freeObject(r->reply);
58
- r->reply = NULL;
59
- }
60
-
61
- /* Clear input buffer on errors. */
62
- sdsfree(r->buf);
63
- r->buf = NULL;
64
- r->pos = r->len = 0;
65
-
66
- /* Reset task stack. */
67
- r->ridx = -1;
68
-
69
- /* Set error. */
70
- r->err = type;
71
- len = strlen(str);
72
- len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
73
- memcpy(r->errstr,str,len);
74
- r->errstr[len] = '\0';
75
- }
76
-
77
- static size_t chrtos(char *buf, size_t size, char byte) {
78
- size_t len = 0;
79
-
80
- switch(byte) {
81
- case '\\':
82
- case '"':
83
- len = snprintf(buf,size,"\"\\%c\"",byte);
84
- break;
85
- case '\n': len = snprintf(buf,size,"\"\\n\""); break;
86
- case '\r': len = snprintf(buf,size,"\"\\r\""); break;
87
- case '\t': len = snprintf(buf,size,"\"\\t\""); break;
88
- case '\a': len = snprintf(buf,size,"\"\\a\""); break;
89
- case '\b': len = snprintf(buf,size,"\"\\b\""); break;
90
- default:
91
- if (isprint(byte))
92
- len = snprintf(buf,size,"\"%c\"",byte);
93
- else
94
- len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
95
- break;
96
- }
97
-
98
- return len;
99
- }
100
-
101
- static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
102
- char cbuf[8], sbuf[128];
103
-
104
- chrtos(cbuf,sizeof(cbuf),byte);
105
- snprintf(sbuf,sizeof(sbuf),
106
- "Protocol error, got %s as reply type byte", cbuf);
107
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
108
- }
109
-
110
- static void __redisReaderSetErrorOOM(redisReader *r) {
111
- __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
112
- }
113
-
114
- static char *readBytes(redisReader *r, unsigned int bytes) {
115
- char *p;
116
- if (r->len-r->pos >= bytes) {
117
- p = r->buf+r->pos;
118
- r->pos += bytes;
119
- return p;
120
- }
121
- return NULL;
122
- }
123
-
124
- /* Find pointer to \r\n. */
125
- static char *seekNewline(char *s, size_t len) {
126
- int pos = 0;
127
- int _len = len-1;
128
-
129
- /* Position should be < len-1 because the character at "pos" should be
130
- * followed by a \n. Note that strchr cannot be used because it doesn't
131
- * allow to search a limited length and the buffer that is being searched
132
- * might not have a trailing NULL character. */
133
- while (pos < _len) {
134
- while(pos < _len && s[pos] != '\r') pos++;
135
- if (pos==_len) {
136
- /* Not found. */
137
- return NULL;
138
- } else {
139
- if (s[pos+1] == '\n') {
140
- /* Found. */
141
- return s+pos;
142
- } else {
143
- /* Continue searching. */
144
- pos++;
145
- }
146
- }
147
- }
148
- return NULL;
149
- }
150
-
151
- /* Convert a string into a long long. Returns REDIS_OK if the string could be
152
- * parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value
153
- * will be set to the parsed value when appropriate.
154
- *
155
- * Note that this function demands that the string strictly represents
156
- * a long long: no spaces or other characters before or after the string
157
- * representing the number are accepted, nor zeroes at the start if not
158
- * for the string "0" representing the zero number.
159
- *
160
- * Because of its strictness, it is safe to use this function to check if
161
- * you can convert a string into a long long, and obtain back the string
162
- * from the number without any loss in the string representation. */
163
- static int string2ll(const char *s, size_t slen, long long *value) {
164
- const char *p = s;
165
- size_t plen = 0;
166
- int negative = 0;
167
- unsigned long long v;
168
-
169
- if (plen == slen)
170
- return REDIS_ERR;
171
-
172
- /* Special case: first and only digit is 0. */
173
- if (slen == 1 && p[0] == '0') {
174
- if (value != NULL) *value = 0;
175
- return REDIS_OK;
176
- }
177
-
178
- if (p[0] == '-') {
179
- negative = 1;
180
- p++; plen++;
181
-
182
- /* Abort on only a negative sign. */
183
- if (plen == slen)
184
- return REDIS_ERR;
185
- }
186
-
187
- /* First digit should be 1-9, otherwise the string should just be 0. */
188
- if (p[0] >= '1' && p[0] <= '9') {
189
- v = p[0]-'0';
190
- p++; plen++;
191
- } else if (p[0] == '0' && slen == 1) {
192
- *value = 0;
193
- return REDIS_OK;
194
- } else {
195
- return REDIS_ERR;
196
- }
197
-
198
- while (plen < slen && p[0] >= '0' && p[0] <= '9') {
199
- if (v > (ULLONG_MAX / 10)) /* Overflow. */
200
- return REDIS_ERR;
201
- v *= 10;
202
-
203
- if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
204
- return REDIS_ERR;
205
- v += p[0]-'0';
206
-
207
- p++; plen++;
208
- }
209
-
210
- /* Return if not all bytes were used. */
211
- if (plen < slen)
212
- return REDIS_ERR;
213
-
214
- if (negative) {
215
- if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
216
- return REDIS_ERR;
217
- if (value != NULL) *value = -v;
218
- } else {
219
- if (v > LLONG_MAX) /* Overflow. */
220
- return REDIS_ERR;
221
- if (value != NULL) *value = v;
222
- }
223
- return REDIS_OK;
224
- }
225
-
226
- static char *readLine(redisReader *r, int *_len) {
227
- char *p, *s;
228
- int len;
229
-
230
- p = r->buf+r->pos;
231
- s = seekNewline(p,(r->len-r->pos));
232
- if (s != NULL) {
233
- len = s-(r->buf+r->pos);
234
- r->pos += len+2; /* skip \r\n */
235
- if (_len) *_len = len;
236
- return p;
237
- }
238
- return NULL;
239
- }
240
-
241
- static void moveToNextTask(redisReader *r) {
242
- redisReadTask *cur, *prv;
243
- while (r->ridx >= 0) {
244
- /* Return a.s.a.p. when the stack is now empty. */
245
- if (r->ridx == 0) {
246
- r->ridx--;
247
- return;
248
- }
249
-
250
- cur = r->task[r->ridx];
251
- prv = r->task[r->ridx-1];
252
- assert(prv->type == REDIS_REPLY_ARRAY ||
253
- prv->type == REDIS_REPLY_MAP ||
254
- prv->type == REDIS_REPLY_SET ||
255
- prv->type == REDIS_REPLY_PUSH);
256
- if (cur->idx == prv->elements-1) {
257
- r->ridx--;
258
- } else {
259
- /* Reset the type because the next item can be anything */
260
- assert(cur->idx < prv->elements);
261
- cur->type = -1;
262
- cur->elements = -1;
263
- cur->idx++;
264
- return;
265
- }
266
- }
267
- }
268
-
269
- static int processLineItem(redisReader *r) {
270
- redisReadTask *cur = r->task[r->ridx];
271
- void *obj;
272
- char *p;
273
- int len;
274
-
275
- if ((p = readLine(r,&len)) != NULL) {
276
- if (cur->type == REDIS_REPLY_INTEGER) {
277
- if (r->fn && r->fn->createInteger) {
278
- long long v;
279
- if (string2ll(p, len, &v) == REDIS_ERR) {
280
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
281
- "Bad integer value");
282
- return REDIS_ERR;
283
- }
284
- obj = r->fn->createInteger(cur,v);
285
- } else {
286
- obj = (void*)REDIS_REPLY_INTEGER;
287
- }
288
- } else if (cur->type == REDIS_REPLY_DOUBLE) {
289
- if (r->fn && r->fn->createDouble) {
290
- char buf[326], *eptr;
291
- double d;
292
-
293
- if ((size_t)len >= sizeof(buf)) {
294
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
295
- "Double value is too large");
296
- return REDIS_ERR;
297
- }
298
-
299
- memcpy(buf,p,len);
300
- buf[len] = '\0';
301
-
302
- if (strcasecmp(buf,",inf") == 0) {
303
- d = INFINITY; /* Positive infinite. */
304
- } else if (strcasecmp(buf,",-inf") == 0) {
305
- d = -INFINITY; /* Negative infinite. */
306
- } else {
307
- d = strtod((char*)buf,&eptr);
308
- if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) {
309
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
310
- "Bad double value");
311
- return REDIS_ERR;
312
- }
313
- }
314
- obj = r->fn->createDouble(cur,d,buf,len);
315
- } else {
316
- obj = (void*)REDIS_REPLY_DOUBLE;
317
- }
318
- } else if (cur->type == REDIS_REPLY_NIL) {
319
- if (r->fn && r->fn->createNil)
320
- obj = r->fn->createNil(cur);
321
- else
322
- obj = (void*)REDIS_REPLY_NIL;
323
- } else if (cur->type == REDIS_REPLY_BOOL) {
324
- int bval = p[0] == 't' || p[0] == 'T';
325
- if (r->fn && r->fn->createBool)
326
- obj = r->fn->createBool(cur,bval);
327
- else
328
- obj = (void*)REDIS_REPLY_BOOL;
329
- } else {
330
- /* Type will be error or status. */
331
- if (r->fn && r->fn->createString)
332
- obj = r->fn->createString(cur,p,len);
333
- else
334
- obj = (void*)(size_t)(cur->type);
335
- }
336
-
337
- if (obj == NULL) {
338
- __redisReaderSetErrorOOM(r);
339
- return REDIS_ERR;
340
- }
341
-
342
- /* Set reply if this is the root object. */
343
- if (r->ridx == 0) r->reply = obj;
344
- moveToNextTask(r);
345
- return REDIS_OK;
346
- }
347
-
348
- return REDIS_ERR;
349
- }
350
-
351
- static int processBulkItem(redisReader *r) {
352
- redisReadTask *cur = r->task[r->ridx];
353
- void *obj = NULL;
354
- char *p, *s;
355
- long long len;
356
- unsigned long bytelen;
357
- int success = 0;
358
-
359
- p = r->buf+r->pos;
360
- s = seekNewline(p,r->len-r->pos);
361
- if (s != NULL) {
362
- p = r->buf+r->pos;
363
- bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
364
-
365
- if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) {
366
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
367
- "Bad bulk string length");
368
- return REDIS_ERR;
369
- }
370
-
371
- if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) {
372
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
373
- "Bulk string length out of range");
374
- return REDIS_ERR;
375
- }
376
-
377
- if (len == -1) {
378
- /* The nil object can always be created. */
379
- if (r->fn && r->fn->createNil)
380
- obj = r->fn->createNil(cur);
381
- else
382
- obj = (void*)REDIS_REPLY_NIL;
383
- success = 1;
384
- } else {
385
- /* Only continue when the buffer contains the entire bulk item. */
386
- bytelen += len+2; /* include \r\n */
387
- if (r->pos+bytelen <= r->len) {
388
- if ((cur->type == REDIS_REPLY_VERB && len < 4) ||
389
- (cur->type == REDIS_REPLY_VERB && s[5] != ':'))
390
- {
391
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
392
- "Verbatim string 4 bytes of content type are "
393
- "missing or incorrectly encoded.");
394
- return REDIS_ERR;
395
- }
396
- if (r->fn && r->fn->createString)
397
- obj = r->fn->createString(cur,s+2,len);
398
- else
399
- obj = (void*)(long)cur->type;
400
- success = 1;
401
- }
402
- }
403
-
404
- /* Proceed when obj was created. */
405
- if (success) {
406
- if (obj == NULL) {
407
- __redisReaderSetErrorOOM(r);
408
- return REDIS_ERR;
409
- }
410
-
411
- r->pos += bytelen;
412
-
413
- /* Set reply if this is the root object. */
414
- if (r->ridx == 0) r->reply = obj;
415
- moveToNextTask(r);
416
- return REDIS_OK;
417
- }
418
- }
419
-
420
- return REDIS_ERR;
421
- }
422
-
423
- static int redisReaderGrow(redisReader *r) {
424
- redisReadTask **aux;
425
- int newlen;
426
-
427
- /* Grow our stack size */
428
- newlen = r->tasks + REDIS_READER_STACK_SIZE;
429
- aux = hi_realloc(r->task, sizeof(*r->task) * newlen);
430
- if (aux == NULL)
431
- goto oom;
432
-
433
- r->task = aux;
434
-
435
- /* Allocate new tasks */
436
- for (; r->tasks < newlen; r->tasks++) {
437
- r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
438
- if (r->task[r->tasks] == NULL)
439
- goto oom;
440
- }
441
-
442
- return REDIS_OK;
443
- oom:
444
- __redisReaderSetErrorOOM(r);
445
- return REDIS_ERR;
446
- }
447
-
448
- /* Process the array, map and set types. */
449
- static int processAggregateItem(redisReader *r) {
450
- redisReadTask *cur = r->task[r->ridx];
451
- void *obj;
452
- char *p;
453
- long long elements;
454
- int root = 0, len;
455
-
456
- /* Set error for nested multi bulks with depth > 7 */
457
- if (r->ridx == r->tasks - 1) {
458
- if (redisReaderGrow(r) == REDIS_ERR)
459
- return REDIS_ERR;
460
- }
461
-
462
- if ((p = readLine(r,&len)) != NULL) {
463
- if (string2ll(p, len, &elements) == REDIS_ERR) {
464
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
465
- "Bad multi-bulk length");
466
- return REDIS_ERR;
467
- }
468
-
469
- root = (r->ridx == 0);
470
-
471
- if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX) ||
472
- (r->maxelements > 0 && elements > r->maxelements))
473
- {
474
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
475
- "Multi-bulk length out of range");
476
- return REDIS_ERR;
477
- }
478
-
479
- if (elements == -1) {
480
- if (r->fn && r->fn->createNil)
481
- obj = r->fn->createNil(cur);
482
- else
483
- obj = (void*)REDIS_REPLY_NIL;
484
-
485
- if (obj == NULL) {
486
- __redisReaderSetErrorOOM(r);
487
- return REDIS_ERR;
488
- }
489
-
490
- moveToNextTask(r);
491
- } else {
492
- if (cur->type == REDIS_REPLY_MAP) elements *= 2;
493
-
494
- if (r->fn && r->fn->createArray)
495
- obj = r->fn->createArray(cur,elements);
496
- else
497
- obj = (void*)(long)cur->type;
498
-
499
- if (obj == NULL) {
500
- __redisReaderSetErrorOOM(r);
501
- return REDIS_ERR;
502
- }
503
-
504
- /* Modify task stack when there are more than 0 elements. */
505
- if (elements > 0) {
506
- cur->elements = elements;
507
- cur->obj = obj;
508
- r->ridx++;
509
- r->task[r->ridx]->type = -1;
510
- r->task[r->ridx]->elements = -1;
511
- r->task[r->ridx]->idx = 0;
512
- r->task[r->ridx]->obj = NULL;
513
- r->task[r->ridx]->parent = cur;
514
- r->task[r->ridx]->privdata = r->privdata;
515
- } else {
516
- moveToNextTask(r);
517
- }
518
- }
519
-
520
- /* Set reply if this is the root object. */
521
- if (root) r->reply = obj;
522
- return REDIS_OK;
523
- }
524
-
525
- return REDIS_ERR;
526
- }
527
-
528
- static int processItem(redisReader *r) {
529
- redisReadTask *cur = r->task[r->ridx];
530
- char *p;
531
-
532
- /* check if we need to read type */
533
- if (cur->type < 0) {
534
- if ((p = readBytes(r,1)) != NULL) {
535
- switch (p[0]) {
536
- case '-':
537
- cur->type = REDIS_REPLY_ERROR;
538
- break;
539
- case '+':
540
- cur->type = REDIS_REPLY_STATUS;
541
- break;
542
- case ':':
543
- cur->type = REDIS_REPLY_INTEGER;
544
- break;
545
- case ',':
546
- cur->type = REDIS_REPLY_DOUBLE;
547
- break;
548
- case '_':
549
- cur->type = REDIS_REPLY_NIL;
550
- break;
551
- case '$':
552
- cur->type = REDIS_REPLY_STRING;
553
- break;
554
- case '*':
555
- cur->type = REDIS_REPLY_ARRAY;
556
- break;
557
- case '%':
558
- cur->type = REDIS_REPLY_MAP;
559
- break;
560
- case '~':
561
- cur->type = REDIS_REPLY_SET;
562
- break;
563
- case '#':
564
- cur->type = REDIS_REPLY_BOOL;
565
- break;
566
- case '=':
567
- cur->type = REDIS_REPLY_VERB;
568
- break;
569
- case '>':
570
- cur->type = REDIS_REPLY_PUSH;
571
- break;
572
- default:
573
- __redisReaderSetErrorProtocolByte(r,*p);
574
- return REDIS_ERR;
575
- }
576
- } else {
577
- /* could not consume 1 byte */
578
- return REDIS_ERR;
579
- }
580
- }
581
-
582
- /* process typed item */
583
- switch(cur->type) {
584
- case REDIS_REPLY_ERROR:
585
- case REDIS_REPLY_STATUS:
586
- case REDIS_REPLY_INTEGER:
587
- case REDIS_REPLY_DOUBLE:
588
- case REDIS_REPLY_NIL:
589
- case REDIS_REPLY_BOOL:
590
- return processLineItem(r);
591
- case REDIS_REPLY_STRING:
592
- case REDIS_REPLY_VERB:
593
- return processBulkItem(r);
594
- case REDIS_REPLY_ARRAY:
595
- case REDIS_REPLY_MAP:
596
- case REDIS_REPLY_SET:
597
- case REDIS_REPLY_PUSH:
598
- return processAggregateItem(r);
599
- default:
600
- assert(NULL);
601
- return REDIS_ERR; /* Avoid warning. */
602
- }
603
- }
604
-
605
- redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
606
- redisReader *r;
607
-
608
- r = hi_calloc(1,sizeof(redisReader));
609
- if (r == NULL)
610
- return NULL;
611
-
612
- r->buf = sdsempty();
613
- if (r->buf == NULL)
614
- goto oom;
615
-
616
- r->task = hi_calloc(REDIS_READER_STACK_SIZE, sizeof(*r->task));
617
- if (r->task == NULL)
618
- goto oom;
619
-
620
- for (; r->tasks < REDIS_READER_STACK_SIZE; r->tasks++) {
621
- r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
622
- if (r->task[r->tasks] == NULL)
623
- goto oom;
624
- }
625
-
626
- r->fn = fn;
627
- r->maxbuf = REDIS_READER_MAX_BUF;
628
- r->maxelements = REDIS_READER_MAX_ARRAY_ELEMENTS;
629
- r->ridx = -1;
630
-
631
- return r;
632
- oom:
633
- redisReaderFree(r);
634
- return NULL;
635
- }
636
-
637
- void redisReaderFree(redisReader *r) {
638
- if (r == NULL)
639
- return;
640
-
641
- if (r->reply != NULL && r->fn && r->fn->freeObject)
642
- r->fn->freeObject(r->reply);
643
-
644
- if (r->task) {
645
- /* We know r->task[i] is allocated if i < r->tasks */
646
- for (int i = 0; i < r->tasks; i++) {
647
- hi_free(r->task[i]);
648
- }
649
-
650
- hi_free(r->task);
651
- }
652
-
653
- sdsfree(r->buf);
654
- hi_free(r);
655
- }
656
-
657
- int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
658
- sds newbuf;
659
-
660
- /* Return early when this reader is in an erroneous state. */
661
- if (r->err)
662
- return REDIS_ERR;
663
-
664
- /* Copy the provided buffer. */
665
- if (buf != NULL && len >= 1) {
666
- /* Destroy internal buffer when it is empty and is quite large. */
667
- if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
668
- sdsfree(r->buf);
669
- r->buf = sdsempty();
670
- if (r->buf == 0) goto oom;
671
-
672
- r->pos = 0;
673
- }
674
-
675
- newbuf = sdscatlen(r->buf,buf,len);
676
- if (newbuf == NULL) goto oom;
677
-
678
- r->buf = newbuf;
679
- r->len = sdslen(r->buf);
680
- }
681
-
682
- return REDIS_OK;
683
- oom:
684
- __redisReaderSetErrorOOM(r);
685
- return REDIS_ERR;
686
- }
687
-
688
- int redisReaderGetReply(redisReader *r, void **reply) {
689
- /* Default target pointer to NULL. */
690
- if (reply != NULL)
691
- *reply = NULL;
692
-
693
- /* Return early when this reader is in an erroneous state. */
694
- if (r->err)
695
- return REDIS_ERR;
696
-
697
- /* When the buffer is empty, there will never be a reply. */
698
- if (r->len == 0)
699
- return REDIS_OK;
700
-
701
- /* Set first item to process when the stack is empty. */
702
- if (r->ridx == -1) {
703
- r->task[0]->type = -1;
704
- r->task[0]->elements = -1;
705
- r->task[0]->idx = -1;
706
- r->task[0]->obj = NULL;
707
- r->task[0]->parent = NULL;
708
- r->task[0]->privdata = r->privdata;
709
- r->ridx = 0;
710
- }
711
-
712
- /* Process items in reply. */
713
- while (r->ridx >= 0)
714
- if (processItem(r) != REDIS_OK)
715
- break;
716
-
717
- /* Return ASAP when an error occurred. */
718
- if (r->err)
719
- return REDIS_ERR;
720
-
721
- /* Discard part of the buffer when we've consumed at least 1k, to avoid
722
- * doing unnecessary calls to memmove() in sds.c. */
723
- if (r->pos >= 1024) {
724
- if (sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR;
725
- r->pos = 0;
726
- r->len = sdslen(r->buf);
727
- }
728
-
729
- /* Emit a reply when there is one. */
730
- if (r->ridx == -1) {
731
- if (reply != NULL) {
732
- *reply = r->reply;
733
- } else if (r->reply != NULL && r->fn && r->fn->freeObject) {
734
- r->fn->freeObject(r->reply);
735
- }
736
- r->reply = NULL;
737
- }
738
- return REDIS_OK;
739
- }