@litert/televoke 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGES.md +16 -0
  2. package/docs/README.md +6 -0
  3. package/docs/Televoke_v2.1.md +499 -0
  4. package/docs/Televoke_v2.md +1 -1
  5. package/lib/client/Client.Constants.d.ts +5 -0
  6. package/lib/client/Client.Constants.d.ts.map +1 -0
  7. package/lib/client/Client.Constants.js +9 -0
  8. package/lib/client/Client.Constants.js.map +1 -0
  9. package/lib/client/Client.decl.d.ts +31 -1
  10. package/lib/client/Client.decl.d.ts.map +1 -1
  11. package/lib/client/JsonApiClient.impl.d.ts.map +1 -1
  12. package/lib/client/JsonApiClient.impl.js +29 -4
  13. package/lib/client/JsonApiClient.impl.js.map +1 -1
  14. package/lib/server/LegacyServerChannel.impl.d.ts +1 -1
  15. package/lib/server/LegacyServerChannel.impl.d.ts.map +1 -1
  16. package/lib/server/Server.decl.d.ts +17 -2
  17. package/lib/server/Server.decl.d.ts.map +1 -1
  18. package/lib/server/Server.impl.d.ts.map +1 -1
  19. package/lib/server/Server.impl.js +4 -3
  20. package/lib/server/Server.impl.js.map +1 -1
  21. package/lib/server/SimpleJsonApiRouter.d.ts +1 -1
  22. package/lib/server/SimpleJsonApiRouter.d.ts.map +1 -1
  23. package/lib/server/SimpleJsonApiRouter.js +8 -3
  24. package/lib/server/SimpleJsonApiRouter.js.map +1 -1
  25. package/lib/shared/Channel.impl.d.ts +1 -1
  26. package/lib/shared/Channel.impl.d.ts.map +1 -1
  27. package/lib/shared/Channel.impl.js +22 -10
  28. package/lib/shared/Channel.impl.js.map +1 -1
  29. package/lib/shared/Encodings/v2/Constants.v2.d.ts +13 -0
  30. package/lib/shared/Encodings/v2/Constants.v2.d.ts.map +1 -1
  31. package/lib/shared/Encodings/v2/Constants.v2.js +16 -1
  32. package/lib/shared/Encodings/v2/Constants.v2.js.map +1 -1
  33. package/lib/shared/Encodings/v2/DecoderV2.d.ts.map +1 -1
  34. package/lib/shared/Encodings/v2/DecoderV2.js +80 -6
  35. package/lib/shared/Encodings/v2/DecoderV2.js.map +1 -1
  36. package/lib/shared/Encodings/v2/EncoderV2.d.ts +2 -1
  37. package/lib/shared/Encodings/v2/EncoderV2.d.ts.map +1 -1
  38. package/lib/shared/Encodings/v2/EncoderV2.js +103 -24
  39. package/lib/shared/Encodings/v2/EncoderV2.js.map +1 -1
  40. package/lib/shared/Encodings/v2/Encoding.v2.decl.d.ts +69 -39
  41. package/lib/shared/Encodings/v2/Encoding.v2.decl.d.ts.map +1 -1
  42. package/lib/shared/Errors.d.ts +1 -0
  43. package/lib/shared/Errors.d.ts.map +1 -1
  44. package/lib/shared/Errors.js +1 -0
  45. package/lib/shared/Errors.js.map +1 -1
  46. package/lib/shared/Shared.decl.d.ts +15 -15
  47. package/lib/shared/Shared.decl.d.ts.map +1 -1
  48. package/lib/shared/Utils.d.ts +1 -1
  49. package/lib/shared/Utils.d.ts.map +1 -1
  50. package/lib/shared/Utils.js.map +1 -1
  51. package/lib/transporters/http-listener/Http.Decl.d.ts.map +1 -1
  52. package/lib/transporters/http-listener/Http.Decl.js +0 -1
  53. package/lib/transporters/http-listener/Http.Decl.js.map +1 -1
  54. package/lib/transporters/legacy-http/LegacyHttp.Client.Native.d.ts.map +1 -1
  55. package/lib/transporters/legacy-http/LegacyHttp.Client.Native.js +22 -6
  56. package/lib/transporters/legacy-http/LegacyHttp.Client.Native.js.map +1 -1
  57. package/lib/transporters/legacy-http/LegacyHttp.Server.js.map +1 -1
  58. package/lib/transporters/memory/Memory.Impl.js.map +1 -1
  59. package/lib/transporters/websocket/WebSocket.Server.d.ts.map +1 -1
  60. package/lib/transporters/websocket/WebSocket.Server.js.map +1 -1
  61. package/package.json +1 -1
  62. package/src/lib/client/Client.Constants.ts +4 -0
  63. package/src/lib/client/Client.decl.ts +41 -1
  64. package/src/lib/client/JsonApiClient.impl.ts +58 -7
  65. package/src/lib/server/LegacyServerChannel.impl.ts +1 -1
  66. package/src/lib/server/Server.decl.ts +22 -1
  67. package/src/lib/server/Server.impl.ts +4 -3
  68. package/src/lib/server/SimpleJsonApiRouter.ts +16 -3
  69. package/src/lib/shared/Channel.impl.ts +42 -22
  70. package/src/lib/shared/Encodings/v2/Constants.v2.ts +19 -0
  71. package/src/lib/shared/Encodings/v2/DecoderV2.ts +136 -14
  72. package/src/lib/shared/Encodings/v2/EncoderV2.ts +159 -35
  73. package/src/lib/shared/Encodings/v2/Encoding.v2.decl.ts +95 -43
  74. package/src/lib/shared/Errors.ts +1 -0
  75. package/src/lib/shared/Shared.decl.ts +20 -15
  76. package/src/lib/shared/Utils.ts +2 -2
  77. package/src/lib/transporters/http-listener/Http.Decl.ts +0 -1
  78. package/src/lib/transporters/legacy-http/LegacyHttp.Client.Native.ts +30 -7
  79. package/src/lib/transporters/legacy-http/LegacyHttp.Server.ts +1 -1
  80. package/src/lib/transporters/memory/Memory.Impl.ts +3 -3
  81. package/src/lib/transporters/websocket/WebSocket.Server.ts +4 -3
