You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
4.8 KiB
188 lines
4.8 KiB
'use strict' |
|
|
|
var Buffer = require('safe-buffer').Buffer |
|
|
|
/* Protocol - protocol constants */ |
|
var protocol = module.exports |
|
|
|
/* Command code => mnemonic */ |
|
protocol.types = { |
|
0: 'reserved', |
|
1: 'connect', |
|
2: 'connack', |
|
3: 'publish', |
|
4: 'puback', |
|
5: 'pubrec', |
|
6: 'pubrel', |
|
7: 'pubcomp', |
|
8: 'subscribe', |
|
9: 'suback', |
|
10: 'unsubscribe', |
|
11: 'unsuback', |
|
12: 'pingreq', |
|
13: 'pingresp', |
|
14: 'disconnect', |
|
15: 'auth' |
|
} |
|
|
|
/* Mnemonic => Command code */ |
|
protocol.codes = {} |
|
for (var k in protocol.types) { |
|
var v = protocol.types[k] |
|
protocol.codes[v] = k |
|
} |
|
|
|
/* Header */ |
|
protocol.CMD_SHIFT = 4 |
|
protocol.CMD_MASK = 0xF0 |
|
protocol.DUP_MASK = 0x08 |
|
protocol.QOS_MASK = 0x03 |
|
protocol.QOS_SHIFT = 1 |
|
protocol.RETAIN_MASK = 0x01 |
|
|
|
/* Length */ |
|
protocol.LENGTH_MASK = 0x7F |
|
protocol.LENGTH_FIN_MASK = 0x80 |
|
|
|
/* Connack */ |
|
protocol.SESSIONPRESENT_MASK = 0x01 |
|
protocol.SESSIONPRESENT_HEADER = Buffer.from([protocol.SESSIONPRESENT_MASK]) |
|
protocol.CONNACK_HEADER = Buffer.from([protocol.codes['connack'] << protocol.CMD_SHIFT]) |
|
|
|
/* Connect */ |
|
protocol.USERNAME_MASK = 0x80 |
|
protocol.PASSWORD_MASK = 0x40 |
|
protocol.WILL_RETAIN_MASK = 0x20 |
|
protocol.WILL_QOS_MASK = 0x18 |
|
protocol.WILL_QOS_SHIFT = 3 |
|
protocol.WILL_FLAG_MASK = 0x04 |
|
protocol.CLEAN_SESSION_MASK = 0x02 |
|
protocol.CONNECT_HEADER = Buffer.from([protocol.codes['connect'] << protocol.CMD_SHIFT]) |
|
|
|
/* Properties */ |
|
protocol.properties = { |
|
sessionExpiryInterval: 17, |
|
willDelayInterval: 24, |
|
receiveMaximum: 33, |
|
maximumPacketSize: 39, |
|
topicAliasMaximum: 34, |
|
requestResponseInformation: 25, |
|
requestProblemInformation: 23, |
|
userProperties: 38, |
|
authenticationMethod: 21, |
|
authenticationData: 22, |
|
payloadFormatIndicator: 1, |
|
messageExpiryInterval: 2, |
|
contentType: 3, |
|
responseTopic: 8, |
|
correlationData: 9, |
|
maximumQoS: 36, |
|
retainAvailable: 37, |
|
assignedClientIdentifier: 18, |
|
reasonString: 31, |
|
wildcardSubscriptionAvailable: 40, |
|
subscriptionIdentifiersAvailable: 41, |
|
sharedSubscriptionAvailable: 42, |
|
serverKeepAlive: 19, |
|
responseInformation: 26, |
|
serverReference: 28, |
|
topicAlias: 35, |
|
subscriptionIdentifier: 11 |
|
} |
|
protocol.propertiesCodes = {} |
|
for (var prop in protocol.properties) { |
|
var id = protocol.properties[prop] |
|
protocol.propertiesCodes[id] = prop |
|
} |
|
protocol.propertiesTypes = { |
|
sessionExpiryInterval: 'int32', |
|
willDelayInterval: 'int32', |
|
receiveMaximum: 'int16', |
|
maximumPacketSize: 'int32', |
|
topicAliasMaximum: 'int16', |
|
requestResponseInformation: 'byte', |
|
requestProblemInformation: 'byte', |
|
userProperties: 'pair', |
|
authenticationMethod: 'string', |
|
authenticationData: 'binary', |
|
payloadFormatIndicator: 'byte', |
|
messageExpiryInterval: 'int32', |
|
contentType: 'string', |
|
responseTopic: 'string', |
|
correlationData: 'binary', |
|
maximumQoS: 'int8', |
|
retainAvailable: 'byte', |
|
assignedClientIdentifier: 'string', |
|
reasonString: 'string', |
|
wildcardSubscriptionAvailable: 'byte', |
|
subscriptionIdentifiersAvailable: 'byte', |
|
sharedSubscriptionAvailable: 'byte', |
|
serverKeepAlive: 'int16', |
|
responseInformation: 'string', |
|
serverReference: 'string', |
|
topicAlias: 'int16', |
|
subscriptionIdentifier: 'var' |
|
} |
|
|
|
function genHeader (type) { |
|
return [0, 1, 2].map(function (qos) { |
|
return [0, 1].map(function (dup) { |
|
return [0, 1].map(function (retain) { |
|
var buf = new Buffer(1) |
|
buf.writeUInt8( |
|
protocol.codes[type] << protocol.CMD_SHIFT | |
|
(dup ? protocol.DUP_MASK : 0) | |
|
qos << protocol.QOS_SHIFT | retain, 0, true) |
|
return buf |
|
}) |
|
}) |
|
}) |
|
} |
|
|
|
/* Publish */ |
|
protocol.PUBLISH_HEADER = genHeader('publish') |
|
|
|
/* Subscribe */ |
|
protocol.SUBSCRIBE_HEADER = genHeader('subscribe') |
|
protocol.SUBSCRIBE_OPTIONS_QOS_MASK = 0x03 |
|
protocol.SUBSCRIBE_OPTIONS_NL_MASK = 0x01 |
|
protocol.SUBSCRIBE_OPTIONS_NL_SHIFT = 2 |
|
protocol.SUBSCRIBE_OPTIONS_RAP_MASK = 0x01 |
|
protocol.SUBSCRIBE_OPTIONS_RAP_SHIFT = 3 |
|
protocol.SUBSCRIBE_OPTIONS_RH_MASK = 0x03 |
|
protocol.SUBSCRIBE_OPTIONS_RH_SHIFT = 4 |
|
protocol.SUBSCRIBE_OPTIONS_RH = [0x00, 0x10, 0x20] |
|
protocol.SUBSCRIBE_OPTIONS_NL = 0x04 |
|
protocol.SUBSCRIBE_OPTIONS_RAP = 0x08 |
|
protocol.SUBSCRIBE_OPTIONS_QOS = [0x00, 0x01, 0x02] |
|
|
|
/* Unsubscribe */ |
|
protocol.UNSUBSCRIBE_HEADER = genHeader('unsubscribe') |
|
|
|
/* Confirmations */ |
|
protocol.ACKS = { |
|
unsuback: genHeader('unsuback'), |
|
puback: genHeader('puback'), |
|
pubcomp: genHeader('pubcomp'), |
|
pubrel: genHeader('pubrel'), |
|
pubrec: genHeader('pubrec') |
|
} |
|
|
|
protocol.SUBACK_HEADER = Buffer.from([protocol.codes['suback'] << protocol.CMD_SHIFT]) |
|
|
|
/* Protocol versions */ |
|
protocol.VERSION3 = Buffer.from([3]) |
|
protocol.VERSION4 = Buffer.from([4]) |
|
protocol.VERSION5 = Buffer.from([5]) |
|
|
|
/* QoS */ |
|
protocol.QOS = [0, 1, 2].map(function (qos) { |
|
return Buffer.from([qos]) |
|
}) |
|
|
|
/* Empty packets */ |
|
protocol.EMPTY = { |
|
pingreq: Buffer.from([protocol.codes['pingreq'] << 4, 0]), |
|
pingresp: Buffer.from([protocol.codes['pingresp'] << 4, 0]), |
|
disconnect: Buffer.from([protocol.codes['disconnect'] << 4, 0]) |
|
}
|
|
|