@seriousme/opifex
Version:
MQTT client & server for Deno & NodeJS
116 lines • 4.63 kB
JavaScript
import { PacketType } from "./PacketType.js";
import { BitMask } from "./BitMask.js";
import { Encoder } from "./encoder.js";
import { booleanFlag, Decoder, DecoderError, hasEmptyFlags, } from "./decoder.js";
function invalidProtocolName(version, name) {
if (version === 4 && name !== "MQTT") {
return true;
}
return false;
}
export const connect = {
encode(packet) {
const flags = 0;
const protocolLevel = 4;
const protocolName = protocolLevel === 4 ? "MQTT" : "MQIsdp";
const clientId = packet.clientId || "";
const usernameFlag = !!packet.username;
const passwordFlag = !!packet.password;
const willRetain = !!packet.will?.retain;
const willQoS = packet.will?.qos || 0;
const willFlag = !!packet.will;
const cleanSession = packet.clean !== false;
const connectFlags = (usernameFlag ? BitMask.bit7 : 0) +
(passwordFlag ? BitMask.bit6 : 0) +
(willRetain ? BitMask.bit5 : 0) +
(willQoS & 2 ? BitMask.bit4 : 0) +
(willQoS & 1 ? BitMask.bit3 : 0) +
(willFlag ? BitMask.bit2 : 0) +
(cleanSession ? BitMask.bit1 : 0);
const keepAlive = packet.keepAlive || 0;
const encoder = new Encoder();
encoder
.setUtf8String(protocolName)
.setByte(protocolLevel)
.setByte(connectFlags)
.setInt16(keepAlive)
.setUtf8String(clientId);
if (packet.will) {
encoder.setTopic(packet.will.topic).setByteArray(packet.will.payload);
}
if (packet.username) {
encoder.setUtf8String(packet.username);
}
if (packet.password) {
encoder.setByteArray(packet.password);
}
return { flags, bytes: encoder.done() };
},
decode(buffer, flags) {
const decoder = new Decoder(buffer);
const protocolName = decoder.getUtf8String();
const protocolLevel = decoder.getByte();
if (invalidProtocolName(protocolLevel, protocolName)) {
throw new DecoderError("Invalid protocol name");
}
const connectFlags = decoder.getByte();
const usernameFlag = booleanFlag(connectFlags, BitMask.bit7);
const passwordFlag = booleanFlag(connectFlags, BitMask.bit6);
const willRetain = booleanFlag(connectFlags, BitMask.bit5);
const willQoS = (connectFlags & (BitMask.bit4 + BitMask.bit3)) >> 3;
const willFlag = booleanFlag(connectFlags, BitMask.bit2);
const cleanSession = booleanFlag(connectFlags, BitMask.bit1);
const reservedBit = booleanFlag(connectFlags, BitMask.bit0);
hasEmptyFlags(flags);
// The Server MUST validate that the reserved flag in the CONNECT Control Packet
// is set to zero and disconnect the Client if it is not zero [MQTT-3.1.2-3].
if (reservedBit) {
throw new DecoderError("Invalid reserved bit");
}
if (willQoS !== 0 && willQoS !== 1 && willQoS !== 2) {
throw new DecoderError("Invalid will qos");
}
const keepAlive = decoder.getInt16();
const clientId = decoder.getUtf8String();
let willTopic;
let willPayload;
if (willFlag) {
willTopic = decoder.getTopic();
willPayload = decoder.getByteArray();
}
let username;
let password;
if (usernameFlag) {
username = decoder.getUtf8String();
}
if (passwordFlag) {
password = decoder.getByteArray();
}
decoder.done();
if (!willFlag && (willQoS !== 0 || willRetain === true)) {
throw new DecoderError("Will QoS must be 0 and Will retain to false when Will flag is false");
}
if (clientId.length === 0 && cleanSession === false) {
throw new DecoderError("Clean session must be true if clientID is empty");
}
return {
type: PacketType.connect,
protocolName: protocolName,
protocolLevel,
clientId: clientId,
username: username ? username : undefined,
password: password ? password : undefined,
will: willFlag
? {
topic: willTopic || "",
payload: willPayload || Uint8Array.from([0]),
retain: willRetain,
qos: willQoS,
}
: undefined,
clean: cleanSession,
keepAlive,
};
},
};
//# sourceMappingURL=connect.js.map