@@ -36,6 +36,8 @@ interface IDecodeContext {
36
36
 
37
37
  const B8 = Buffer.allocUnsafe(8);
38
38
  const B4 = Buffer.allocUnsafe(4);
39
+ const B_API_CALL_REQ_EXT_HEADER = Buffer.allocUnsafe(CSv2.API_CALL_REQ_EXT_HEADER_SIZE);
40
+ const B_API_CALL_RESP_EXT_HEADER = Buffer.allocUnsafe(CSv2.API_CALL_RESP_EXT_HEADER_SIZE);
39
41
  const B2 = Buffer.allocUnsafe(2);
40
42
 
41
43
  interface IPacketDecoder {
@@ -43,6 +45,45 @@ interface IPacketDecoder {
43
45
  decode(ctx: IDecodeContext): dEnc2.ICommandPacket;
44
46
  }
45
47
 
48
+ function skipBytes(bytes: number, ctx: IDecodeContext): void {
49
+
50
+ let readBytes = 0;
51
+
52
+ while (readBytes < bytes) {
53
+
54
+ if (ctx.chIndex === ctx.chunks.length) {
55
+
56
+ throw new errors.incomplete_packet();
57
+ }
58
+
59
+ const c = ctx.chunks[ctx.chIndex];
60
+ const cLen = c.byteLength;
61
+ let cOff = ctx.chOffset;
62
+
63
+ do {
64
+
65
+ readBytes++;
66
+ cOff++;
67
+ }
68
+ while (cOff < cLen && readBytes < bytes);
69
+
70
+ if (cOff === cLen) {
71
+
72
+ ctx.chIndex++;
73
+ ctx.chOffset = 0;
74
+ }
75
+ else {
76
+
77
+ ctx.chOffset = cOff;
78
+ }
79
+
80
+ if (readBytes === bytes) {
81
+
82
+ break;
83
+ }
84
+ }
85
+ }
86
+
46
87
  function readSmallBytes(bytes: number, buf: Buffer, ctx: IDecodeContext): Buffer {
47
88
 
48
89
  let readBytes = 0;
@@ -209,25 +250,67 @@ class TvErrorResponseDecoder implements IPacketDecoder {
209
250
  'typ': CSv2.EPacketType.ERROR_RESPONSE,
210
251
  'seq': ctx.seq,
211
252
  'ct': err,
212
- } satisfies dEnc2.IErrorResponsePacket;
253
+ } satisfies dEnc2.IErrorReplyPacket;
213
254
  }
214
255
  }
