@@ -74,7 +74,9 @@ const enum MessageCodes {
74
74
export type MessageCallback = ( msg : BackendMessage ) => void
75
75
76
76
export class Parser {
77
- private remainingBuffer : Buffer = emptyBuffer
77
+ private buffer : Buffer = emptyBuffer
78
+ private bufferLength : number = 0
79
+ private bufferOffset : number = 0
78
80
private reader = new BufferReader ( )
79
81
private mode : Mode
80
82
@@ -86,35 +88,65 @@ export class Parser {
86
88
}
87
89
88
90
public parse ( buffer : Buffer , callback : MessageCallback ) {
89
- let combinedBuffer = buffer
90
- if ( this . remainingBuffer . byteLength ) {
91
- combinedBuffer = Buffer . allocUnsafe ( this . remainingBuffer . byteLength + buffer . byteLength )
92
- this . remainingBuffer . copy ( combinedBuffer )
93
- buffer . copy ( combinedBuffer , this . remainingBuffer . byteLength )
94
- }
95
- let offset = 0
96
- while ( offset + HEADER_LENGTH <= combinedBuffer . byteLength ) {
91
+ this . mergeBuffer ( buffer )
92
+ const bufferFullLength = this . bufferOffset + this . bufferLength
93
+ let offset = this . bufferOffset
94
+ while ( offset + HEADER_LENGTH <= bufferFullLength ) {
97
95
// code is 1 byte long - it identifies the message type
98
- const code = combinedBuffer [ offset ]
99
-
96
+ const code = this . buffer [ offset ]
100
97
// length is 1 Uint32BE - it is the length of the message EXCLUDING the code
101
- const length = combinedBuffer . readUInt32BE ( offset + CODE_LENGTH )
102
-
98
+ const length = this . buffer . readUInt32BE ( offset + CODE_LENGTH )
103
99
const fullMessageLength = CODE_LENGTH + length
104
-
105
- if ( fullMessageLength + offset <= combinedBuffer . byteLength ) {
106
- const message = this . handlePacket ( offset + HEADER_LENGTH , code , length , combinedBuffer )
100
+ if ( fullMessageLength + offset <= bufferFullLength ) {
101
+ const message = this . handlePacket ( offset + HEADER_LENGTH , code , length , this . buffer )
107
102
callback ( message )
108
103
offset += fullMessageLength
109
104
} else {
110
105
break
111
106
}
112
107
}
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
+ }
118
+ }
113
119
114
- if ( offset === combinedBuffer . byteLength ) {
115
- this . remainingBuffer = emptyBuffer
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 ) {
125
+ // We can't concat the new buffer with the remaining one
126
+ let newBuffer : Buffer
127
+ if ( newLength <= this . buffer . byteLength && this . bufferOffset >= this . bufferLength ) {
128
+ // We can move the relevant part to the beginning of the buffer instead of allocating a new buffer
129
+ newBuffer = this . buffer
130
+ } else {
131
+ // Allocate a new larger buffer
132
+ let newBufferLength = this . buffer . byteLength * 2
133
+ while ( newLength >= newBufferLength ) {
134
+ newBufferLength *= 2
135
+ }
136
+ newBuffer = Buffer . allocUnsafe ( newBufferLength )
137
+ }
138
+ // 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
142
+ }
143
+ // Concat the new buffer with the remaining one
144
+ buffer . copy ( this . buffer , this . bufferOffset + this . bufferLength )
145
+ this . bufferLength = newLength
116
146
} else {
117
- this . remainingBuffer = combinedBuffer . slice ( offset )
147
+ this . buffer = buffer
148
+ this . bufferOffset = 0
149
+ this . bufferLength = buffer . byteLength
118
150
}
119
151
}
120
152
0 commit comments