From 23885b73340c96d9a6c3221b66484abfa814c8b8 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Thu, 26 Dec 2024 12:27:17 -0600 Subject: [PATCH] add encoding --- packages/ddp/src/index.ts | 65 +++++++++++++++++++++++++++++++ packages/ddp/tests/encode.test.js | 31 ++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/packages/ddp/src/index.ts b/packages/ddp/src/index.ts index 9e2bde3..f94bde5 100644 --- a/packages/ddp/src/index.ts +++ b/packages/ddp/src/index.ts @@ -114,3 +114,68 @@ export function decode(bytes: Uint8Array): DDPPacket { data: bytes.subarray(dataStart), }; } + +export function encode(packet: DDPPacket): Uint8Array { + let flagByte = packet.header.flags.version << 6; + + let headerLength = 10; + + if (packet.header.flags.timecode) { + flagByte += 16; + headerLength = 14; + } + + if (packet.header.flags.storage) { + flagByte += 8; + } + if (packet.header.flags.reply) { + flagByte += 4; + } + if (packet.header.flags.query) { + flagByte += 2; + } + if (packet.header.flags.push) { + flagByte += 1; + } + + let dataTypeByte = 0; + + if (!packet.header.dataType.standard) { + dataTypeByte += 128; + } + + dataTypeByte += packet.header.dataType.type << 3; + + if (packet.header.dataType.bitsPerPixel === 1) { + dataTypeByte += 1; + } else if (packet.header.dataType.bitsPerPixel === 4) { + dataTypeByte += 2; + } else if (packet.header.dataType.bitsPerPixel === 8) { + dataTypeByte += 3; + } else if (packet.header.dataType.bitsPerPixel === 16) { + dataTypeByte += 4; + } else if (packet.header.dataType.bitsPerPixel === 24) { + dataTypeByte += 5; + } else if (packet.header.dataType.bitsPerPixel === 32) { + dataTypeByte += 6; + } else if (packet.header.dataType.bitsPerPixel === 0) { + dataTypeByte += 0; + } else { + throw new Error('DDP packet has unsupported bits per pixel value'); + } + + const bytes = new Uint8Array(headerLength); + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + + view.setUint8(0, flagByte); + view.setUint8(1, packet.header.sequenceNumber); + view.setUint8(2, dataTypeByte); + view.setUint8(3, packet.header.sourceOrDestinationID); + view.setUint32(4, packet.header.dataOffset); + view.setUint16(8, packet.header.dataLength); + + // const bytes = new Uint8Array([flagByte, sequenceNumberByte, dataTypeByte, packet.header.sourceOrDestinationID]) + const headerBytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength); + + return new Uint8Array([...headerBytes, ...packet.data]); +} diff --git a/packages/ddp/tests/encode.test.js b/packages/ddp/tests/encode.test.js index 3bea32c..ad0b792 100644 --- a/packages/ddp/tests/encode.test.js +++ b/packages/ddp/tests/encode.test.js @@ -2,14 +2,41 @@ const { deepEqual, throws } = require('assert'); const { describe, it } = require('node:test'); const ddp = require('../dist/cjs/index'); -const goodTests = []; +const goodTests = [ + { + description: 'simple DDP packet', + expected: new Uint8Array([0x40, 0x0f, 0x92, 0x01, 0x45, 0x67, 0x89, 0x10, 0x10, 0x11]), + packet: { + header: { + flags: { + version: 1, + timecode: false, + storage: false, + reply: false, + query: false, + push: false, + }, + sequenceNumber: 15, + dataType: { + standard: false, + type: 2, + bitsPerPixel: 4, + }, + sourceOrDestinationID: 1, + dataOffset: 1164413200, + dataLength: 4113, + }, + data: new Uint8Array([]), + }, + }, +]; const badTests = []; describe('DDP Message Encoding Pass', () => { goodTests.forEach((messageTest) => { it(messageTest.description, () => { - const encoded = ddp.encode(messageTest.message); + const encoded = ddp.encode(messageTest.packet); deepEqual(encoded, messageTest.expected); }); });