215
256
 
216
257
  class TvApiRequestDecoder implements IPacketDecoder {
217
258
 
259
+ private _decodeExtPart(
260
+ ctx: IDecodeContext,
261
+ ctOut: dEnc2.IApiRequestPacketDecoded['ct']
262
+ ): dEnc2.IApiRequestPacketDecoded['ct'] {
263
+
264
+ if (ctx.chIndex >= ctx.chunks.length) {
265
+
266
+ ctOut.bodyEnc = CSv2.DEFAULT_API_ARGS_ENCODING;
267
+ return ctOut;
268
+ }
269
+
270
+ const hdrBuf = readSmallBytes(B_API_CALL_REQ_EXT_HEADER.byteLength, B_API_CALL_REQ_EXT_HEADER, ctx);
271
+ const hdrLen = hdrBuf.readUInt32LE(CSv2.EApiCallReqExtHeaderFieldOffset.LENGTH);
272
+ const bodyEnc = hdrBuf.readUInt32LE(CSv2.EApiCallReqExtHeaderFieldOffset.BODY_ENC);
273
+ const chkQty = hdrBuf.readUInt32LE(CSv2.EApiCallReqExtHeaderFieldOffset.BIN_CHUNK_QTY);
274
+
275
+ if (!chkQty) {
276
+
277
+ ctOut.bodyEnc = bodyEnc;
278
+ return ctOut;
279
+ }
280
+
281
+ if (hdrLen > B_API_CALL_REQ_EXT_HEADER.length) {
282
+
283
+ skipBytes(hdrLen - B_API_CALL_REQ_EXT_HEADER.length, ctx);
284
+ }
285
+
286
+ const binChunks: Buffer[][] = [];
287
+
288
+ for (let i = 0; i < chkQty; ++i) {
289
+
290
+ binChunks.push(readVarBuffer(ctx));
291
+ }
292
+
293
+ ctOut.bodyEnc = bodyEnc;
294
+ ctOut.binChunks = binChunks;
295
+
296
+ return ctOut;
297
+ }
298
+
218
299
  public decode(ctx: IDecodeContext): dEnc2.ICommandPacket {
219
300
 
220
301
  const name = readVarString(ctx);
221
302
 
303
+ const body = readVarBuffer(ctx);
304
+
222
305
  return {
223
306
  'cmd': CSv2.ECommand.API_CALL,
224
307
  'typ': CSv2.EPacketType.REQUEST,
225
308
  'seq': ctx.seq,
226
- 'ct': {
309
+ 'ct': this._decodeExtPart(ctx, {
227
310
  'name': name,
228
- 'body': readVarBuffer(ctx),
229
- }
230
- } satisfies dEnc2.IApiRequestPacket;
311
+ 'body': body,
312
+ })
313
+ } satisfies dEnc2.IApiRequestPacketDecoded;
231
314
  }
232
315
  }
233
316
 
@@ -240,7 +323,7 @@ class TvPingRequestDecoder implements IPacketDecoder {
240
323
  'typ': CSv2.EPacketType.REQUEST,
241
324
  'seq': ctx.seq,
242
325
  'ct': readVarBuffer16(ctx)
243
- } satisfies dEnc2.IPingRequestPacket;
326
+ } satisfies dEnc2.IPingRequestPacketDecoded;
244
327
  }
245
328
  }
246
329
 
