import type { CodecOpts, PacketId } from "./types.ts"; import type { ProtocolLevelNoV5 } from "./protocolLevels.ts"; import { ReasonCode } from "./ReasonCode.ts"; import type { PubackProperties } from "./Properties.ts"; import { PacketType } from "./PacketType.ts"; import { Decoder, DecoderError } from "./decoder.ts"; import { Encoder } from "./encoder.ts"; export type AckPacketV4 = { type: T; protocolLevel: ProtocolLevelNoV5; id: PacketId; }; export type AckPacketV5 = { type: T; protocolLevel: 5; id: PacketId; reasonCode?: ReasonCode; properties?: PubackProperties; }; /** * all 4 ack packets are identical except for packet type and flags of Pubrel */ export type AckPacket = AckPacketV4 | AckPacketV5; /** * PubackPacket is sent to indicate publish complete (QoS 1) */ export type PubackPacket = AckPacket; /** * Pubrec is sent to indicate publish received (QoS 2) */ export type PubrecPacket = AckPacket; /** * Pubrel is sent to indicate publish release (QoS 2) */ export type PubrelPacket = AckPacket; /** * Pubcomp is sent to indicate publish complete (QoS 2) */ export type PubcompPacket = AckPacket; export type AnyAckPacket = | PubackPacket | PubrecPacket | PubrelPacket | PubcompPacket; export function encode(packet: AnyAckPacket, codecOpts: CodecOpts): Uint8Array { const flags = packet.type === PacketType.pubrel ? 2 : 0; const encoder = new Encoder(packet.type); encoder.setInt16(packet.id); if (packet.protocolLevel === 5) { const reasonCode = packet.reasonCode || ReasonCode.success; // if remaining length is less than 1 the value of 0x00 (success) is used. if ( reasonCode === ReasonCode.success && Object.keys(packet.properties || {}).length === 0 ) { return encoder.done(flags); } encoder.seReasonCode(reasonCode); encoder.setProperties( packet.properties || {}, packet.type, codecOpts.maxOutgoingPacketSize, ); } return encoder.done(flags); } export function decode( buffer: Uint8Array, flags: number, codecOpts: CodecOpts, packetType: PacketType, ): AnyAckPacket { const expectedFlags = packetType === PacketType.pubrel ? 2 : 0; if (flags !== expectedFlags) { throw new DecoderError("Invalid flags"); } const decoder = new Decoder(packetType, buffer); const id = decoder.getInt16(); if (codecOpts.protocolLevel !== 5) { decoder.done(); return { type: packetType as AnyAckPacket["type"], protocolLevel: codecOpts.protocolLevel, id, } as AnyAckPacket; } if (decoder.atEnd()) { return { type: packetType as AnyAckPacket["type"], protocolLevel: 5, id, reasonCode: 0, } as AnyAckPacket; } const reasonCode = decoder.geReasonCode(); const properties = decoder.getProperties(packetType); return { type: packetType as AnyAckPacket["type"], protocolLevel: 5, id, reasonCode, properties, } as AnyAckPacket; }