@seriousme/opifex
Version:
MQTT client & server for Deno & NodeJS
81 lines (68 loc) • 2.14 kB
text/typescript
import type { Payload, QoS, Topic, TPacketType } from "./types.ts";
import { PacketType } from "./PacketType.ts";
import { BitMask } from "./BitMask.ts";
import { Encoder, EncoderError } from "./encoder.ts";
import { booleanFlag, Decoder, DecoderError } from "./decoder.ts";
/**
* PublishPacket is used to send data from client to server and
* from server to subscribers
*/
export type PublishPacket = {
type: TPacketType;
topic: Topic;
payload: Payload;
dup?: boolean;
retain?: boolean;
qos?: QoS;
id?: number;
};
export const publish: {
encode(packet: PublishPacket): { flags: number; bytes: number[] };
decode(buffer: Uint8Array, flags: number): PublishPacket;
} = {
encode(packet: PublishPacket): { flags: number; bytes: number[] } {
const qos = packet.qos || 0;
const flags = (packet.dup ? BitMask.bit3 : 0) +
(qos & 2 ? BitMask.bit2 : 0) +
(qos & 1 ? BitMask.bit1 : 0) +
(packet.retain ? BitMask.bit0 : 0);
const encoder = new Encoder();
encoder.setTopic(packet.topic);
if (qos === 1 || qos === 2) {
if (typeof packet.id !== "number" || packet.id < 1) {
throw new EncoderError("when qos is 1 or 2, packet must have id");
}
encoder.setInt16(packet.id);
}
encoder.setRemainder(packet.payload);
return { flags, bytes: encoder.done() };
},
decode(buffer: Uint8Array, flags: number): PublishPacket {
const dup = booleanFlag(flags, BitMask.bit3);
const qos = (flags & 6) >> 1;
const retain = booleanFlag(flags, BitMask.bit0);
if (qos !== 0 && qos !== 1 && qos !== 2) {
throw new DecoderError("Invalid qos");
}
if (dup && qos === 0) {
throw new DecoderError("Invalid qos for possible duplicate");
}
const decoder = new Decoder(buffer);
const topic = decoder.getTopic();
let id = 0;
if (qos > 0) {
id = decoder.getInt16();
}
const payload = decoder.getRemainder();
// no decoder.done() required because of getRemainder
return {
type: PacketType.publish,
topic,
payload,
dup,
retain,
qos,
id,
};
},
};