@@ -253,7 +336,7 @@ class TvPushMessageRequestDecoder implements IPacketDecoder {
253
336
  'typ': CSv2.EPacketType.REQUEST,
254
337
  'seq': ctx.seq,
255
338
  'ct': readVarBuffer(ctx)
256
- } satisfies dEnc2.IPushMessageRequestPacket;
339
+ } satisfies dEnc2.IPushMessageRequestPacketDecoded;
257
340
  }
258
341
  }
259
342
 
@@ -272,7 +355,7 @@ class TvBinaryChunkRequestDecoder implements IPacketDecoder {
272
355
  'index': chunkIndex,
273
356
  'body': readVarBuffer(ctx),
274
357
  }
275
- } satisfies dEnc2.IBinaryChunkRequestPacket;
358
+ } satisfies dEnc2.IBinaryChunkRequestPacketDecoded;
276
359
  }
277
360
  }
278
361
 
@@ -298,20 +381,59 @@ class TvVoidResponseDecoder implements IPacketDecoder {
298
381
  'typ': CSv2.EPacketType.SUCCESS_RESPONSE,
299
382
  'seq': ctx.seq,
300
383
  'ct': null
301
- } satisfies dEnc2.ISuccessResponsePacket;
384
+ } satisfies dEnc2.IOkReplyPacket;
302
385
  }
303
386
  }
304
387
 
305
- class TvApiResponseDecoder implements IPacketDecoder {
388
+ class TvApiReplyDecoder implements IPacketDecoder {
389
+
390
+ private _decodeExtPart(
391
+ ctx: IDecodeContext,
392
+ ctOut: dEnc2.IApiReplyPacketDecoded['ct'],
393
+
394
+ ): dEnc2.IApiReplyPacketDecoded['ct'] {
395
+
396
+ if (ctx.chIndex >= ctx.chunks.length) {
397
+
398
+ return ctOut;
399
+ }
400
+
401
+ const MIN_EXT_HEADER_LEN = CSv2.API_CALL_RESP_EXT_HEADER_SIZE;
402
+ const extHdr = readSmallBytes(MIN_EXT_HEADER_LEN, B_API_CALL_RESP_EXT_HEADER, ctx);
403
+ const extHdrLen = extHdr.readUInt32LE(CSv2.EApiCallRespExtHeaderFieldOffset.LENGTH);
404
+ const extBinChunkQty = extHdr.readUInt32LE(CSv2.EApiCallRespExtHeaderFieldOffset.BIN_CHUNK_QTY);
405
+
406
+ if (!extBinChunkQty) {
407
+
408
+ return ctOut;
409
+ }
410
+
411
+ if (extHdrLen > MIN_EXT_HEADER_LEN) {
412
+
413
+ skipBytes(extHdrLen - MIN_EXT_HEADER_LEN, ctx);
414
+ }
415
+
416
+ const extBinChunks: Buffer[][] = [];
417
+
418
+ for (let i = 0; i < extBinChunkQty; ++i) {
419
+
420
+ extBinChunks.push(readVarBuffer(ctx));
421
+ }
422
+
423
+ ctOut.binChunks = extBinChunks;
424
+
425
+ return ctOut;
426
+ }
306
427
 
307
428
  public decode(ctx: IDecodeContext): dEnc2.ICommandPacket {
308
429
 
430
+ const body = readVarBuffer(ctx);
309
431
  return {
310
432
  'cmd': CSv2.ECommand.API_CALL,
311
433
  'typ': CSv2.EPacketType.SUCCESS_RESPONSE,
312
434
  'seq': ctx.seq,
313
- 'ct': readVarBuffer(ctx)
314
- } satisfies dEnc2.IApiResponsePacket;
435
+ 'ct': this._decodeExtPart(ctx, { body })
436
+ } satisfies dEnc2.IApiReplyPacketDecoded;
315
437
  }
316
438
  }
317
439
 
