![JAR search and dependency download from the Maven repository](/logo.png)
node_modules.mqtt-packet.parser.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of libjoynr-js Show documentation
Show all versions of libjoynr-js Show documentation
JOYnr JavaScript libjoynr-js
'use strict'
var bl = require('bl')
var inherits = require('inherits')
var EE = require('events').EventEmitter
var Packet = require('./packet')
var constants = require('./constants')
function Parser () {
if (!(this instanceof Parser)) return new Parser()
this._states = [
'_parseHeader',
'_parseLength',
'_parsePayload',
'_newPacket'
]
this._resetState()
}
inherits(Parser, EE)
Parser.prototype._resetState = function () {
this.packet = new Packet()
this.error = null
this._list = bl()
this._stateCounter = 0
}
Parser.prototype.parse = function (buf) {
if (this.error) this._resetState()
this._list.append(buf)
while ((this.packet.length !== -1 || this._list.length > 0) &&
this[this._states[this._stateCounter]]() &&
!this.error) {
this._stateCounter++
if (this._stateCounter >= this._states.length) this._stateCounter = 0
}
return this._list.length
}
Parser.prototype._parseHeader = function () {
// There is at least one byte in the buffer
var zero = this._list.readUInt8(0)
this.packet.cmd = constants.types[zero >> constants.CMD_SHIFT]
this.packet.retain = (zero & constants.RETAIN_MASK) !== 0
this.packet.qos = (zero >> constants.QOS_SHIFT) & constants.QOS_MASK
this.packet.dup = (zero & constants.DUP_MASK) !== 0
this._list.consume(1)
return true
}
Parser.prototype._parseLength = function () {
// There is at least one byte in the list
var bytes = 0
var mul = 1
var length = 0
var result = true
var current
while (bytes < 5) {
current = this._list.readUInt8(bytes++)
length += mul * (current & constants.LENGTH_MASK)
mul *= 0x80
if ((current & constants.LENGTH_FIN_MASK) === 0) break
if (this._list.length <= bytes) {
result = false
break
}
}
if (result) {
this.packet.length = length
this._list.consume(bytes)
}
return result
}
Parser.prototype._parsePayload = function () {
var result = false
// Do we have a payload? Do we have enough data to complete the payload?
// PINGs have no payload
if (this.packet.length === 0 || this._list.length >= this.packet.length) {
this._pos = 0
switch (this.packet.cmd) {
case 'connect':
this._parseConnect()
break
case 'connack':
this._parseConnack()
break
case 'publish':
this._parsePublish()
break
case 'puback':
case 'pubrec':
case 'pubrel':
case 'pubcomp':
this._parseMessageId()
break
case 'subscribe':
this._parseSubscribe()
break
case 'suback':
this._parseSuback()
break
case 'unsubscribe':
this._parseUnsubscribe()
break
case 'unsuback':
this._parseUnsuback()
break
case 'pingreq':
case 'pingresp':
case 'disconnect':
// These are empty, nothing to do
break
default:
this._emitError(new Error('Not supported'))
}
result = true
}
return result
}
Parser.prototype._parseConnect = function () {
var protocolId // Protocol ID
var clientId // Client ID
var topic // Will topic
var payload // Will payload
var password // Password
var username // Username
var flags = {}
var packet = this.packet
// Parse protocolId
protocolId = this._parseString()
if (protocolId === null) return this._emitError(new Error('Cannot parse protocolId'))
if (protocolId !== 'MQTT' && protocolId !== 'MQIsdp') {
return this._emitError(new Error('Invalid protocolId'))
}
packet.protocolId = protocolId
// Parse constants version number
if (this._pos >= this._list.length) return this._emitError(new Error('Packet too short'))
packet.protocolVersion = this._list.readUInt8(this._pos)
if (packet.protocolVersion !== 3 && packet.protocolVersion !== 4) {
return this._emitError(new Error('Invalid protocol version'))
}
this._pos++
if (this._pos >= this._list.length) {
return this._emitError(new Error('Packet too short'))
}
// Parse connect flags
flags.username = (this._list.readUInt8(this._pos) & constants.USERNAME_MASK)
flags.password = (this._list.readUInt8(this._pos) & constants.PASSWORD_MASK)
flags.will = (this._list.readUInt8(this._pos) & constants.WILL_FLAG_MASK)
if (flags.will) {
packet.will = {}
packet.will.retain = (this._list.readUInt8(this._pos) & constants.WILL_RETAIN_MASK) !== 0
packet.will.qos = (this._list.readUInt8(this._pos) &
constants.WILL_QOS_MASK) >> constants.WILL_QOS_SHIFT
}
packet.clean = (this._list.readUInt8(this._pos) & constants.CLEAN_SESSION_MASK) !== 0
this._pos++
// Parse keepalive
packet.keepalive = this._parseNum()
if (packet.keepalive === -1) return this._emitError(new Error('Packet too short'))
// Parse clientId
clientId = this._parseString()
if (clientId === null) return this._emitError(new Error('Packet too short'))
packet.clientId = clientId
if (flags.will) {
// Parse will topic
topic = this._parseString()
if (topic === null) return this._emitError(new Error('Cannot parse will topic'))
packet.will.topic = topic
// Parse will payload
payload = this._parseBuffer()
if (payload === null) return this._emitError(new Error('Cannot parse will payload'))
packet.will.payload = payload
}
// Parse username
if (flags.username) {
username = this._parseString()
if (username === null) return this._emitError(new Error('Cannot parse username'))
packet.username = username
}
// Parse password
if (flags.password) {
password = this._parseBuffer()
if (password === null) return this._emitError(new Error('Cannot parse password'))
packet.password = password
}
return packet
}
Parser.prototype._parseConnack = function () {
var packet = this.packet
if (this._list.length < 2) return null
packet.sessionPresent = !!(this._list.readUInt8(this._pos++) & constants.SESSIONPRESENT_MASK)
packet.returnCode = this._list.readUInt8(this._pos)
if (packet.returnCode === -1) return this._emitError(new Error('Cannot parse return code'))
}
Parser.prototype._parsePublish = function () {
var packet = this.packet
packet.topic = this._parseString()
if (packet.topic === null) return this._emitError(new Error('Cannot parse topic'))
// Parse messageId
if (packet.qos > 0) if (!this._parseMessageId()) { return }
packet.payload = this._list.slice(this._pos, packet.length)
}
Parser.prototype._parseSubscribe = function () {
var packet = this.packet
var topic
var qos
if (packet.qos !== 1) {
return this._emitError(new Error('Wrong subscribe header'))
}
packet.subscriptions = []
if (!this._parseMessageId()) { return }
while (this._pos < packet.length) {
// Parse topic
topic = this._parseString()
if (topic === null) return this._emitError(new Error('Cannot parse topic'))
qos = this._list.readUInt8(this._pos++)
// Push pair to subscriptions
packet.subscriptions.push({ topic: topic, qos: qos })
}
}
Parser.prototype._parseSuback = function () {
this.packet.granted = []
if (!this._parseMessageId()) { return }
// Parse granted QoSes
while (this._pos < this.packet.length) {
this.packet.granted.push(this._list.readUInt8(this._pos++))
}
}
Parser.prototype._parseUnsubscribe = function () {
var packet = this.packet
packet.unsubscriptions = []
// Parse messageId
if (!this._parseMessageId()) { return }
while (this._pos < packet.length) {
var topic
// Parse topic
topic = this._parseString()
if (topic === null) return this._emitError(new Error('Cannot parse topic'))
// Push topic to unsubscriptions
packet.unsubscriptions.push(topic)
}
}
Parser.prototype._parseUnsuback = function () {
if (!this._parseMessageId()) return this._emitError(new Error('Cannot parse messageId'))
}
Parser.prototype._parseMessageId = function () {
var packet = this.packet
packet.messageId = this._parseNum()
if (packet.messageId === null) {
this._emitError(new Error('Cannot parse messageId'))
return false
}
return true
}
Parser.prototype._parseString = function (maybeBuffer) {
var length = this._parseNum()
var result
var end = length + this._pos
if (length === -1 || end > this._list.length || end > this.packet.length) return null
result = this._list.toString('utf8', this._pos, end)
this._pos += length
return result
}
Parser.prototype._parseBuffer = function () {
var length = this._parseNum()
var result
var end = length + this._pos
if (length === -1 || end > this._list.length || end > this.packet.length) return null
result = this._list.slice(this._pos, end)
this._pos += length
return result
}
Parser.prototype._parseNum = function () {
if (this._list.length - this._pos < 2) return -1
var result = this._list.readUInt16BE(this._pos)
this._pos += 2
return result
}
Parser.prototype._newPacket = function () {
if (this.packet) {
this._list.consume(this.packet.length)
this.emit('packet', this.packet)
}
this.packet = new Packet()
return true
}
Parser.prototype._emitError = function (err) {
this.error = err
this.emit('error', err)
}
module.exports = Parser
© 2015 - 2025 Weber Informatics LLC | Privacy Policy