Closed oligriffiths closed 1 month ago
Hi Oli, Sorry for the late reply. Was busy with home problems... Yes, I still developing this project. But I fully concentrated on UI part on the internal company users. Let me release a new version of the artnet-lib, where I separate protocol packets into separate package. Please let me know if this issue still relevant for you. If you have any questions and suggestions please fill free to ask me.
I've moved all packets to separate package: "@rtf-dm/artnet-packets" now you can use it as :
npm i @rtf-dm/artnet-packets;
import {DmxPacket} from "@rtf-dm/artnet-packets";
import {SyncPacket} from "@rtf-dm/artnet-packets";
const dmxPacket = new DmxPacket({
net: 1,
subNet: 2,
length: 10,
dmxData: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
]
});
const buffer = dmxPacket.encode();
const payload = dmxPacket.decode(buffer)
@rize-the-flag Amazing thank you. Is there a utility to pass in the incoming data packet and have it decoded to whichever packet type it corresponds to?
@oligriffiths I think you are talking about @rtf-dm/protocol package. It allows you to create any packets definition with encode/decode functionality.
1) install package
npm i @rtf-dm/protocol
2) Describe type of your packet payload:
type TestPacketPayload = {
ID: string,
opCode: number,
foo: number,
bar: number[]
}
3) create a class which is extends abstract class Packet
class TestPacket extends Packet<TestPacketPayload> {
constructor(payload: Partial<TestPacketPayload>) {
const schema: PacketSchemaPublic<TestPacketPayload> = [
['opCode', {length: 2, type: 'number', byteOrder: 'LE'}],
['ID', {length: 4, type: 'string'}],
['foo', {length: 2, type: 'number', byteOrder: 'BE'}],
['bar', {length: 10, type: 'array'}]
];
const testPacketPayload: TestPacketPayload = {
ID: "Test",
opCode: 0xFA,
foo: 20,
bar: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
...payload
}
super(testPacketPayload, schema);
}
}
4) Describe the packet schema and initial payload
const schema: PacketSchemaPublic<TestPacketPayload> = [
['opCode', {length: 2, type: 'number', byteOrder: 'LE'}],
['ID', {length: 4, type: 'string'}],
['foo', {length: 2, type: 'number', byteOrder: 'BE'}],
['bar', {length: 10, type: 'array'}]
];
const testPacketPayload: TestPacketPayload = {
ID: "Test",
opCode: 0xFA,
foo: 20,
bar: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
...payload
}
5) Use Your packet
const packet = new TestPacket({
foo: 10,
bar: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
});
const buf = packet.encode();
const payload = packet.decode(buf);
console.log(payload.ID);
console.log(payload.opCode);
console.log(payload.bar);
console.log(payload.foo);
Ah perhaps I wasn't clear.
I am referring to incoming UDP packets and decoding them via a single function that returns the relevant class instance.
This function called decode, it construct payload object by schema. However construction a relevant class is little bit more complex problem.
Reasons:
You can use
export function decode<TPayload extends PacketPayload>(
buffer: Buffer,
schema: Schema<TPayload>,
): TPayload
One of possible solution is to add some kind of static factory method e.g. make to each packet. Check if UDP packet has valid ID/opCode and than just create new packet.
type TestPayload = {
ID: string,
opCode: number
}
class TestPacket extends Packet<TestPayload> {
public static schemaDefault: PacketSchemaPublic<TestPayload> = [
['ID', {length: 4, type: "string", byteOrder: 'LE'}],
['opCode', {length: 2, type: "number", byteOrder: 'BE'}]
]
constructor(payload: TestPayload) {
super(payload, TestPacket.schemaDefault);
}
static isTestPacket(data: Buffer) {
return data.subarray(0, 4).toString() === 'TEST'
}
static make(data: Buffer, schema: PacketSchemaPublic<TestPayload> = TestPacket.schemaDefault) {
return new TestPacket(decode(data, new Schema<TestPayload>(schema)));
}
}
const packet1 = new TestPacket({
ID: 'TEST',
opCode: 42
});
const data = packet1.encode(); // recieved UDP packet
if (TestPacket.isTestPacket(data)) { // check if entire data is TestPacket
const packet = TestPacket.make(data) // build test packet using default packet schema
}
I want to say that instantiatiation of a concrete packet depends on many factors (protocol rules, project needs e.t.c.) and it's not obvious for me how to develop a good generic interface for such functionality. This should be done on client side of library. However i open for suggestions =)
Hi
This is nice project are you still developing it?
Would you consider breaking out the artnet packets into a separate package? I am building my own artnet relay and have been using the packets from this project, but I have to import them using:
Which is a bit cumbersome.
Thoughts?