@@ -324,7 +446,7 @@ class TvPingResponseDecoder implements IPacketDecoder {
324
446
  'typ': CSv2.EPacketType.SUCCESS_RESPONSE,
325
447
  'seq': ctx.seq,
326
448
  'ct': readVarBuffer16(ctx)
327
- } satisfies dEnc2.IPingResponsePacket;
449
+ } satisfies dEnc2.IPingReplyPacketDecoded;
328
450
  }
329
451
  }
330
452
 
@@ -345,7 +467,7 @@ const packetDecoders: Record<number, IPacketDecoder> = {
345
467
  [CSv2.EPacketType.SUCCESS_RESPONSE + 0x100 * CSv2.ECommand.PUSH_MESSAGE]: new TvVoidResponseDecoder(),
346
468
  [CSv2.EPacketType.SUCCESS_RESPONSE + 0x100 * CSv2.ECommand.CLOSE]: new TvVoidResponseDecoder(),
347
469
  [CSv2.EPacketType.SUCCESS_RESPONSE + 0x100 * CSv2.ECommand.BINARY_CHUNK]: new TvVoidResponseDecoder(),
348
- [CSv2.EPacketType.SUCCESS_RESPONSE + 0x100 * CSv2.ECommand.API_CALL]: new TvApiResponseDecoder(),
470
+ [CSv2.EPacketType.SUCCESS_RESPONSE + 0x100 * CSv2.ECommand.API_CALL]: new TvApiReplyDecoder(),
349
471
  [CSv2.EPacketType.SUCCESS_RESPONSE + 0x100 * CSv2.ECommand.PING]: new TvPingResponseDecoder(),
350
472
  };
351
473
 
@@ -37,9 +37,10 @@ interface IPacketEncoder {
37
37
  */
38
38
  encode(packet: dEnc2.ICommandPacket): Array<string | Buffer>;
39
39
  }
