@@ -73,10 +73,18 @@ const enum MessageCodes {
73
73
74
74
export type MessageCallback = ( msg : BackendMessage ) => void
75
75
76
+ interface CombinedBuffer {
77
+ combinedBuffer : Buffer
78
+ combinedBufferOffset : number
79
+ combinedBufferLength : number
80
+ combinedBufferFullLength : number
81
+ reuseRemainingBuffer : boolean
82
+ }
83
+
76
84
export class Parser {
77
- private buffer : Buffer = emptyBuffer
78
- private bufferLength : number = 0
79
- private bufferOffset : number = 0
85
+ private remainingBuffer : Buffer = emptyBuffer
86
+ private remainingBufferLength : number = 0
87
+ private remainingBufferOffset : number = 0
80
88
private reader = new BufferReader ( )
81
89
private mode : Mode
82
90
@@ -88,65 +96,111 @@ export class Parser {
88
96
}
89
97
90
98
public parse ( buffer : Buffer , callback : MessageCallback ) {
91
- this . mergeBuffer ( buffer )
92
- const bufferFullLength = this . bufferOffset + this . bufferLength
93
- let offset = this . bufferOffset
94
- while ( offset + HEADER_LENGTH <= bufferFullLength ) {
99
+ const {
100
+ combinedBuffer,
101
+ combinedBufferOffset,
102
+ combinedBufferLength,
103
+ reuseRemainingBuffer,
104
+ combinedBufferFullLength,
105
+ } = this . mergeBuffer ( buffer )
106
+ let offset = combinedBufferOffset
107
+ while ( offset + HEADER_LENGTH <= combinedBufferFullLength ) {
95
108
// code is 1 byte long - it identifies the message type
96
- const code = this . buffer [ offset ]
109
+ const code = combinedBuffer [ offset ]
110
+
97
111
// length is 1 Uint32BE - it is the length of the message EXCLUDING the code
98
- const length = this . buffer . readUInt32BE ( offset + CODE_LENGTH )
112
+ const length = combinedBuffer . readUInt32BE ( offset + CODE_LENGTH )
113
+
99
114
const fullMessageLength = CODE_LENGTH + length
100
- if ( fullMessageLength + offset <= bufferFullLength ) {
101
- const message = this . handlePacket ( offset + HEADER_LENGTH , code , length , this . buffer )
115
+
116
+ if ( fullMessageLength + offset <= combinedBufferFullLength ) {
117
+ const message = this . handlePacket ( offset + HEADER_LENGTH , code , length , combinedBuffer )
102
118
callback ( message )
103
119
offset += fullMessageLength
104
120
} else {
105
121
break
106
122
}
107
123
}
108
- if ( offset === bufferFullLength ) {
109
- // No more use for the buffer
110
- this . buffer = emptyBuffer
111
- this . bufferLength = 0
112
- this . bufferOffset = 0
113
- } else {
114
- // Adjust the cursors of remainingBuffer
115
- this . bufferLength = bufferFullLength - offset
116
- this . bufferOffset = offset
117
- }
124
+ this . consumeBuffer ( {
125
+ combinedBuffer,
126
+ combinedBufferOffset : offset ,
127
+ combinedBufferLength,
128
+ reuseRemainingBuffer,
129
+ combinedBufferFullLength,
130
+ } )
118
131
}
119
132
120
- private mergeBuffer ( buffer : Buffer ) : void {
121
- if ( this . bufferLength > 0 ) {
122
- const newLength = this . bufferLength + buffer . byteLength
123
- const newFullLength = newLength + this . bufferOffset
124
- if ( newFullLength > this . buffer . byteLength ) {
133
+ private mergeBuffer ( buffer : Buffer ) : CombinedBuffer {
134
+ let combinedBuffer = buffer
135
+ let combinedBufferLength = buffer . byteLength
136
+ let combinedBufferOffset = 0
137
+ let reuseRemainingBuffer = this . remainingBufferLength > 0
138
+ if ( reuseRemainingBuffer ) {
139
+ const newLength = this . remainingBufferLength + combinedBufferLength
140
+ const newFullLength = newLength + this . remainingBufferOffset
141
+ if ( newFullLength > this . remainingBuffer . byteLength ) {
125
142
// We can't concat the new buffer with the remaining one
126
143
let newBuffer : Buffer
127
- if ( newLength <= this . buffer . byteLength && this . bufferOffset >= this . bufferLength ) {
144
+ if ( newLength <= this . remainingBuffer . byteLength && this . remainingBufferOffset >= this . remainingBufferLength ) {
128
145
// We can move the relevant part to the beginning of the buffer instead of allocating a new buffer
129
- newBuffer = this . buffer
146
+ newBuffer = this . remainingBuffer
130
147
} else {
131
148
// Allocate a new larger buffer
132
- let newBufferLength = this . buffer . byteLength * 2
149
+ let newBufferLength = this . remainingBuffer . byteLength * 2
133
150
while ( newLength >= newBufferLength ) {
134
151
newBufferLength *= 2
135
152
}
136
153
newBuffer = Buffer . allocUnsafe ( newBufferLength )
137
154
}
138
155
// Move the remaining buffer to the new one
139
- this . buffer . copy ( newBuffer , 0 , this . bufferOffset , this . bufferOffset + this . bufferLength )
140
- this . buffer = newBuffer
141
- this . bufferOffset = 0
156
+ this . remainingBuffer . copy (
157
+ newBuffer ,
158
+ 0 ,
159
+ this . remainingBufferOffset ,
160
+ this . remainingBufferOffset + this . remainingBufferLength
161
+ )
162
+ this . remainingBuffer = newBuffer
163
+ this . remainingBufferOffset = 0
142
164
}
143
165
// Concat the new buffer with the remaining one
144
- buffer . copy ( this . buffer , this . bufferOffset + this . bufferLength )
145
- this . bufferLength = newLength
166
+ buffer . copy ( this . remainingBuffer , this . remainingBufferOffset + this . remainingBufferLength )
167
+ combinedBuffer = this . remainingBuffer
168
+ combinedBufferLength = this . remainingBufferLength = newLength
169
+ combinedBufferOffset = this . remainingBufferOffset
170
+ }
171
+ const combinedBufferFullLength = combinedBufferOffset + combinedBufferLength
172
+ return {
173
+ combinedBuffer,
174
+ combinedBufferOffset,
175
+ combinedBufferLength,
176
+ reuseRemainingBuffer,
177
+ combinedBufferFullLength,
178
+ }
179
+ }
180
+
181
+ private consumeBuffer ( {
182
+ combinedBufferOffset,
183
+ combinedBufferFullLength,
184
+ reuseRemainingBuffer,
185
+ combinedBuffer,
186
+ combinedBufferLength,
187
+ } : CombinedBuffer ) {
188
+ if ( combinedBufferOffset === combinedBufferFullLength ) {
189
+ // No more use for the buffer
190
+ this . remainingBuffer = emptyBuffer
191
+ this . remainingBufferLength = 0
192
+ this . remainingBufferOffset = 0
146
193
} else {
147
- this . buffer = buffer
148
- this . bufferOffset = 0
149
- this . bufferLength = buffer . byteLength
194
+ this . remainingBufferLength = combinedBufferFullLength - combinedBufferOffset
195
+ if ( reuseRemainingBuffer ) {
196
+ // Adjust the cursors of remainingBuffer
197
+ this . remainingBufferOffset = combinedBufferOffset
198
+ } else {
199
+ // To avoid side effects, copy the remaining part of the new buffer to remainingBuffer with extra space for next buffer
200
+ this . remainingBuffer = Buffer . allocUnsafe ( combinedBufferLength * 2 )
201
+ combinedBuffer . copy ( this . remainingBuffer , 0 , combinedBufferOffset )
202
+ this . remainingBufferOffset = 0
203
+ }
150
204
}
151
205
}
152
206
0 commit comments