Skip to content

Commit

Permalink
fix(ignore): Fix crash due to BigInt serialization (#1191)
Browse files Browse the repository at this point in the history
  • Loading branch information
Koenkk authored Sep 19, 2024
1 parent a334e76 commit d760eb3
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 5 deletions.
8 changes: 8 additions & 0 deletions src/utils/patchBigIntSerialization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Patch BigInt serialization which is used in e.g. Zcl payloads.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#use_within_json
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BigInt.prototype as any).toJSON = function (): string {
return this.toString();
};

export {};
2 changes: 2 additions & 0 deletions src/zspec/zcl/zclFrame.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import '../../utils/patchBigIntSerialization';

import {BuffaloZcl} from './buffaloZcl';
import {BuffaloZclDataType, DataType, Direction, FrameType, ParameterCondition} from './definition/enums';
import {FoundationCommandName} from './definition/foundation';
Expand Down
12 changes: 12 additions & 0 deletions test/utils/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,15 @@ export const uint16To8Array = (n: number): number[] => {
export const uint32To8Array = (n: number): number[] => {
return [n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff];
};

export const uint56To8Array = (n: bigint): number[] => {
return [
Number(n & 0xffn),
Number(n >> 8n) & 0xff,
Number(n >> 16n) & 0xff,
Number(n >> 24n) & 0xff,
Number(n >> 32n) & 0xff,
Number(n >> 40n) & 0xff,
Number(n >> 48n) & 0xff,
];
};
51 changes: 46 additions & 5 deletions test/zspec/zcl/frame.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as Zcl from '../../../src/zspec/zcl';
import {BuffaloZcl} from '../../../src/zspec/zcl/buffaloZcl';
import {uint16To8Array, uint32To8Array} from '../../utils/math';
import {uint16To8Array, uint32To8Array, uint56To8Array} from '../../utils/math';

/** Header with Global frame type */
const GLOBAL_HEADER = new Zcl.Header(
Expand Down Expand Up @@ -32,6 +32,21 @@ const GLOBAL_RSP_HEADER = new Zcl.Header(
);
const GLOBAL_RSP_HEADER_BUFFER = Buffer.from([8, 78, Zcl.Foundation.readRsp.ID]);

/** Header with Global frame type with command report */
const GLOBAL_HEADER_REPORT = new Zcl.Header(
{
frameType: Zcl.FrameType.GLOBAL,
manufacturerSpecific: false,
direction: Zcl.Direction.CLIENT_TO_SERVER,
disableDefaultResponse: false,
reservedBits: 0,
},
undefined,
123,
Zcl.Foundation.report.ID,
);
const GLOBAL_HEADER_REPORT_BUFFER = Buffer.from([0, 123, Zcl.Foundation.report.ID]);

/** Header with Global frame type and server to client direction including condition-based parameters */
const GLOBAL_CONDITION_HEADER = new Zcl.Header(
{
Expand Down Expand Up @@ -115,14 +130,35 @@ const GLOBAL_FRAME = Zcl.Frame.create(
GLOBAL_HEADER.manufacturerCode,
GLOBAL_HEADER.transactionSequenceNumber,
GLOBAL_HEADER.commandIdentifier,
Zcl.Foundation.read.ID,
Zcl.Clusters.genBasic.ID,
[{attrId: 256}] /*payload*/,
{} /*custom clusters*/,
GLOBAL_HEADER.frameControl.reservedBits,
);
const GLOBAL_FRAME_BUFFER = Buffer.concat([GLOBAL_HEADER_BUFFER, Buffer.from(uint16To8Array(256))]);
const GLOBAL_FRAME_STRING = `{"header":{"frameControl":{"reservedBits":0,"frameType":0,"direction":0,"disableDefaultResponse":false,"manufacturerSpecific":false},"transactionSequenceNumber":123,"commandIdentifier":0},"payload":[{"attrId":256}],"command":{"ID":0,"name":"read","parameters":[{"name":"attrId","type":33}],"response":1}}`;

/** Frame of Global type with BigInt */
const GLOBAL_FRAME_BIG_INT = Zcl.Frame.create(
GLOBAL_HEADER_REPORT.frameControl.frameType,
GLOBAL_HEADER_REPORT.frameControl.direction,
GLOBAL_HEADER_REPORT.frameControl.disableDefaultResponse,
GLOBAL_HEADER_REPORT.manufacturerCode,
GLOBAL_HEADER_REPORT.transactionSequenceNumber,
GLOBAL_HEADER_REPORT.commandIdentifier,
Zcl.Clusters.haApplianceIdentification.ID,
[{attrId: 0, dataType: Zcl.DataType.UINT56, attrData: 200n}] /*payload*/,
{} /*custom clusters*/,
GLOBAL_HEADER_REPORT.frameControl.reservedBits,
);
const GLOBAL_FRAME_BIG_INT_BUFFER = Buffer.concat([
GLOBAL_HEADER_REPORT_BUFFER,
Buffer.from(uint16To8Array(0)),
Buffer.from([Zcl.DataType.UINT56]),
Buffer.from(uint56To8Array(200n)),
]);
const GLOBAL_FRAME_BIG_INT_STRING = `{"header":{"frameControl":{"reservedBits":0,"frameType":0,"direction":0,"disableDefaultResponse":false,"manufacturerSpecific":false},"transactionSequenceNumber":123,"commandIdentifier":10},"payload":[{"attrId":0,"dataType":38,"attrData":"200"}],"command":{"ID":10,"name":"report","parameters":[{"name":"attrId","type":33},{"name":"dataType","type":32},{"name":"attrData","type":1000}]}}`;

/** Frame of Global type and response command */
const GLOBAL_RSP_FRAME = Zcl.Frame.create(
GLOBAL_RSP_HEADER.frameControl.frameType,
Expand All @@ -131,7 +167,7 @@ const GLOBAL_RSP_FRAME = Zcl.Frame.create(
GLOBAL_RSP_HEADER.manufacturerCode,
GLOBAL_RSP_HEADER.transactionSequenceNumber,
GLOBAL_RSP_HEADER.commandIdentifier,
Zcl.Foundation.readRsp.ID,
Zcl.Clusters.genPowerCfg.ID,
[{attrId: 256, status: Zcl.Status.SUCCESS, dataType: Zcl.DataType.ENUM8, attrData: 127}] /*payload*/,
{} /*custom clusters*/,
GLOBAL_RSP_HEADER.frameControl.reservedBits,
Expand All @@ -150,7 +186,7 @@ const GLOBAL_FRAME_NO_PAYLOAD = Zcl.Frame.create(
GLOBAL_HEADER.manufacturerCode,
GLOBAL_HEADER.transactionSequenceNumber,
GLOBAL_HEADER.commandIdentifier,
Zcl.Foundation.read.ID,
Zcl.Clusters.genBasic.ID,
[] /*payload*/,
{} /*custom clusters*/,
GLOBAL_HEADER.frameControl.reservedBits,
Expand All @@ -166,7 +202,7 @@ const GLOBAL_CONDITION_FRAME = Zcl.Frame.create(
GLOBAL_CONDITION_HEADER.manufacturerCode,
GLOBAL_CONDITION_HEADER.transactionSequenceNumber,
GLOBAL_CONDITION_HEADER.commandIdentifier,
Zcl.Foundation.configReport.ID,
Zcl.Clusters.genOnOff.ID,
[{direction: Zcl.Direction.SERVER_TO_CLIENT, attrId: 256, timeout: 10000}] /*payload*/,
{} /*custom clusters*/,
GLOBAL_CONDITION_HEADER.frameControl.reservedBits,
Expand Down Expand Up @@ -466,6 +502,11 @@ describe('ZCL Frame', () => {

it.each([
['global', GLOBAL_FRAME, {string: GLOBAL_FRAME_STRING, header: GLOBAL_HEADER, written: GLOBAL_FRAME_BUFFER}],
[
'global BigInt',
GLOBAL_FRAME_BIG_INT,
{string: GLOBAL_FRAME_BIG_INT_STRING, header: GLOBAL_HEADER_REPORT, written: GLOBAL_FRAME_BIG_INT_BUFFER},
],
['global response', GLOBAL_RSP_FRAME, {string: GLOBAL_RSP_FRAME_STRING, header: GLOBAL_RSP_HEADER, written: GLOBAL_RSP_FRAME_BUFFER}],
[
'global no payload',
Expand Down

0 comments on commit d760eb3

Please sign in to comment.