40
- class ErrorResponseEncoder implements IPacketEncoder {
41
40
 
42
- public encode(packet: dEnc2.IErrorResponsePacket): v2.IDataChunkArray {
41
+ class ErrorReplyEncoder implements IPacketEncoder {
42
+
43
+ public encode(packet: dEnc2.IErrorReplyPacket): v2.IBinLikeArray {
43
44
 
44
45
  const errorMsg = `${packet.ct.name}:${packet.ct.message}`;
45
46
 
@@ -56,9 +57,9 @@ class ErrorResponseEncoder implements IPacketEncoder {
56
57
  }
57
58
  }
58
59
 
59
- class VoidResponseEncoder implements IPacketEncoder {
60
+ class VoidReplyEncoder implements IPacketEncoder {
60
61
 
61
- public encode(packet: dEnc2.ISuccessResponsePacket): v2.IDataChunkArray {
62
+ public encode(packet: dEnc2.IOkReplyPacket): v2.IBinLikeArray {
62
63
 
63
64
  const buf = Buffer.allocUnsafe(CS.HEADER_SIZE);
64
65
 
@@ -70,13 +71,68 @@ class VoidResponseEncoder implements IPacketEncoder {
70
71
 
71
72
  class ApiRequestEncoder implements IPacketEncoder {
72
73
 
73
- public encode(packet: dEnc2.IApiRequestPacket): v2.IDataChunkArray {
74
+ private _createExtPart(
75
+ out: dEnc2.IBinLikeArray,
76
+ argsBodyEncoding: number = CS.DEFAULT_API_ARGS_ENCODING,
77
+ binChunks?: dEnc2.IEncBinItem[],
78
+ ): dEnc2.IBinLikeArray {
79
+
80
+ const header = Buffer.allocUnsafe(CS.API_CALL_REQ_EXT_HEADER_SIZE);
81
+
82
+ out.push(header);
83
+
84
+ header.writeUInt32LE(CS.API_CALL_REQ_EXT_HEADER_SIZE, CS.EApiCallReqExtHeaderFieldOffset.LENGTH);
85
+ header.writeUInt32LE(argsBodyEncoding, CS.EApiCallReqExtHeaderFieldOffset.BODY_ENC);
86
+ header.writeUInt32LE(binChunks?.length ?? 0, CS.EApiCallReqExtHeaderFieldOffset.BIN_CHUNK_QTY);
87
+
88
+ if (!binChunks?.length) {
89
+
90
+ return out;
91
+ }
92
+
93
+ for (const chunk of binChunks) {
94
+
95
+ let chunkLen = 0;
96
+
97
+ if (!chunk.length) {
98
+
99
+ const lenBuf = Buffer.allocUnsafe(4);
100
+ lenBuf.writeUInt32LE(chunkLen, 0);
101
+ out.push(lenBuf);
102
+ continue;
103
+ }
104
+
105
+ const lenBuf = Buffer.allocUnsafe(4);
106
+
107
+ if (Array.isArray(chunk)) {
108
+
109
+ for (const p of chunk) {
110
+
111
+ chunkLen += p instanceof Buffer ? p.length : Buffer.byteLength(p);
112
+ }
113
+
114
+ lenBuf.writeUInt32LE(chunkLen, 0);
115
+ out.push(lenBuf);
116
+ out.push(...chunk);
117
+ }
118
+ else {
119
+
120
+ lenBuf.writeUInt32LE(Buffer.byteLength(chunk), 0);
121
+ out.push(lenBuf, chunk);
122
+ }
123
+ }
124
+
125
+ return out;
126
+ }
127
+
128
+ public encode(packet: dEnc2.IApiRequestPacketEncoding): v2.IBinLikeArray {
74
129
 
75
130
  const apiNameLen = Buffer.byteLength(packet.ct.name);
76
131
 
77
132
  const leadSeg = Buffer.allocUnsafe(CS.HEADER_SIZE + 2 + 4 + apiNameLen);
78
133
 
79
134
  writePacketHeader(leadSeg, packet.cmd, packet.typ, packet.seq);
135
+
80
136
  leadSeg.writeUInt16LE(apiNameLen, CS.HEADER_SIZE);
81
137
  leadSeg.write(packet.ct.name, CS.HEADER_SIZE + 2);
82
138
 
@@ -91,18 +147,24 @@ class ApiRequestEncoder implements IPacketEncoder {
91
147
 
92
148
  leadSeg.writeUInt32LE(bodyLen, CS.HEADER_SIZE + 2 + apiNameLen);
93
149
 
94
- return [leadSeg, ...packet.ct.body];
150
+ return this._createExtPart([
151
+ leadSeg,
152
+ ...packet.ct.body
153
+ ], packet.ct.bodyEnc, packet.ct.binChunks);
95
154
  }
96
155
 
97
156
  leadSeg.writeUInt32LE(Buffer.byteLength(packet.ct.body), CS.HEADER_SIZE + 2 + apiNameLen);
98
157
 
99
- return [leadSeg, packet.ct.body];
158
+ return this._createExtPart([
159
+ leadSeg,
160
+ packet.ct.body
161
+ ], packet.ct.bodyEnc, packet.ct.binChunks);
100
162
  }
101
163
  }
102
164
 
103
165
  class BinaryChunkRequestEncoder implements IPacketEncoder {
104
166
 
105
- public encode(packet: dEnc2.IBinaryChunkRequestPacket): v2.IDataChunkArray {
167
+ public encode(packet: dEnc2.IBinaryChunkRequestPacketEncoding): v2.IBinLikeArray {
106
168
 
107
169
  const leadSeg = Buffer.allocUnsafe(CS.HEADER_SIZE + 12);
108
170
 
@@ -132,7 +194,7 @@ class BinaryChunkRequestEncoder implements IPacketEncoder {
132
194
 
133
195
  class PingRequestEncoder implements IPacketEncoder {
134
196
 
135
- public encode(packet: dEnc2.IPingRequestPacket): v2.IDataChunkArray {
197
+ public encode(packet: dEnc2.IPingRequestPacketEncoding): v2.IBinLikeArray {
136
198
 
137
199
  const leadSeg = Buffer.allocUnsafe(CS.HEADER_SIZE + 2);
138
200
 
@@ -160,7 +222,7 @@ class PingRequestEncoder implements IPacketEncoder {
160
222
 
161
223
  class CloseRequestEncoder implements IPacketEncoder {
162
224
 
163
- public encode(packet: dEnc2.ICloseRequestPacket): v2.IDataChunkArray {
225
+ public encode(packet: dEnc2.ICloseRequestPacket): v2.IBinLikeArray {
164
226
 
165
227
  const leadSeg = Buffer.allocUnsafe(CS.HEADER_SIZE);
166
228
 
@@ -172,7 +234,7 @@ class CloseRequestEncoder implements IPacketEncoder {
172
234
 
173
235
  class PushMessageRequestEncoder implements IPacketEncoder {
174
236
 
175
- public encode(packet: dEnc2.IPushMessageRequestPacket): v2.IDataChunkArray {
237
+ public encode(packet: dEnc2.IPushMessageRequestPacketEncoding): v2.IBinLikeArray {
176
238
 
177
239
  const leadSeg = Buffer.allocUnsafe(CS.HEADER_SIZE + 4);
178
240
 
@@ -198,37 +260,99 @@ class PushMessageRequestEncoder implements IPacketEncoder {
198
260
  }
199
261
  }
200
262
 
201
- class ApiResponseEncoder implements IPacketEncoder {
263
+ class ApiReplyEncoder implements IPacketEncoder {
264
+
265
+ private _createExtPart(
266
+ out: dEnc2.IBinLikeArray,
267
+ binChunks?: dEnc2.IEncBinItem[],
268
+ ): dEnc2.IBinLikeArray {
269
+
270
+ const header = Buffer.allocUnsafe(CS.API_CALL_RESP_EXT_HEADER_SIZE);
271
+ out.push(header);
272
+
273
+ header.writeUInt32LE(CS.API_CALL_RESP_EXT_HEADER_SIZE, CS.EApiCallRespExtHeaderFieldOffset.LENGTH);
274
+ header.writeUInt32LE(binChunks?.length ?? 0, CS.EApiCallRespExtHeaderFieldOffset.BIN_CHUNK_QTY);
275
+
276
+ if (!binChunks?.length) {
277
+
278
+ return out;
279
+ }
280
+
281
+ for (const chunk of binChunks) {
282
+
283
+ let chunkLen = 0;
284
+
285
+ if (!chunk.length) {
286
+
287
+ const lenBuf = Buffer.allocUnsafe(4);
288
+ lenBuf.writeUInt32LE(chunkLen, 0);
289
+ out.push(lenBuf);
290
+ continue;
291
+ }
202
292
 
203
- public encode(packet: dEnc2.IApiResponsePacket): v2.IDataChunkArray {
293
+ const lenBuf = Buffer.allocUnsafe(4);
294
+
295
+ if (Array.isArray(chunk)) {
296
+
297
+ for (const p of chunk) {
298
+
299
+ chunkLen += p instanceof Buffer ? p.length : Buffer.byteLength(p);
300
+ }
301
+
302
+ lenBuf.writeUInt32LE(chunkLen, 0);
303
+ out.push(lenBuf);
304
+ out.push(...chunk);
305
+ }
306
+ else {
307
+
308
+ lenBuf.writeUInt32LE(Buffer.byteLength(chunk), 0);
309
+ out.push(lenBuf, chunk);
310
+ }
311
+ }
312
+
313
+ return out;
314
+ }
315
+
316
+ public encode(packet: dEnc2.IApiReplyPacketEncoding): v2.IBinLikeArray {
204
317
 
205
318
  const leadSeg = Buffer.allocUnsafe(CS.HEADER_SIZE + 4);
206
319
 
207
320
  writePacketHeader(leadSeg, packet.cmd, packet.typ, packet.seq);
208
321
 
209
- if (Array.isArray(packet.ct)) {
322
+ let bodyLen = 0;
210
323
 
211
- let bodyLen = 0;
324
+ if (Array.isArray(packet.ct.body)) {
212
325
 
213
- for (const p of packet.ct) {
326
+ for (const p of packet.ct.body) {
214
327
 
215
- bodyLen += Buffer.byteLength(p);
328
+ bodyLen += p instanceof Buffer ? p.byteLength : Buffer.byteLength(p);
216
329
  }
330
+ }
331
+ else {
217
332
 
218
- leadSeg.writeUInt32LE(bodyLen, CS.HEADER_SIZE);
333
+ bodyLen = packet.ct.body instanceof Buffer ? packet.ct.body.byteLength : Buffer.byteLength(packet.ct.body);
334
+ }
219
335
 
220
- return [leadSeg, ...packet.ct];
336
+ leadSeg.writeUInt32LE(bodyLen, CS.HEADER_SIZE);
337
+
338
+ const ret: v2.IBinLikeArray = [leadSeg];
339
+
340
+ if (Array.isArray(packet.ct.body)) {
341
+
342
+ ret.push(...packet.ct.body);
221
343
  }
344
+ else {
222
345
 
223
- leadSeg.writeUInt32LE(Buffer.byteLength(packet.ct), CS.HEADER_SIZE);
346
+ ret.push(packet.ct.body);
347
+ }
224
348
 
225
- return [leadSeg, packet.ct];
349
+ return this._createExtPart(ret, packet.ct.binChunks);
226
350
  }
227
351
  }
228
352
 
229
- class PingResponseEncoder implements IPacketEncoder {
353
+ class PingReplyEncoder implements IPacketEncoder {
230
354
 
231
- public encode(packet: dEnc2.IPingResponsePacket): v2.IDataChunkArray {
355
+ public encode(packet: dEnc2.IPingReplyPacketEncoding): v2.IBinLikeArray {
232
356
 
233
357
  const leadSeg = Buffer.allocUnsafe(CS.HEADER_SIZE + 2);
234
358
 
@@ -262,22 +386,22 @@ const encoders: Record<number, IPacketEncoder> = {
262
386
  [CS.EPacketType.REQUEST * 0x100 + CS.ECommand.PING]: new PingRequestEncoder(),
263
387
  [CS.EPacketType.REQUEST * 0x100 + CS.ECommand.PUSH_MESSAGE]: new PushMessageRequestEncoder(),
264
388
 
265
- [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.API_CALL]: new ApiResponseEncoder(),
266
- [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.BINARY_CHUNK]: new VoidResponseEncoder(),
267
- [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.CLOSE]: new VoidResponseEncoder(),
268
- [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.PING]: new PingResponseEncoder(),
269
- [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.PUSH_MESSAGE]: new VoidResponseEncoder(),
270
-
271
- [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.API_CALL]: new ErrorResponseEncoder(),
272
- [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.BINARY_CHUNK]: new ErrorResponseEncoder(),
273
- [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.CLOSE]: new ErrorResponseEncoder(),
274
- [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.PING]: new ErrorResponseEncoder(),
275
- [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.PUSH_MESSAGE]: new ErrorResponseEncoder(),
389
+ [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.API_CALL]: new ApiReplyEncoder(),
390
+ [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.BINARY_CHUNK]: new VoidReplyEncoder(),
391
+ [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.CLOSE]: new VoidReplyEncoder(),
392
+ [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.PING]: new PingReplyEncoder(),
393
+ [CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.PUSH_MESSAGE]: new VoidReplyEncoder(),
394
+
395
+ [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.API_CALL]: new ErrorReplyEncoder(),
396
+ [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.BINARY_CHUNK]: new ErrorReplyEncoder(),
397
+ [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.CLOSE]: new ErrorReplyEncoder(),
398
+ [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.PING]: new ErrorReplyEncoder(),
399
+ [CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.PUSH_MESSAGE]: new ErrorReplyEncoder(),
276
400
  };
277
401
 
278
402
  export class TvEncoderV2 {
279
403
 
280
- public encode(packet: dEnc2.ICommandPacket): Array<Buffer | string> {
404
+ public encode(packet: dEnc2.ICommandPacket): v2.IBinLikeArray {
281
405
 
282
406
  return encoders[packet.typ * 0x100 + packet.cmd].encode(packet);
283
407
  }