Skip to content

Commit 3c5a09f

Browse files
committed
feat: 🎸 add suback packet
1 parent b712c0e commit 3c5a09f

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

‎src/MqttDecoder.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {PacketPubrec, parsePubrec} from './packets/pubrec';
88
import {PacketPubrel, parsePubrel} from './packets/pubrel';
99
import {PacketPubcomp, parsePubcomp} from './packets/pubcomp';
1010
import {PacketSubscribe, parseSubscribe} from './packets/subscribe';
11+
import {PacketSuback, parseSuback} from './packets/suback';
1112

1213
export class MqttDecoder {
1314
public state: DECODER_STATE = DECODER_STATE.HEADER;
@@ -35,7 +36,7 @@ export class MqttDecoder {
3536
this.list = new BufferList();
3637
}
3738

38-
public parse(): null | PacketConnect | PacketConnack | PacketPublish | PacketPuback | PacketPubrec | PacketPubrel | PacketPubcomp | PacketSubscribe {
39+
public parse(): null | PacketConnect | PacketConnack | PacketPublish | PacketPuback | PacketPubrec | PacketPubrel | PacketPubcomp | PacketSubscribe | PacketSuback {
3940
this.parseFixedHeader();
4041
const data = this.parseVariableData();
4142
if (!data) return null;
@@ -50,9 +51,6 @@ export class MqttDecoder {
5051
case PACKET_TYPE.CONNACK: {
5152
return parseConnack(b, l, data, this.version);
5253
}
53-
case PACKET_TYPE.SUBACK: {
54-
return null;
55-
}
5654
case PACKET_TYPE.PUBLISH: {
5755
const packet = parsePublish(b, l, data, this.version);
5856
return packet;
@@ -77,6 +75,10 @@ export class MqttDecoder {
7775
const packet = parseSubscribe(b, l, data, this.version);
7876
return packet;
7977
}
78+
case PACKET_TYPE.SUBACK: {
79+
const packet = parseSuback(b, l, data, this.version);
80+
return packet;
81+
}
8082
default: {
8183
return null;
8284
}

‎src/__tests__/MqttDecoder.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {PacketPublish} from '../packets/publish';
77
import {PacketPuback} from '../packets/puback';
88
import {PacketPubrec} from '../packets/pubrec';
99
import {PacketSubscribe} from '../packets/subscribe';
10+
import { PacketSuback } from '../packets/suback';
1011

1112
it('can instantiate', () => {
1213
const decoder = new MqttDecoder();
@@ -479,3 +480,44 @@ describe('SUBSCRIBE', () => {
479480
expect(packet.s[2].retainHandling()).toBe(0);
480481
});
481482
});
483+
484+
describe('SUBACK', () => {
485+
it('parses MQTT 3.1.1 packet', () => {
486+
const decoder = new MqttDecoder();
487+
decoder.push(Buffer.from([
488+
144, 6, // Header
489+
0, 6, // Message ID
490+
0, 1, 2, 128 // Granted qos (0, 1, 2) and a rejected being 0x80
491+
]));
492+
const packet: PacketSuback = decoder.parse() as PacketSuback;
493+
expect(packet.b).toBe(144);
494+
expect(packet.l).toBe(6);
495+
expect(packet.i).toBe(6);
496+
expect(packet.p).toEqual({});
497+
expect(packet.s).toEqual([0, 1, 2, 128]);
498+
});
499+
500+
it('parses MQTT 5.0 packet', () => {
501+
const decoder = new MqttDecoder();
502+
decoder.version = 5;
503+
decoder.push(Buffer.from([
504+
144, 27, // Header
505+
0, 6, // Message ID
506+
20, // properties length
507+
31, 0, 4, 116, 101, 115, 116, // reasonString
508+
38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties
509+
0, 1, 2, 1 // Granted qos (0, 1, 2) and a rejected being 0x80
510+
]));
511+
const packet: PacketSuback = decoder.parse() as PacketSuback;
512+
expect(packet.b).toBe(144);
513+
expect(packet.l).toBe(27);
514+
expect(packet.i).toBe(6);
515+
expect(packet.p).toEqual({
516+
[PROPERTY.ReasonString]: 'test',
517+
[PROPERTY.UserProperty]: [
518+
['test', 'test'],
519+
],
520+
});
521+
expect(packet.s).toEqual([0, 1, 2, 1]);
522+
});
523+
});

‎src/packets/suback.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import BufferList from 'bl';
2+
import {Packet, PacketHeaderData} from '../packet';
3+
import {Properties} from '../types';
4+
import {parseProps} from '../util/parse';
5+
6+
export interface PacketSubackData extends PacketHeaderData {
7+
/** Packet Identifier. */
8+
i: number;
9+
/** Properties. */
10+
p: Properties;
11+
/** SUBACK Payload. */
12+
s: number[];
13+
}
14+
15+
export class PacketSuback extends Packet implements PacketSubackData {
16+
constructor(
17+
b: number,
18+
l: number,
19+
public i: number,
20+
public p: Properties,
21+
public s: number[],
22+
) {
23+
super(b, l);
24+
}
25+
}
26+
27+
export const parseSuback = (b: number, l: number, data: BufferList, version: number): PacketSuback => {
28+
const i = data.readUInt16BE(0);
29+
let offset = 2;
30+
let p: Properties = {};
31+
if (version === 5) {
32+
const [props, size] = parseProps(data, offset);
33+
p = props;
34+
offset += size;
35+
}
36+
const len = data.length;
37+
const s: number[] = [];
38+
while (offset < len) {
39+
s.push(data.readUInt8(offset++));
40+
}
41+
return new PacketSuback(b, l, i, p, s);
42+
};

0 commit comments

Comments
 (0)