• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nats-io / nats.js / 13845550996

13 Mar 2025 10:08PM UTC coverage: 82.565% (-0.03%) from 82.598%
13845550996

push

github

web-flow
fix(node): websocket under node doesn't emit close+error (only error) so redials didn't happen (#219)

Introduce a `cleanup` method for socket event handling, ensuring consistent resource cleanup across close/error scenarios. Additionally, implement a test case to verify websocket reconnect functionality after disconnection.

Signed-off-by: Alberto Ricart <alberto@synadia.com>

2276 of 3117 branches covered (73.02%)

Branch coverage included in aggregate %.

2 of 14 new or added lines in 3 files covered. (14.29%)

392 existing lines in 14 files now uncovered.

9838 of 11555 relevant lines covered (85.14%)

769151.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.75
/core/src/parser.ts
1
// deno-lint-ignore-file no-undef
2
/*
3
 * Copyright 2020-2021 The NATS Authors
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
import { DenoBuffer } from "./denobuffer.ts";
55✔
17
import { TD } from "./encoders.ts";
55✔
18
import type { Dispatcher } from "./core.ts";
19

20
export const Kind = {
55✔
21
  OK: 0,
55✔
22
  ERR: 1,
55✔
23
  MSG: 2,
55✔
24
  INFO: 3,
55✔
25
  PING: 4,
55✔
26
  PONG: 5,
55✔
27
} as const;
55✔
28

29
export type Kind = typeof Kind[keyof typeof Kind];
30

31
export interface ParserEvent {
32
  kind: Kind;
33
  msg?: MsgArg;
34
  data?: Uint8Array;
35
}
36

37
export function describe(e: ParserEvent): string {
×
38
  let ks: string;
×
39
  let data = "";
×
40

41
  switch (e.kind) {
×
42
    case Kind.MSG:
×
43
      ks = "MSG";
×
44
      break;
×
45
    case Kind.OK:
×
46
      ks = "OK";
×
47
      break;
×
48
    case Kind.ERR:
×
49
      ks = "ERR";
×
50
      data = TD.decode(e.data);
×
51
      break;
×
52
    case Kind.PING:
×
53
      ks = "PING";
×
54
      break;
×
55
    case Kind.PONG:
×
56
      ks = "PONG";
×
57
      break;
×
58
    case Kind.INFO:
×
59
      ks = "INFO";
×
60
      data = TD.decode(e.data);
×
61
  }
×
62
  return `${ks}: ${data}`;
×
63
}
×
64

65
export interface MsgArg {
66
  subject: Uint8Array;
67
  reply?: Uint8Array;
68
  sid: number;
69
  hdr: number;
70
  size: number;
71
}
72

73
function newMsgArg(): MsgArg {
395,887✔
74
  const ma = {} as MsgArg;
395,887✔
75
  ma.sid = -1;
395,887✔
76
  ma.hdr = -1;
395,887✔
77
  ma.size = -1;
395,887✔
78

79
  return ma;
395,887✔
80
}
395,887✔
81

82
const ASCII_0 = 48;
55✔
83
const ASCII_9 = 57;
55✔
84

85
// This is an almost verbatim port of the Go NATS parser
86
// https://github.com/nats-io/nats.go/blob/master/parser.go
87
export class Parser {
55✔
88
  dispatcher: Dispatcher<ParserEvent>;
54✔
89
  state: State;
1,604✔
90
  as: number;
1,604✔
91
  drop: number;
1,604✔
92
  hdr: number;
1,604✔
93
  ma!: MsgArg;
1,604✔
94
  argBuf?: DenoBuffer;
1,604✔
95
  msgBuf?: DenoBuffer;
54✔
96

97
  constructor(dispatcher: Dispatcher<ParserEvent>) {
54✔
98
    this.dispatcher = dispatcher;
1,604✔
99
    this.state = State.OP_START;
1,604✔
100
    this.as = 0;
1,604✔
101
    this.drop = 0;
1,604✔
102
    this.hdr = 0;
1,604✔
103
  }
1,604✔
104

105
  parse(buf: Uint8Array): void {
54✔
106
    let i: number;
8,880✔
107
    for (i = 0; i < buf.length; i++) {
8,880✔
108
      const b = buf[i];
20,571,676✔
109
      switch (this.state) {
20,571,676✔
110
        case State.OP_START:
20,571,676✔
111
          switch (b) {
20,969,407✔
112
            case cc.M:
20,969,407✔
113
            case cc.m:
20,969,407✔
114
              this.state = State.OP_M;
21,364,645✔
115
              this.hdr = -1;
21,364,645✔
116
              this.ma = newMsgArg();
21,364,645✔
117
              break;
21,364,645✔
118
            case cc.H:
20,969,407✔
119
            case cc.h:
20,969,407✔
120
              this.state = State.OP_H;
20,970,002✔
121
              this.hdr = 0;
20,970,002✔
122
              this.ma = newMsgArg();
20,970,002✔
123
              break;
20,970,002✔
124
            case cc.P:
20,969,407✔
125
            case cc.p:
20,969,407✔
126
              this.state = State.OP_P;
20,970,471✔
127
              break;
20,970,471✔
128
            case cc.PLUS:
12,184,427✔
129
              this.state = State.OP_PLUS;
12,184,435✔
130
              break;
12,184,435✔
UNCOV
131
            case cc.MINUS:
12,204,401✔
UNCOV
132
              this.state = State.OP_MINUS;
12,204,469✔
UNCOV
133
              break;
12,204,469✔
134
            case cc.I:
20,969,407✔
135
            case cc.i:
20,969,407✔
136
              this.state = State.OP_I;
20,970,161✔
137
              break;
20,970,161✔
138
            default:
12,184,427✔
139
              throw this.fail(buf.subarray(i));
12,184,431✔
140
          }
20,969,407✔
141
          break;
21,238,320✔
142
        case State.OP_H:
20,571,676✔
143
          switch (b) {
20,572,271✔
144
            case cc.M:
20,572,271✔
145
            case cc.m:
20,572,271✔
146
              this.state = State.OP_M;
20,572,271✔
147
              break;
20,572,271✔
148
            default:
×
149
              throw this.fail(buf.subarray(i));
×
150
          }
20,572,271✔
151
          break;
20,572,271✔
152
        case State.OP_M:
20,571,676✔
153
          switch (b) {
20,967,509✔
154
            case cc.S:
20,967,509✔
155
            case cc.s:
20,967,509✔
156
              this.state = State.OP_MS;
21,235,488✔
157
              break;
21,235,488✔
158
            default:
12,183,491!
159
              throw this.fail(buf.subarray(i));
12,183,493✔
160
          }
20,967,509✔
161
          break;
21,235,488✔
162
        case State.OP_MS:
20,571,676✔
163
          switch (b) {
20,967,507✔
164
            case cc.G:
20,967,507✔
165
            case cc.g:
20,967,507✔
166
              this.state = State.OP_MSG;
21,235,484✔
167
              break;
21,235,484✔
168
            default:
12,183,489!
169
              throw this.fail(buf.subarray(i));
12,183,491✔
170
          }
20,967,507✔
171
          break;
21,235,484✔
172
        case State.OP_MSG:
20,571,676✔
173
          switch (b) {
20,967,505✔
174
            case cc.SPACE:
20,967,505✔
175
            case cc.TAB:
20,967,505✔
176
              this.state = State.OP_MSG_SPC;
21,235,480✔
177
              break;
21,235,480✔
178
            default:
12,183,487!
179
              throw this.fail(buf.subarray(i));
12,183,489✔
180
          }
20,967,505✔
181
          break;
21,235,480✔
182
        case State.OP_MSG_SPC:
20,571,676✔
183
          switch (b) {
20,967,503✔
184
            case cc.SPACE:
×
185
            case cc.TAB:
×
186
              continue;
×
187
            default:
20,967,503✔
188
              this.state = State.MSG_ARG;
20,967,503✔
189
              this.as = i;
20,967,503✔
190
          }
20,967,503✔
191
          break;
20,967,503✔
192
        case State.MSG_ARG:
20,571,676✔
193
          switch (b) {
38,049,973✔
194
            case cc.CR:
38,049,973✔
195
              this.drop = 1;
38,445,798✔
196
              break;
38,445,798✔
197
            case cc.NL: {
76,495,773✔
198
              const arg: Uint8Array = this.argBuf
23,745,353✔
199
                ? this.argBuf.bytes()
23,745,353✔
200
                : buf.subarray(this.as, i - this.drop);
23,745,353✔
201
              this.processMsgArgs(arg);
38,445,800✔
202
              this.drop = 0;
38,445,800✔
203
              this.as = i + 1;
38,445,800✔
204
              this.state = State.MSG_PAYLOAD;
38,445,800✔
205

206
              // jump ahead with the index. If this overruns
207
              // what is left we fall out and process a split buffer.
208
              i = this.as + this.ma.size - 1;
38,445,800✔
209
              break;
38,445,800✔
210
            }
38,445,800✔
211
            default:
38,049,973✔
212
              if (this.argBuf) {
33,572,540!
213
                this.argBuf.writeByte(b);
33,572,990✔
214
              }
33,572,990✔
215
          }
38,049,973✔
216
          break;
47,950,016✔
217
        case State.MSG_PAYLOAD:
20,571,676✔
218
          if (this.msgBuf) {
20,842,730✔
219
            if (this.msgBuf.length >= this.ma.size) {
20,845,569✔
220
              const data = this.msgBuf.bytes({ copy: false });
62,540,364✔
221
              this.dispatcher.push(
20,846,788✔
222
                { kind: Kind.MSG, msg: this.ma, data: data },
104,233,940✔
223
              );
224
              this.argBuf = undefined;
20,846,788✔
225
              this.msgBuf = undefined;
20,846,788✔
226
              this.state = State.MSG_END;
20,846,788✔
227
            } else {
20,845,628✔
228
              let toCopy = this.ma.size - this.msgBuf.length;
20,847,307✔
229
              const avail = buf.length - i;
20,847,307✔
230

231
              if (avail < toCopy) {
20,847,307✔
232
                toCopy = avail;
20,847,825✔
233
              }
20,847,825✔
234

235
              if (toCopy > 0) {
20,847,307✔
236
                this.msgBuf.write(buf.subarray(i, i + toCopy));
20,847,307✔
237
                i = (i + toCopy) - 1;
20,847,307✔
238
              } else {
×
239
                this.msgBuf.writeByte(b);
×
240
              }
×
241
            }
20,847,307✔
242
          } else if (i - this.as >= this.ma.size) {
20,842,730✔
243
            this.dispatcher.push(
21,362,723✔
244
              { kind: Kind.MSG, msg: this.ma, data: buf.subarray(this.as, i) },
106,813,615✔
245
            );
246
            this.argBuf = undefined;
21,362,723✔
247
            this.msgBuf = undefined;
21,362,723✔
248
            this.state = State.MSG_END;
21,362,723✔
249
          }
21,362,723✔
250
          break;
20,969,163✔
251
        case State.MSG_END:
20,571,676✔
252
          switch (b) {
20,967,484✔
253
            case cc.NL:
20,967,484✔
254
              this.drop = 0;
20,967,484✔
255
              this.as = i + 1;
20,967,484✔
256
              this.state = State.OP_START;
20,967,484✔
257
              break;
20,967,484✔
258
            default:
×
259
              continue;
×
260
          }
20,967,484✔
261
          break;
20,967,484✔
262
        case State.OP_PLUS:
11,915,510!
263
          switch (b) {
11,915,518✔
264
            case cc.O:
11,915,518✔
265
            case cc.o:
11,915,518✔
266
              this.state = State.OP_PLUS_O;
11,915,522✔
267
              break;
11,915,522✔
268
            default:
11,915,518✔
269
              throw this.fail(buf.subarray(i));
11,915,522✔
270
          }
11,915,518✔
271
          break;
11,915,522✔
272
        case State.OP_PLUS_O:
11,915,510!
273
          switch (b) {
11,915,514✔
274
            case cc.K:
11,915,514✔
275
            case cc.k:
11,915,514✔
276
              this.state = State.OP_PLUS_OK;
11,915,514✔
277
              break;
11,915,514✔
278
            default:
×
279
              throw this.fail(buf.subarray(i));
×
280
          }
11,915,514✔
281
          break;
11,915,514✔
282
        case State.OP_PLUS_OK:
11,915,510!
283
          switch (b) {
11,915,522✔
284
            case cc.NL:
11,915,522✔
285
              this.dispatcher.push({ kind: Kind.OK });
35,746,578✔
286
              this.drop = 0;
11,915,526✔
287
              this.state = State.OP_START;
11,915,526✔
288
              break;
11,915,526✔
289
          }
11,915,522✔
290
          break;
11,915,522✔
UNCOV
291
        case State.OP_MINUS:
11,935,253!
UNCOV
292
          switch (b) {
11,935,321✔
UNCOV
293
            case cc.E:
11,935,321✔
UNCOV
294
            case cc.e:
11,935,321✔
UNCOV
295
              this.state = State.OP_MINUS_E;
11,935,385✔
UNCOV
296
              break;
11,935,385✔
297
            default:
11,915,576!
298
              throw this.fail(buf.subarray(i));
11,915,578✔
UNCOV
299
          }
11,935,321✔
UNCOV
300
          break;
11,935,385✔
UNCOV
301
        case State.OP_MINUS_E:
11,935,253!
UNCOV
302
          switch (b) {
11,935,319✔
UNCOV
303
            case cc.R:
11,935,319✔
UNCOV
304
            case cc.r:
11,935,319✔
UNCOV
305
              this.state = State.OP_MINUS_ER;
11,935,381✔
UNCOV
306
              break;
11,935,381✔
307
            default:
11,915,574!
308
              throw this.fail(buf.subarray(i));
11,915,576✔
UNCOV
309
          }
11,935,319✔
UNCOV
310
          break;
11,935,381✔
UNCOV
311
        case State.OP_MINUS_ER:
11,935,253!
UNCOV
312
          switch (b) {
11,935,317✔
UNCOV
313
            case cc.R:
11,935,317✔
UNCOV
314
            case cc.r:
11,935,317✔
UNCOV
315
              this.state = State.OP_MINUS_ERR;
11,935,377✔
UNCOV
316
              break;
11,935,377✔
317
            default:
11,915,572!
318
              throw this.fail(buf.subarray(i));
11,915,574✔
UNCOV
319
          }
11,935,317✔
UNCOV
320
          break;
11,935,377✔
UNCOV
321
        case State.OP_MINUS_ERR:
11,935,253!
UNCOV
322
          switch (b) {
11,935,315✔
UNCOV
323
            case cc.SPACE:
11,935,315✔
UNCOV
324
            case cc.TAB:
11,935,315✔
UNCOV
325
              this.state = State.OP_MINUS_ERR_SPC;
11,935,373✔
UNCOV
326
              break;
11,935,373✔
327
            default:
11,915,570!
328
              throw this.fail(buf.subarray(i));
11,915,572✔
UNCOV
329
          }
11,935,315✔
UNCOV
330
          break;
11,935,373✔
UNCOV
331
        case State.OP_MINUS_ERR_SPC:
11,935,253!
UNCOV
332
          switch (b) {
11,935,313✔
333
            case cc.SPACE:
×
334
            case cc.TAB:
×
335
              continue;
×
UNCOV
336
            default:
11,935,313✔
UNCOV
337
              this.state = State.MINUS_ERR_ARG;
11,935,313✔
UNCOV
338
              this.as = i;
11,935,313✔
UNCOV
339
          }
11,935,313✔
UNCOV
340
          break;
11,935,313✔
UNCOV
341
        case State.MINUS_ERR_ARG:
11,935,253!
UNCOV
342
          switch (b) {
11,937,399✔
UNCOV
343
            case cc.CR:
11,937,399✔
UNCOV
344
              this.drop = 1;
11,937,459✔
UNCOV
345
              break;
11,937,459✔
UNCOV
346
            case cc.NL: {
23,874,858✔
UNCOV
347
              let arg: Uint8Array;
11,937,459✔
348
              if (this.argBuf) {
11,917,580!
349
                arg = this.argBuf.bytes();
11,917,638✔
350
                this.argBuf = undefined;
11,917,638✔
351
              } else {
11,917,636✔
UNCOV
352
                arg = buf.subarray(this.as, i - this.drop);
11,937,515✔
UNCOV
353
              }
11,937,515✔
UNCOV
354
              this.dispatcher.push({ kind: Kind.ERR, data: arg });
47,749,836✔
UNCOV
355
              this.drop = 0;
11,937,459✔
UNCOV
356
              this.as = i + 1;
11,937,459✔
UNCOV
357
              this.state = State.OP_START;
11,937,459✔
UNCOV
358
              break;
11,937,459✔
UNCOV
359
            }
11,937,459✔
UNCOV
360
            default:
11,937,399✔
361
              if (this.argBuf) {
11,919,418!
362
                this.argBuf.write(Uint8Array.of(b));
11,919,436✔
363
              }
11,919,436✔
UNCOV
364
          }
11,937,399✔
UNCOV
365
          break;
11,937,399✔
366
        case State.OP_P:
20,571,676✔
367
          switch (b) {
20,572,740✔
UNCOV
368
            case cc.I:
19,694,429✔
UNCOV
369
            case cc.i:
19,694,429✔
UNCOV
370
              this.state = State.OP_PI;
19,694,478✔
UNCOV
371
              break;
19,694,478✔
372
            case cc.O:
20,572,740✔
373
            case cc.o:
20,572,740✔
374
              this.state = State.OP_PO;
20,573,716✔
375
              break;
20,573,716✔
376
            default:
11,916,035!
377
              throw this.fail(buf.subarray(i));
11,916,037✔
378
          }
20,572,740✔
379
          break;
20,573,263✔
380
        case State.OP_PO:
20,571,676✔
381
          switch (b) {
20,572,689✔
382
            case cc.N:
20,572,689✔
383
            case cc.n:
20,572,689✔
384
              this.state = State.OP_PON;
20,573,192✔
385
              break;
20,573,192✔
386
            default:
11,916,015!
387
              throw this.fail(buf.subarray(i));
11,916,017✔
388
          }
20,572,689✔
389
          break;
20,573,192✔
390
        case State.OP_PON:
20,571,676✔
391
          switch (b) {
20,572,687✔
392
            case cc.G:
20,572,687✔
393
            case cc.g:
20,572,687✔
394
              this.state = State.OP_PONG;
20,573,188✔
395
              break;
20,573,188✔
396
            default:
11,916,013!
397
              throw this.fail(buf.subarray(i));
11,916,015✔
398
          }
20,572,687✔
399
          break;
20,573,188✔
400
        case State.OP_PONG:
20,571,676✔
401
          switch (b) {
20,573,694✔
402
            case cc.NL:
20,573,694✔
403
              this.dispatcher.push({ kind: Kind.PONG });
61,724,109✔
404
              this.drop = 0;
20,574,703✔
405
              this.state = State.OP_START;
20,574,703✔
406
              break;
20,574,703✔
407
          }
20,573,694✔
408
          break;
20,573,694✔
UNCOV
409
        case State.OP_PI:
19,693,402!
UNCOV
410
          switch (b) {
19,693,451✔
UNCOV
411
            case cc.N:
19,693,451✔
UNCOV
412
            case cc.n:
19,693,451✔
UNCOV
413
              this.state = State.OP_PIN;
19,693,467✔
UNCOV
414
              break;
19,693,467✔
415
            default:
11,915,528!
416
              throw this.fail(buf.subarray(i));
11,915,530✔
UNCOV
417
          }
19,693,451✔
UNCOV
418
          break;
19,693,467✔
UNCOV
419
        case State.OP_PIN:
19,693,402!
UNCOV
420
          switch (b) {
19,693,449✔
UNCOV
421
            case cc.G:
19,693,449✔
UNCOV
422
            case cc.g:
19,693,449✔
UNCOV
423
              this.state = State.OP_PING;
19,693,463✔
UNCOV
424
              break;
19,693,463✔
425
            default:
11,915,526!
426
              throw this.fail(buf.subarray(i));
11,915,528✔
UNCOV
427
          }
19,693,449✔
UNCOV
428
          break;
19,693,463✔
UNCOV
429
        case State.OP_PING:
19,693,402!
UNCOV
430
          switch (b) {
19,693,508✔
UNCOV
431
            case cc.NL:
19,693,508✔
UNCOV
432
              this.dispatcher.push({ kind: Kind.PING });
59,080,659✔
UNCOV
433
              this.drop = 0;
19,693,553✔
UNCOV
434
              this.state = State.OP_START;
19,693,553✔
UNCOV
435
              break;
19,693,553✔
UNCOV
436
          }
19,693,508✔
UNCOV
437
          break;
19,693,508✔
438
        case State.OP_I:
20,571,676✔
439
          switch (b) {
20,572,440✔
440
            case cc.N:
20,572,440✔
441
            case cc.n:
20,572,440✔
442
              this.state = State.OP_IN;
20,572,771✔
443
              break;
20,572,771✔
444
            default:
11,915,853!
445
              throw this.fail(buf.subarray(i));
11,915,865✔
446
          }
20,572,440✔
447
          break;
20,572,771✔
448
        case State.OP_IN:
20,571,676✔
449
          switch (b) {
20,572,428✔
450
            case cc.F:
20,572,428✔
451
            case cc.f:
20,572,428✔
452
              this.state = State.OP_INF;
20,572,428✔
453
              break;
20,572,428✔
454
            default:
×
455
              throw this.fail(buf.subarray(i));
×
456
          }
20,572,428✔
457
          break;
20,572,428✔
458
        case State.OP_INF:
20,571,676✔
459
          switch (b) {
20,572,428✔
460
            case cc.O:
20,572,428✔
461
            case cc.o:
20,572,428✔
462
              this.state = State.OP_INFO;
20,572,428✔
463
              break;
20,572,428✔
464
            default:
×
465
              throw this.fail(buf.subarray(i));
×
466
          }
20,572,428✔
467
          break;
20,572,428✔
468
        case State.OP_INFO:
20,571,676✔
469
          switch (b) {
20,572,428✔
470
            case cc.SPACE:
20,572,428✔
471
            case cc.TAB:
20,572,428✔
472
              this.state = State.OP_INFO_SPC;
20,572,428✔
473
              break;
20,572,428✔
474
            default:
×
475
              throw this.fail(buf.subarray(i));
×
476
          }
20,572,428✔
477
          break;
20,572,428✔
478
        case State.OP_INFO_SPC:
20,571,676✔
479
          switch (b) {
20,572,430✔
480
            case cc.SPACE:
11,915,843!
481
            case cc.TAB:
11,915,843!
482
              continue;
11,915,845✔
483
            default:
20,572,430✔
484
              this.state = State.INFO_ARG;
20,572,761✔
485
              this.as = i;
20,572,761✔
486
          }
20,572,430✔
487
          break;
20,572,761✔
488
        case State.INFO_ARG:
20,571,676✔
489
          switch (b) {
20,869,662✔
490
            case cc.CR:
20,869,662✔
491
              this.drop = 1;
20,870,414✔
492
              break;
20,870,414✔
493
            case cc.NL: {
41,740,076✔
494
              let arg: Uint8Array;
20,870,414✔
495
              if (this.argBuf) {
12,042,759!
496
                arg = this.argBuf.bytes();
12,042,763✔
497
                this.argBuf = undefined;
12,042,763✔
498
              } else {
12,042,759✔
499
                arg = buf.subarray(this.as, i - this.drop);
20,870,741✔
500
              }
20,870,741✔
501
              this.dispatcher.push({ kind: Kind.INFO, data: arg });
83,481,656✔
502
              this.drop = 0;
20,870,414✔
503
              this.as = i + 1;
20,870,414✔
504
              this.state = State.OP_START;
20,870,414✔
505
              break;
20,870,414✔
506
            }
20,870,414✔
507
            default:
20,869,662✔
508
              if (this.argBuf) {
12,168,684!
509
                this.argBuf.writeByte(b);
12,169,044✔
510
              }
12,169,044✔
511
          }
20,869,662✔
512
          break;
20,869,662✔
513
        default:
×
514
          throw this.fail(buf.subarray(i));
×
515
      }
20,571,676✔
516
    }
20,571,676✔
517

518
    if (
3,852✔
519
      (this.state === State.MSG_ARG || this.state === State.MINUS_ERR_ARG ||
3,852✔
520
        this.state === State.INFO_ARG) && !this.argBuf
3,852!
521
    ) {
3,852!
522
      this.argBuf = new DenoBuffer(buf.subarray(this.as, i - this.drop));
3,896✔
523
    }
3,896✔
524

525
    if (this.state === State.MSG_PAYLOAD && !this.msgBuf) {
7,725!
526
      if (!this.argBuf) {
8,888✔
527
        this.cloneMsgArg();
9,993✔
528
      }
9,993✔
529
      this.msgBuf = new DenoBuffer(buf.subarray(this.as));
8,888✔
530
    }
8,888✔
531
  }
8,880✔
532

533
  cloneMsgArg() {
52✔
534
    const s = this.ma.subject.length;
1,213✔
535
    const r = this.ma.reply ? this.ma.reply.length : 0;
1,213✔
536
    const buf = new Uint8Array(s + r);
1,213✔
537
    buf.set(this.ma.subject);
1,213✔
538
    if (this.ma.reply) {
1,213✔
539
      buf.set(this.ma.reply, s);
1,369✔
540
    }
1,369✔
541
    this.argBuf = new DenoBuffer(buf);
1,213✔
542
    this.ma.subject = buf.subarray(0, s);
1,213✔
543
    if (this.ma.reply) {
1,213✔
544
      this.ma.reply = buf.subarray(s);
1,369✔
545
    }
1,369✔
546
  }
1,213✔
547

548
  processMsgArgs(arg: Uint8Array): void {
54✔
549
    if (this.hdr >= 0) {
395,881✔
550
      return this.processHeaderMsgArgs(arg);
664,449✔
551
    }
664,449✔
552

553
    const args: Uint8Array[] = [];
1,059,086✔
554
    let start = -1;
1,059,086✔
555
    for (let i = 0; i < arg.length; i++) {
663,854✔
556
      const b = arg[i];
17,708,373✔
557
      switch (b) {
17,708,373✔
558
        case cc.SPACE:
17,708,373✔
559
        case cc.TAB:
17,708,373✔
560
        case cc.CR:
17,708,373✔
561
        case cc.NL:
17,708,373✔
562
          if (start >= 0) {
18,504,320✔
563
            args.push(arg.subarray(start, i));
19,271,752✔
564
            start = -1;
19,271,752✔
565
          }
19,271,752✔
566
          break;
18,504,320✔
567
        default:
17,708,373✔
568
          if (start < 0) {
33,956,945✔
569
            start = i;
35,148,118✔
570
          }
35,148,118✔
571
      }
17,708,373✔
572
    }
17,708,373✔
573
    if (start >= 0) {
1,440,892✔
574
      args.push(arg.subarray(start));
1,708,638✔
575
    }
1,708,638✔
576

577
    switch (args.length) {
1,708,640✔
578
      case 3:
1,045,447✔
579
        this.ma.subject = args[0];
1,435,178✔
580
        this.ma.sid = this.protoParseInt(args[1]);
1,435,178✔
581
        this.ma.reply = undefined;
1,435,178✔
582
        this.ma.size = this.protoParseInt(args[2]);
1,435,178✔
583
        break;
1,435,178✔
584
      case 4:
395,881✔
585
        this.ma.subject = args[0];
401,374✔
586
        this.ma.sid = this.protoParseInt(args[1]);
401,374✔
587
        this.ma.reply = args[2];
401,374✔
588
        this.ma.size = this.protoParseInt(args[3]);
401,374✔
589
        break;
401,374✔
590
      default:
268,008!
591
        throw this.fail(arg, "processMsgArgs Parse Error");
268,016✔
592
    }
395,881✔
593

594
    if (this.ma.sid < 0) {
535,981!
595
      throw this.fail(arg, "processMsgArgs Bad or Missing Sid Error");
535,987✔
596
    }
535,987✔
597
    if (this.ma.size < 0) {
535,981!
598
      throw this.fail(arg, "processMsgArgs Bad or Missing Size Error");
535,983✔
599
    }
535,983✔
600
  }
395,881✔
601

602
  fail(data: Uint8Array, label = ""): Error {
33✔
603
    if (!label) {
93✔
604
      label = `parse error [${this.state}]`;
137✔
605
    } else {
93✔
606
      label = `${label} [${this.state}]`;
109✔
607
    }
109✔
608

609
    return new Error(`${label}: ${TD.decode(data)}`);
93✔
610
  }
93✔
611

612
  processHeaderMsgArgs(arg: Uint8Array): void {
54✔
613
    const args: Uint8Array[] = [];
649✔
614
    let start = -1;
649✔
615
    for (let i = 0; i < arg.length; i++) {
649✔
616
      const b = arg[i];
38,602✔
617
      switch (b) {
38,602✔
618
        case cc.SPACE:
38,602✔
619
        case cc.TAB:
38,602✔
620
        case cc.CR:
38,602✔
621
        case cc.NL:
38,602✔
622
          if (start >= 0) {
40,708✔
623
            args.push(arg.subarray(start, i));
41,596✔
624
            start = -1;
41,596✔
625
          }
41,596✔
626
          break;
40,708✔
627
        default:
38,602✔
628
          if (start < 0) {
74,449✔
629
            start = i;
77,149✔
630
          }
77,149✔
631
      }
38,602✔
632
    }
38,602✔
633
    if (start >= 0) {
649✔
634
      args.push(arg.subarray(start));
649✔
635
    }
649✔
636

637
    switch (args.length) {
649✔
UNCOV
638
      case 4:
638✔
UNCOV
639
        this.ma.subject = args[0];
907✔
UNCOV
640
        this.ma.sid = this.protoParseInt(args[1]);
907✔
UNCOV
641
        this.ma.reply = undefined;
907✔
UNCOV
642
        this.ma.hdr = this.protoParseInt(args[2]);
907✔
UNCOV
643
        this.ma.size = this.protoParseInt(args[3]);
907✔
UNCOV
644
        break;
907✔
645
      case 5:
642!
646
        this.ma.subject = args[0];
952✔
647
        this.ma.sid = this.protoParseInt(args[1]);
952✔
648
        this.ma.reply = args[2];
952✔
649
        this.ma.hdr = this.protoParseInt(args[3]);
952✔
650
        this.ma.size = this.protoParseInt(args[4]);
952✔
651
        break;
952✔
652
      default:
×
653
        throw this.fail(arg, "processHeaderMsgArgs Parse Error");
×
654
    }
649✔
655

656
    if (this.ma.sid < 0) {
×
657
      throw this.fail(arg, "processHeaderMsgArgs Bad or Missing Sid Error");
×
658
    }
×
659
    if (this.ma.hdr < 0 || this.ma.hdr > this.ma.size) {
×
660
      throw this.fail(
×
661
        arg,
×
662
        "processHeaderMsgArgs Bad or Missing Header Size Error",
×
663
      );
664
    }
×
665
    if (this.ma.size < 0) {
×
666
      throw this.fail(arg, "processHeaderMsgArgs Bad or Missing Size Error");
×
667
    }
×
668
  }
649✔
669

670
  protoParseInt(a: Uint8Array): number {
54✔
671
    if (a.length === 0) {
×
672
      return -1;
×
673
    }
×
674
    let n = 0;
792,287✔
675
    for (let i = 0; i < a.length; i++) {
792,287✔
676
      if (a[i] < ASCII_0 || a[i] > ASCII_9) {
1,843,642✔
677
        return -1;
1,843,654✔
678
      }
1,843,654✔
679
      n = n * 10 + (a[i] - ASCII_0);
3,789,696✔
680
    }
3,789,696✔
681
    return n;
1,328,436✔
682
  }
792,287✔
683
}
55✔
684

685
export const State = {
55✔
686
  OP_START: 0,
55✔
687
  OP_PLUS: 1,
55✔
688
  OP_PLUS_O: 2,
55✔
689
  OP_PLUS_OK: 3,
55✔
690
  OP_MINUS: 4,
55✔
691
  OP_MINUS_E: 5,
55✔
692
  OP_MINUS_ER: 6,
55✔
693
  OP_MINUS_ERR: 7,
55✔
694
  OP_MINUS_ERR_SPC: 8,
55✔
695
  MINUS_ERR_ARG: 9,
55✔
696
  OP_M: 10,
55✔
697
  OP_MS: 11,
55✔
698
  OP_MSG: 12,
55✔
699
  OP_MSG_SPC: 13,
55✔
700
  MSG_ARG: 14,
55✔
701
  MSG_PAYLOAD: 15,
55✔
702
  MSG_END: 16,
55✔
703
  OP_H: 17,
55✔
704
  OP_P: 18,
55✔
705
  OP_PI: 19,
55✔
706
  OP_PIN: 20,
55✔
707
  OP_PING: 21,
55✔
708
  OP_PO: 22,
55✔
709
  OP_PON: 23,
55✔
710
  OP_PONG: 24,
55✔
711
  OP_I: 25,
55✔
712
  OP_IN: 26,
55✔
713
  OP_INF: 27,
55✔
714
  OP_INFO: 28,
55✔
715
  OP_INFO_SPC: 29,
55✔
716
  INFO_ARG: 30,
55✔
717
} as const;
55✔
718

719
export type State = typeof State[keyof typeof State];
720

721
export const cc = {
55✔
722
  CR: "\r".charCodeAt(0),
55✔
723
  E: "E".charCodeAt(0),
55✔
724
  e: "e".charCodeAt(0),
55✔
725
  F: "F".charCodeAt(0),
55✔
726
  f: "f".charCodeAt(0),
55✔
727
  G: "G".charCodeAt(0),
55✔
728
  g: "g".charCodeAt(0),
55✔
729
  H: "H".charCodeAt(0),
55✔
730
  h: "h".charCodeAt(0),
55✔
731
  I: "I".charCodeAt(0),
55✔
732
  i: "i".charCodeAt(0),
55✔
733
  K: "K".charCodeAt(0),
55✔
734
  k: "k".charCodeAt(0),
55✔
735
  M: "M".charCodeAt(0),
55✔
736
  m: "m".charCodeAt(0),
55✔
737
  MINUS: "-".charCodeAt(0),
55✔
738
  N: "N".charCodeAt(0),
55✔
739
  n: "n".charCodeAt(0),
55✔
740
  NL: "\n".charCodeAt(0),
55✔
741
  O: "O".charCodeAt(0),
55✔
742
  o: "o".charCodeAt(0),
55✔
743
  P: "P".charCodeAt(0),
55✔
744
  p: "p".charCodeAt(0),
55✔
745
  PLUS: "+".charCodeAt(0),
55✔
746
  R: "R".charCodeAt(0),
55✔
747
  r: "r".charCodeAt(0),
55✔
748
  S: "S".charCodeAt(0),
55✔
749
  s: "s".charCodeAt(0),
55✔
750
  SPACE: " ".charCodeAt(0),
55✔
751
  TAB: "\t".charCodeAt(0),
55✔
752
} as const;
55✔
753

754
export type cc = typeof cc[keyof typeof cc];
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc