@litert/televoke 1.2.0 → 1.3.1
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.
- package/CHANGES.md +22 -0
- package/docs/README.md +6 -0
- package/docs/Televoke_v2.1.md +499 -0
- package/docs/Televoke_v2.md +1 -1
- package/lib/client/Client.Constants.d.ts +5 -0
- package/lib/client/Client.Constants.d.ts.map +1 -0
- package/lib/client/Client.Constants.js +9 -0
- package/lib/client/Client.Constants.js.map +1 -0
- package/lib/client/Client.decl.d.ts +31 -1
- package/lib/client/Client.decl.d.ts.map +1 -1
- package/lib/client/JsonApiClient.impl.d.ts.map +1 -1
- package/lib/client/JsonApiClient.impl.js +29 -4
- package/lib/client/JsonApiClient.impl.js.map +1 -1
- package/lib/server/LegacyServerChannel.impl.d.ts +1 -1
- package/lib/server/LegacyServerChannel.impl.d.ts.map +1 -1
- package/lib/server/Server.decl.d.ts +17 -2
- package/lib/server/Server.decl.d.ts.map +1 -1
- package/lib/server/Server.impl.d.ts.map +1 -1
- package/lib/server/Server.impl.js +4 -3
- package/lib/server/Server.impl.js.map +1 -1
- package/lib/server/SimpleJsonApiRouter.d.ts +1 -1
- package/lib/server/SimpleJsonApiRouter.d.ts.map +1 -1
- package/lib/server/SimpleJsonApiRouter.js +8 -3
- package/lib/server/SimpleJsonApiRouter.js.map +1 -1
- package/lib/shared/Channel.impl.d.ts +1 -1
- package/lib/shared/Channel.impl.d.ts.map +1 -1
- package/lib/shared/Channel.impl.js +22 -10
- package/lib/shared/Channel.impl.js.map +1 -1
- package/lib/shared/Encodings/v2/Constants.v2.d.ts +13 -0
- package/lib/shared/Encodings/v2/Constants.v2.d.ts.map +1 -1
- package/lib/shared/Encodings/v2/Constants.v2.js +16 -1
- package/lib/shared/Encodings/v2/Constants.v2.js.map +1 -1
- package/lib/shared/Encodings/v2/DecoderV2.d.ts.map +1 -1
- package/lib/shared/Encodings/v2/DecoderV2.js +80 -6
- package/lib/shared/Encodings/v2/DecoderV2.js.map +1 -1
- package/lib/shared/Encodings/v2/EncoderV2.d.ts +2 -1
- package/lib/shared/Encodings/v2/EncoderV2.d.ts.map +1 -1
- package/lib/shared/Encodings/v2/EncoderV2.js +103 -24
- package/lib/shared/Encodings/v2/EncoderV2.js.map +1 -1
- package/lib/shared/Encodings/v2/Encoding.v2.decl.d.ts +69 -39
- package/lib/shared/Encodings/v2/Encoding.v2.decl.d.ts.map +1 -1
- package/lib/shared/Errors.d.ts +1 -0
- package/lib/shared/Errors.d.ts.map +1 -1
- package/lib/shared/Errors.js +1 -0
- package/lib/shared/Errors.js.map +1 -1
- package/lib/shared/Shared.decl.d.ts +15 -15
- package/lib/shared/Shared.decl.d.ts.map +1 -1
- package/lib/shared/Utils.d.ts +1 -1
- package/lib/shared/Utils.d.ts.map +1 -1
- package/lib/shared/Utils.js.map +1 -1
- package/lib/transporters/http-listener/Http.Decl.d.ts.map +1 -1
- package/lib/transporters/http-listener/Http.Decl.js +0 -1
- package/lib/transporters/http-listener/Http.Decl.js.map +1 -1
- package/lib/transporters/legacy-http/LegacyHttp.Client.Native.d.ts.map +1 -1
- package/lib/transporters/legacy-http/LegacyHttp.Client.Native.js +22 -6
- package/lib/transporters/legacy-http/LegacyHttp.Client.Native.js.map +1 -1
- package/lib/transporters/legacy-http/LegacyHttp.Server.js.map +1 -1
- package/lib/transporters/memory/Memory.Impl.js.map +1 -1
- package/lib/transporters/websocket/WebSocket.Client.d.ts.map +1 -1
- package/lib/transporters/websocket/WebSocket.Client.js +6 -12
- package/lib/transporters/websocket/WebSocket.Client.js.map +1 -1
- package/lib/transporters/websocket/WebSocket.Server.d.ts.map +1 -1
- package/lib/transporters/websocket/WebSocket.Server.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/client/Client.Constants.ts +4 -0
- package/src/lib/client/Client.decl.ts +41 -1
- package/src/lib/client/JsonApiClient.impl.ts +58 -7
- package/src/lib/server/LegacyServerChannel.impl.ts +1 -1
- package/src/lib/server/Server.decl.ts +22 -1
- package/src/lib/server/Server.impl.ts +4 -3
- package/src/lib/server/SimpleJsonApiRouter.ts +16 -3
- package/src/lib/shared/Channel.impl.ts +42 -22
- package/src/lib/shared/Encodings/v2/Constants.v2.ts +19 -0
- package/src/lib/shared/Encodings/v2/DecoderV2.ts +136 -14
- package/src/lib/shared/Encodings/v2/EncoderV2.ts +159 -35
- package/src/lib/shared/Encodings/v2/Encoding.v2.decl.ts +95 -43
- package/src/lib/shared/Errors.ts +1 -0
- package/src/lib/shared/Shared.decl.ts +20 -15
- package/src/lib/shared/Utils.ts +2 -2
- package/src/lib/transporters/http-listener/Http.Decl.ts +0 -1
- package/src/lib/transporters/legacy-http/LegacyHttp.Client.Native.ts +30 -7
- package/src/lib/transporters/legacy-http/LegacyHttp.Server.ts +1 -1
- package/src/lib/transporters/memory/Memory.Impl.ts +3 -3
- package/src/lib/transporters/websocket/WebSocket.Client.ts +6 -12
- package/src/lib/transporters/websocket/WebSocket.Server.ts +4 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
1
2
|
/**
|
|
2
3
|
* Copyright 2025 Angus.Fenying <fenying@litert.org>
|
|
3
4
|
*
|
|
@@ -26,10 +27,15 @@ export interface IChannelEvents extends Shared.IDefaultEvents {
|
|
|
26
27
|
close(): void;
|
|
27
28
|
|
|
28
29
|
['api_call'](
|
|
29
|
-
callback: (
|
|
30
|
+
callback: (
|
|
31
|
+
result: string | Buffer | Array<string | Buffer> | E.TelevokeError | E.TvErrorResponse,
|
|
32
|
+
binChunks?: Array<Buffer | Buffer[]>,
|
|
33
|
+
) => void,
|
|
30
34
|
name: string,
|
|
31
35
|
args: Buffer[],
|
|
32
36
|
sequence: number,
|
|
37
|
+
argsEncoding: number,
|
|
38
|
+
extBinChunks?: Buffer[][],
|
|
33
39
|
): void;
|
|
34
40
|
|
|
35
41
|
['push_message'](
|
|
@@ -290,7 +296,7 @@ export abstract class AbstractTvChannelV2
|
|
|
290
296
|
request.callback(packet);
|
|
291
297
|
}
|
|
292
298
|
|
|
293
|
-
private _reply(packet:
|
|
299
|
+
private _reply<T extends v2.ICommandPacket = v2.ICommandPacket>(packet: T): void {
|
|
294
300
|
|
|
295
301
|
try {
|
|
296
302
|
|
|
@@ -403,30 +409,44 @@ export abstract class AbstractTvChannelV2
|
|
|
403
409
|
|
|
404
410
|
this.emit(
|
|
405
411
|
'api_call',
|
|
406
|
-
once((response: v2.
|
|
412
|
+
once((response: v2.IEncBinItem | E.TelevokeError, binChunks?: v2.IEncBinItem[]) => {
|
|
407
413
|
|
|
408
414
|
this._recvRequests--;
|
|
409
415
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
v2.
|
|
414
|
-
v2.EPacketType.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
416
|
+
if (response instanceof E.TelevokeError) {
|
|
417
|
+
|
|
418
|
+
this._reply<v2.IErrorReplyPacket>({
|
|
419
|
+
'cmd': v2.ECommand.API_CALL,
|
|
420
|
+
'typ': v2.EPacketType.ERROR_RESPONSE,
|
|
421
|
+
'seq': packet.seq,
|
|
422
|
+
'ct': response,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
this._reply<v2.IApiReplyPacketEncoding>({
|
|
427
|
+
'cmd': v2.ECommand.API_CALL,
|
|
428
|
+
'typ': v2.EPacketType.SUCCESS_RESPONSE,
|
|
429
|
+
'seq': packet.seq,
|
|
430
|
+
'ct': {
|
|
431
|
+
'body': response,
|
|
432
|
+
binChunks,
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
}
|
|
418
436
|
this._tryClean();
|
|
419
437
|
}),
|
|
420
|
-
(packet as v2.
|
|
421
|
-
(packet as v2.
|
|
422
|
-
packet.seq
|
|
438
|
+
(packet as v2.IApiRequestPacketDecoded).ct.name,
|
|
439
|
+
(packet as v2.IApiRequestPacketDecoded).ct.body,
|
|
440
|
+
packet.seq,
|
|
441
|
+
(packet as v2.IApiRequestPacketDecoded).ct.bodyEnc,
|
|
442
|
+
(packet as v2.IApiRequestPacketDecoded).ct.binChunks,
|
|
423
443
|
);
|
|
424
444
|
|
|
425
445
|
break;
|
|
426
446
|
|
|
427
447
|
case v2.ECommand.BINARY_CHUNK: {
|
|
428
448
|
|
|
429
|
-
const stream = this.streams.get((packet as v2.
|
|
449
|
+
const stream = this.streams.get((packet as v2.IBinaryChunkRequestPacketEncoding).ct.streamId)!;
|
|
430
450
|
|
|
431
451
|
if (!stream) {
|
|
432
452
|
|
|
@@ -435,16 +455,16 @@ export abstract class AbstractTvChannelV2
|
|
|
435
455
|
'typ': v2.EPacketType.ERROR_RESPONSE,
|
|
436
456
|
'seq': packet.seq,
|
|
437
457
|
'ct': new E.errors.stream_not_found({
|
|
438
|
-
'sid': (packet as v2.
|
|
458
|
+
'sid': (packet as v2.IBinaryChunkRequestPacketEncoding).ct.streamId,
|
|
439
459
|
'chId': this.id,
|
|
440
460
|
}),
|
|
441
461
|
});
|
|
442
462
|
break;
|
|
443
463
|
}
|
|
444
464
|
|
|
445
|
-
const chunkSegments = (packet as v2.
|
|
465
|
+
const chunkSegments = (packet as v2.IBinaryChunkRequestPacketEncoding).ct.body as Buffer[];
|
|
446
466
|
|
|
447
|
-
const chunkIndex = (packet as v2.
|
|
467
|
+
const chunkIndex = (packet as v2.IBinaryChunkRequestPacketEncoding).ct.index;
|
|
448
468
|
|
|
449
469
|
if (chunkIndex === 0xFFFFFFFF) {
|
|
450
470
|
|
|
@@ -457,7 +477,7 @@ export abstract class AbstractTvChannelV2
|
|
|
457
477
|
'typ': v2.EPacketType.ERROR_RESPONSE,
|
|
458
478
|
'seq': packet.seq,
|
|
459
479
|
'ct': new E.errors.stream_index_mismatch({
|
|
460
|
-
'sid': (packet as v2.
|
|
480
|
+
'sid': (packet as v2.IBinaryChunkRequestPacketEncoding).ct.streamId,
|
|
461
481
|
'chId': this.id,
|
|
462
482
|
}),
|
|
463
483
|
});
|
|
@@ -541,7 +561,7 @@ export abstract class AbstractTvChannelV2
|
|
|
541
561
|
'typ': v2.EPacketType.REQUEST,
|
|
542
562
|
'seq': seq,
|
|
543
563
|
'ct': message,
|
|
544
|
-
} satisfies v2.
|
|
564
|
+
} satisfies v2.IPingRequestPacketEncoding));
|
|
545
565
|
|
|
546
566
|
return new Promise((resolve, reject) => {
|
|
547
567
|
|
|
@@ -584,7 +604,7 @@ export abstract class AbstractTvChannelV2
|
|
|
584
604
|
'index': index === false ? 0xFFFFFFFF : index,
|
|
585
605
|
'body': chunk ?? [],
|
|
586
606
|
}
|
|
587
|
-
} satisfies v2.
|
|
607
|
+
} satisfies v2.IBinaryChunkRequestPacketEncoding));
|
|
588
608
|
|
|
589
609
|
return new Promise((resolve, reject) => {
|
|
590
610
|
|
|
@@ -616,7 +636,7 @@ export abstract class AbstractTvChannelV2
|
|
|
616
636
|
'typ': v2.EPacketType.REQUEST,
|
|
617
637
|
'seq': seq,
|
|
618
638
|
'ct': message,
|
|
619
|
-
} satisfies v2.
|
|
639
|
+
} satisfies v2.IPushMessageRequestPacketEncoding));
|
|
620
640
|
|
|
621
641
|
return new Promise((resolve, reject) => {
|
|
622
642
|
|
|
@@ -28,4 +28,23 @@ export enum EPacketType {
|
|
|
28
28
|
ERROR_RESPONSE = 0x02,
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export const JSON_API_ARGS_ENCODING = 0x00; // JSON encoding
|
|
32
|
+
export const DEFAULT_API_ARGS_ENCODING = JSON_API_ARGS_ENCODING;
|
|
33
|
+
|
|
31
34
|
export const HEADER_SIZE = 8;
|
|
35
|
+
|
|
36
|
+
export const API_CALL_REQ_EXT_HEADER_SIZE = 12;
|
|
37
|
+
export const API_CALL_RESP_EXT_HEADER_SIZE = 8;
|
|
38
|
+
|
|
39
|
+
export enum EApiCallReqExtHeaderFieldOffset {
|
|
40
|
+
|
|
41
|
+
LENGTH = 0,
|
|
42
|
+
BODY_ENC = 4,
|
|
43
|
+
BIN_CHUNK_QTY = 8
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export enum EApiCallRespExtHeaderFieldOffset {
|
|
47
|
+
|
|
48
|
+
LENGTH = 0,
|
|
49
|
+
BIN_CHUNK_QTY = 4
|
|
50
|
+
}
|
|
@@ -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.
|
|
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':
|
|
229
|
-
}
|
|
230
|
-
} satisfies dEnc2.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
384
|
+
} satisfies dEnc2.IOkReplyPacket;
|
|
302
385
|
}
|
|
303
386
|
}
|
|
304
387
|
|
|
305
|
-
class
|
|
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':
|
|
314
|
-
} satisfies dEnc2.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
60
|
+
class VoidReplyEncoder implements IPacketEncoder {
|
|
60
61
|
|
|
61
|
-
public encode(packet: dEnc2.
|
|
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
|
-
|
|
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 [
|
|
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 [
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
322
|
+
let bodyLen = 0;
|
|
210
323
|
|
|
211
|
-
|
|
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
|
-
|
|
333
|
+
bodyLen = packet.ct.body instanceof Buffer ? packet.ct.body.byteLength : Buffer.byteLength(packet.ct.body);
|
|
334
|
+
}
|
|
219
335
|
|
|
220
|
-
|
|
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
|
-
|
|
346
|
+
ret.push(packet.ct.body);
|
|
347
|
+
}
|
|
224
348
|
|
|
225
|
-
return
|
|
349
|
+
return this._createExtPart(ret, packet.ct.binChunks);
|
|
226
350
|
}
|
|
227
351
|
}
|
|
228
352
|
|
|
229
|
-
class
|
|
353
|
+
class PingReplyEncoder implements IPacketEncoder {
|
|
230
354
|
|
|
231
|
-
public encode(packet: dEnc2.
|
|
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
|
|
266
|
-
[CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.BINARY_CHUNK]: new
|
|
267
|
-
[CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.CLOSE]: new
|
|
268
|
-
[CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.PING]: new
|
|
269
|
-
[CS.EPacketType.SUCCESS_RESPONSE * 0x100 + CS.ECommand.PUSH_MESSAGE]: new
|
|
270
|
-
|
|
271
|
-
[CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.API_CALL]: new
|
|
272
|
-
[CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.BINARY_CHUNK]: new
|
|
273
|
-
[CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.CLOSE]: new
|
|
274
|
-
[CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.PING]: new
|
|
275
|
-
[CS.EPacketType.ERROR_RESPONSE * 0x100 + CS.ECommand.PUSH_MESSAGE]: new
|
|
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):
|
|
404
|
+
public encode(packet: dEnc2.ICommandPacket): v2.IBinLikeArray {
|
|
281
405
|
|
|
282
406
|
return encoders[packet.typ * 0x100 + packet.cmd].encode(packet);
|
|
283
407
|
}
|