1
+ 'use strict' ;
2
+
3
+ function JavascriptReplyParser ( options ) {
4
+ this . name = 'javascript_old' ;
5
+ this . buffer = new Buffer ( 0 ) ;
6
+ this . offset = 0 ;
7
+ this . bigStrSize = 0 ;
8
+ this . chunksSize = 0 ;
9
+ this . buffers = [ ] ;
10
+ this . type = 0 ;
11
+ this . protocolError = false ;
12
+ this . offsetCache = 0 ;
13
+ // If returnBuffers is active, all return values are returned as buffers besides numbers and errors
14
+ if ( options . return_buffers ) {
15
+ this . handleReply = function ( start , end ) {
16
+ return this . buffer . slice ( start , end ) ;
17
+ } ;
18
+ } else {
19
+ this . handleReply = function ( start , end ) {
20
+ return this . buffer . toString ( 'utf-8' , start , end ) ;
21
+ } ;
22
+ }
23
+ // If stringNumbers is activated the parser always returns numbers as string
24
+ // This is important for big numbers (number > Math.pow(2, 53)) as js numbers are 64bit floating point numbers with reduced precision
25
+ if ( options . string_numbers ) {
26
+ this . handleNumbers = function ( start , end ) {
27
+ return this . buffer . toString ( 'ascii' , start , end ) ;
28
+ } ;
29
+ } else {
30
+ this . handleNumbers = function ( start , end ) {
31
+ return + this . buffer . toString ( 'ascii' , start , end ) ;
32
+ } ;
33
+ }
34
+ }
35
+
36
+ JavascriptReplyParser . prototype . parseResult = function ( type ) {
37
+ var start = 0 ,
38
+ end = 0 ,
39
+ packetHeader = 0 ,
40
+ reply ;
41
+
42
+ if ( type === 36 ) { // $
43
+ packetHeader = this . parseHeader ( ) ;
44
+ // Packets with a size of -1 are considered null
45
+ if ( packetHeader === - 1 ) {
46
+ return null ;
47
+ }
48
+ end = this . offset + packetHeader ;
49
+ start = this . offset ;
50
+ if ( end + 2 > this . buffer . length ) {
51
+ this . buffers . push ( this . offsetCache === 0 ? this . buffer : this . buffer . slice ( this . offsetCache ) ) ;
52
+ this . chunksSize = this . buffers [ 0 ] . length ;
53
+ // Include the packetHeader delimiter
54
+ this . bigStrSize = packetHeader + 2 ;
55
+ throw new Error ( 'Wait for more data.' ) ;
56
+ }
57
+ // Set the offset to after the delimiter
58
+ this . offset = end + 2 ;
59
+ return this . handleReply ( start , end ) ;
60
+ } else if ( type === 58 ) { // :
61
+ // Up to the delimiter
62
+ end = this . packetEndOffset ( ) ;
63
+ start = this . offset ;
64
+ // Include the delimiter
65
+ this . offset = end + 2 ;
66
+ // Return the coerced numeric value
67
+ return this . handleNumbers ( start , end ) ;
68
+ } else if ( type === 43 ) { // +
69
+ end = this . packetEndOffset ( ) ;
70
+ start = this . offset ;
71
+ this . offset = end + 2 ;
72
+ return this . handleReply ( start , end ) ;
73
+ } else if ( type === 42 ) { // *
74
+ packetHeader = this . parseHeader ( ) ;
75
+ if ( packetHeader === - 1 ) {
76
+ return null ;
77
+ }
78
+ reply = [ ] ;
79
+ for ( var i = 0 ; i < packetHeader ; i ++ ) {
80
+ if ( this . offset >= this . buffer . length ) {
81
+ throw new Error ( 'Wait for more data.' ) ;
82
+ }
83
+ reply . push ( this . parseResult ( this . buffer [ this . offset ++ ] ) ) ;
84
+ }
85
+ return reply ;
86
+ } else if ( type === 45 ) { // -
87
+ end = this . packetEndOffset ( ) ;
88
+ start = this . offset ;
89
+ this . offset = end + 2 ;
90
+ return new Error ( this . buffer . toString ( 'utf-8' , start , end ) ) ;
91
+ }
92
+ } ;
93
+
94
+ JavascriptReplyParser . prototype . execute = function ( buffer ) {
95
+ if ( this . chunksSize !== 0 ) {
96
+ if ( this . bigStrSize > this . chunksSize + buffer . length ) {
97
+ this . buffers . push ( buffer ) ;
98
+ this . chunksSize += buffer . length ;
99
+ return ;
100
+ }
101
+ this . buffers . push ( buffer ) ;
102
+ this . buffer = Buffer . concat ( this . buffers , this . chunksSize + buffer . length ) ;
103
+ this . buffers = [ ] ;
104
+ this . bigStrSize = 0 ;
105
+ this . chunksSize = 0 ;
106
+ } else if ( this . offset >= this . buffer . length ) {
107
+ this . buffer = buffer ;
108
+ } else {
109
+ this . buffer = Buffer . concat ( [ this . buffer . slice ( this . offset ) , buffer ] ) ;
110
+ }
111
+ this . offset = 0 ;
112
+ this . run ( ) ;
113
+ } ;
114
+
115
+ JavascriptReplyParser . prototype . tryParsing = function ( ) {
116
+ try {
117
+ return this . parseResult ( this . type ) ;
118
+ } catch ( err ) {
119
+ // Catch the error (not enough data), rewind if it's an array,
120
+ // and wait for the next packet to appear
121
+ this . offset = this . offsetCache ;
122
+ // Indicate that there's no protocol error by resetting the type too
123
+ this . type = undefined ;
124
+ }
125
+ } ;
126
+
127
+ JavascriptReplyParser . prototype . run = function ( ) {
128
+ // Set a rewind point. If a failure occurs, wait for the next execute()/append() and try again
129
+ this . offsetCache = this . offset ;
130
+ this . type = this . buffer [ this . offset ++ ] ;
131
+ var reply = this . tryParsing ( ) ;
132
+
133
+ while ( reply !== undefined ) {
134
+ if ( this . type === 45 ) { // Errors -
135
+ this . returnError ( reply ) ;
136
+ } else {
137
+ this . returnReply ( reply ) ; // Strings + // Integers : // Bulk strings $ // Arrays *
138
+ }
139
+ this . offsetCache = this . offset ;
140
+ this . type = this . buffer [ this . offset ++ ] ;
141
+ reply = this . tryParsing ( ) ;
142
+ }
143
+ if ( this . type !== undefined ) {
144
+ // Reset the buffer so the parser can handle following commands properly
145
+ this . buffer = new Buffer ( 0 ) ;
146
+ this . returnFatalError ( new Error ( 'Protocol error, got ' + JSON . stringify ( String . fromCharCode ( this . type ) ) + ' as reply type byte' ) ) ;
147
+ }
148
+ } ;
149
+
150
+ JavascriptReplyParser . prototype . parseHeader = function ( ) {
151
+ var end = this . packetEndOffset ( ) ,
152
+ value = this . buffer . toString ( 'ascii' , this . offset , end ) | 0 ;
153
+
154
+ this . offset = end + 2 ;
155
+ return value ;
156
+ } ;
157
+
158
+ JavascriptReplyParser . prototype . packetEndOffset = function ( ) {
159
+ var offset = this . offset ,
160
+ len = this . buffer . length - 1 ;
161
+
162
+ while ( this . buffer [ offset ] !== 0x0d && this . buffer [ offset + 1 ] !== 0x0a ) {
163
+ offset ++ ;
164
+
165
+ if ( offset >= len ) {
166
+ throw new Error ( 'Did not see LF after NL reading multi bulk count (' + offset + ' => ' + this . buffer . length + ', ' + this . offset + ')' ) ;
167
+ }
168
+ }
169
+ return offset ;
170
+ } ;
171
+
172
+ module . exports = JavascriptReplyParser ;
0 commit comments