UNPKG

7.82 kBJavaScriptView Raw
1/* Protocol - protocol constants */
2const protocol = module.exports
3
4/* Command code => mnemonic */
5protocol.types = {
6 0: 'reserved',
7 1: 'connect',
8 2: 'connack',
9 3: 'publish',
10 4: 'puback',
11 5: 'pubrec',
12 6: 'pubrel',
13 7: 'pubcomp',
14 8: 'subscribe',
15 9: 'suback',
16 10: 'unsubscribe',
17 11: 'unsuback',
18 12: 'pingreq',
19 13: 'pingresp',
20 14: 'disconnect',
21 15: 'auth'
22}
23
24protocol.requiredHeaderFlags = {
25 1: 0, // 'connect'
26 2: 0, // 'connack'
27 4: 0, // 'puback'
28 5: 0, // 'pubrec'
29 6: 2, // 'pubrel'
30 7: 0, // 'pubcomp'
31 8: 2, // 'subscribe'
32 9: 0, // 'suback'
33 10: 2, // 'unsubscribe'
34 11: 0, // 'unsuback'
35 12: 0, // 'pingreq'
36 13: 0, // 'pingresp'
37 14: 0, // 'disconnect'
38 15: 0 // 'auth'
39}
40
41protocol.requiredHeaderFlagsErrors = {}
42for (const k in protocol.requiredHeaderFlags) {
43 const v = protocol.requiredHeaderFlags[k]
44 protocol.requiredHeaderFlagsErrors[k] = 'Invalid header flag bits, must be 0x' + v.toString(16) + ' for ' + protocol.types[k] + ' packet'
45}
46
47/* Mnemonic => Command code */
48protocol.codes = {}
49for (const k in protocol.types) {
50 const v = protocol.types[k]
51 protocol.codes[v] = k
52}
53
54/* Header */
55protocol.CMD_SHIFT = 4
56protocol.CMD_MASK = 0xF0
57protocol.DUP_MASK = 0x08
58protocol.QOS_MASK = 0x03
59protocol.QOS_SHIFT = 1
60protocol.RETAIN_MASK = 0x01
61
62/* Length */
63protocol.VARBYTEINT_MASK = 0x7F
64protocol.VARBYTEINT_FIN_MASK = 0x80
65protocol.VARBYTEINT_MAX = 268435455
66
67/* Connack */
68protocol.SESSIONPRESENT_MASK = 0x01
69protocol.SESSIONPRESENT_HEADER = Buffer.from([protocol.SESSIONPRESENT_MASK])
70protocol.CONNACK_HEADER = Buffer.from([protocol.codes.connack << protocol.CMD_SHIFT])
71
72/* Connect */
73protocol.USERNAME_MASK = 0x80
74protocol.PASSWORD_MASK = 0x40
75protocol.WILL_RETAIN_MASK = 0x20
76protocol.WILL_QOS_MASK = 0x18
77protocol.WILL_QOS_SHIFT = 3
78protocol.WILL_FLAG_MASK = 0x04
79protocol.CLEAN_SESSION_MASK = 0x02
80protocol.CONNECT_HEADER = Buffer.from([protocol.codes.connect << protocol.CMD_SHIFT])
81
82/* Properties */
83protocol.properties = {
84 sessionExpiryInterval: 17,
85 willDelayInterval: 24,
86 receiveMaximum: 33,
87 maximumPacketSize: 39,
88 topicAliasMaximum: 34,
89 requestResponseInformation: 25,
90 requestProblemInformation: 23,
91 userProperties: 38,
92 authenticationMethod: 21,
93 authenticationData: 22,
94 payloadFormatIndicator: 1,
95 messageExpiryInterval: 2,
96 contentType: 3,
97 responseTopic: 8,
98 correlationData: 9,
99 maximumQoS: 36,
100 retainAvailable: 37,
101 assignedClientIdentifier: 18,
102 reasonString: 31,
103 wildcardSubscriptionAvailable: 40,
104 subscriptionIdentifiersAvailable: 41,
105 sharedSubscriptionAvailable: 42,
106 serverKeepAlive: 19,
107 responseInformation: 26,
108 serverReference: 28,
109 topicAlias: 35,
110 subscriptionIdentifier: 11
111}
112protocol.propertiesCodes = {}
113for (const prop in protocol.properties) {
114 const id = protocol.properties[prop]
115 protocol.propertiesCodes[id] = prop
116}
117protocol.propertiesTypes = {
118 sessionExpiryInterval: 'int32',
119 willDelayInterval: 'int32',
120 receiveMaximum: 'int16',
121 maximumPacketSize: 'int32',
122 topicAliasMaximum: 'int16',
123 requestResponseInformation: 'byte',
124 requestProblemInformation: 'byte',
125 userProperties: 'pair',
126 authenticationMethod: 'string',
127 authenticationData: 'binary',
128 payloadFormatIndicator: 'byte',
129 messageExpiryInterval: 'int32',
130 contentType: 'string',
131 responseTopic: 'string',
132 correlationData: 'binary',
133 maximumQoS: 'int8',
134 retainAvailable: 'byte',
135 assignedClientIdentifier: 'string',
136 reasonString: 'string',
137 wildcardSubscriptionAvailable: 'byte',
138 subscriptionIdentifiersAvailable: 'byte',
139 sharedSubscriptionAvailable: 'byte',
140 serverKeepAlive: 'int16',
141 responseInformation: 'string',
142 serverReference: 'string',
143 topicAlias: 'int16',
144 subscriptionIdentifier: 'var'
145}
146
147function genHeader (type) {
148 return [0, 1, 2].map(qos => {
149 return [0, 1].map(dup => {
150 return [0, 1].map(retain => {
151 const buf = Buffer.alloc(1)
152 buf.writeUInt8(
153 protocol.codes[type] << protocol.CMD_SHIFT |
154 (dup ? protocol.DUP_MASK : 0) |
155 qos << protocol.QOS_SHIFT | retain, 0, true)
156 return buf
157 })
158 })
159 })
160}
161
162/* Publish */
163protocol.PUBLISH_HEADER = genHeader('publish')
164
165/* Subscribe */
166protocol.SUBSCRIBE_HEADER = genHeader('subscribe')
167protocol.SUBSCRIBE_OPTIONS_QOS_MASK = 0x03
168protocol.SUBSCRIBE_OPTIONS_NL_MASK = 0x01
169protocol.SUBSCRIBE_OPTIONS_NL_SHIFT = 2
170protocol.SUBSCRIBE_OPTIONS_RAP_MASK = 0x01
171protocol.SUBSCRIBE_OPTIONS_RAP_SHIFT = 3
172protocol.SUBSCRIBE_OPTIONS_RH_MASK = 0x03
173protocol.SUBSCRIBE_OPTIONS_RH_SHIFT = 4
174protocol.SUBSCRIBE_OPTIONS_RH = [0x00, 0x10, 0x20]
175protocol.SUBSCRIBE_OPTIONS_NL = 0x04
176protocol.SUBSCRIBE_OPTIONS_RAP = 0x08
177protocol.SUBSCRIBE_OPTIONS_QOS = [0x00, 0x01, 0x02]
178
179/* Unsubscribe */
180protocol.UNSUBSCRIBE_HEADER = genHeader('unsubscribe')
181
182/* Confirmations */
183protocol.ACKS = {
184 unsuback: genHeader('unsuback'),
185 puback: genHeader('puback'),
186 pubcomp: genHeader('pubcomp'),
187 pubrel: genHeader('pubrel'),
188 pubrec: genHeader('pubrec')
189}
190
191protocol.SUBACK_HEADER = Buffer.from([protocol.codes.suback << protocol.CMD_SHIFT])
192
193/* Protocol versions */
194protocol.VERSION3 = Buffer.from([3])
195protocol.VERSION4 = Buffer.from([4])
196protocol.VERSION5 = Buffer.from([5])
197protocol.VERSION131 = Buffer.from([131])
198protocol.VERSION132 = Buffer.from([132])
199
200/* QoS */
201protocol.QOS = [0, 1, 2].map(qos => {
202 return Buffer.from([qos])
203})
204
205/* Empty packets */
206protocol.EMPTY = {
207 pingreq: Buffer.from([protocol.codes.pingreq << 4, 0]),
208 pingresp: Buffer.from([protocol.codes.pingresp << 4, 0]),
209 disconnect: Buffer.from([protocol.codes.disconnect << 4, 0])
210}
211
212protocol.MQTT5_PUBACK_PUBREC_CODES = {
213 0x00: 'Success',
214 0x10: 'No matching subscribers',
215 0x80: 'Unspecified error',
216 0x83: 'Implementation specific error',
217 0x87: 'Not authorized',
218 0x90: 'Topic Name invalid',
219 0x91: 'Packet identifier in use',
220 0x97: 'Quota exceeded',
221 0x99: 'Payload format invalid'
222}
223
224protocol.MQTT5_PUBREL_PUBCOMP_CODES = {
225 0x00: 'Success',
226 0x92: 'Packet Identifier not found'
227}
228
229protocol.MQTT5_SUBACK_CODES = {
230 0x00: 'Granted QoS 0',
231 0x01: 'Granted QoS 1',
232 0x02: 'Granted QoS 2',
233 0x80: 'Unspecified error',
234 0x83: 'Implementation specific error',
235 0x87: 'Not authorized',
236 0x8F: 'Topic Filter invalid',
237 0x91: 'Packet Identifier in use',
238 0x97: 'Quota exceeded',
239 0x9E: 'Shared Subscriptions not supported',
240 0xA1: 'Subscription Identifiers not supported',
241 0xA2: 'Wildcard Subscriptions not supported'
242}
243
244protocol.MQTT5_UNSUBACK_CODES = {
245 0x00: 'Success',
246 0x11: 'No subscription existed',
247 0x80: 'Unspecified error',
248 0x83: 'Implementation specific error',
249 0x87: 'Not authorized',
250 0x8F: 'Topic Filter invalid',
251 0x91: 'Packet Identifier in use'
252}
253
254protocol.MQTT5_DISCONNECT_CODES = {
255 0x00: 'Normal disconnection',
256 0x04: 'Disconnect with Will Message',
257 0x80: 'Unspecified error',
258 0x81: 'Malformed Packet',
259 0x82: 'Protocol Error',
260 0x83: 'Implementation specific error',
261 0x87: 'Not authorized',
262 0x89: 'Server busy',
263 0x8B: 'Server shutting down',
264 0x8D: 'Keep Alive timeout',
265 0x8E: 'Session taken over',
266 0x8F: 'Topic Filter invalid',
267 0x90: 'Topic Name invalid',
268 0x93: 'Receive Maximum exceeded',
269 0x94: 'Topic Alias invalid',
270 0x95: 'Packet too large',
271 0x96: 'Message rate too high',
272 0x97: 'Quota exceeded',
273 0x98: 'Administrative action',
274 0x99: 'Payload format invalid',
275 0x9A: 'Retain not supported',
276 0x9B: 'QoS not supported',
277 0x9C: 'Use another server',
278 0x9D: 'Server moved',
279 0x9E: 'Shared Subscriptions not supported',
280 0x9F: 'Connection rate exceeded',
281 0xA0: 'Maximum connect time',
282 0xA1: 'Subscription Identifiers not supported',
283 0xA2: 'Wildcard Subscriptions not supported'
284}
285
286protocol.MQTT5_AUTH_CODES = {
287 0x00: 'Success',
288 0x18: 'Continue authentication',
289 0x19: 'Re-authenticate'
290}