u8-mqtt 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +23 -55
  2. package/cjs/index.cjs +633 -558
  3. package/cjs/index.cjs.map +1 -1
  4. package/cjs/v4.cjs +480 -663
  5. package/cjs/v4.cjs.map +1 -1
  6. package/cjs/v5.cjs +632 -551
  7. package/cjs/v5.cjs.map +1 -1
  8. package/code/_conn.jsy +53 -54
  9. package/code/_router.jsy +15 -4
  10. package/code/base.jsy +36 -17
  11. package/code/core.jsy +78 -59
  12. package/code/index.mjs +4 -4
  13. package/code/v4.mjs +6 -6
  14. package/code/v5.mjs +14 -6
  15. package/esm/deno/index.js +636 -563
  16. package/esm/deno/index.js.map +1 -1
  17. package/esm/deno/v4.js +487 -670
  18. package/esm/deno/v4.js.map +1 -1
  19. package/esm/deno/v5.js +638 -559
  20. package/esm/deno/v5.js.map +1 -1
  21. package/esm/node/index.js +629 -556
  22. package/esm/node/index.js.map +1 -1
  23. package/esm/node/index.mjs +629 -556
  24. package/esm/node/index.mjs.map +1 -1
  25. package/esm/node/v4.js +480 -663
  26. package/esm/node/v4.js.map +1 -1
  27. package/esm/node/v4.mjs +480 -663
  28. package/esm/node/v4.mjs.map +1 -1
  29. package/esm/node/v5.js +631 -552
  30. package/esm/node/v5.js.map +1 -1
  31. package/esm/node/v5.mjs +631 -552
  32. package/esm/node/v5.mjs.map +1 -1
  33. package/esm/web/index.js +631 -558
  34. package/esm/web/index.js.map +1 -1
  35. package/esm/web/index.min.js +1 -0
  36. package/esm/web/index.min.js.br +0 -0
  37. package/esm/web/index.min.js.gz +0 -0
  38. package/esm/web/v4.js +482 -665
  39. package/esm/web/v4.js.map +1 -1
  40. package/esm/web/v4.min.js +1 -0
  41. package/esm/web/v4.min.js.br +0 -0
  42. package/esm/web/v4.min.js.gz +0 -0
  43. package/esm/web/v5.js +633 -554
  44. package/esm/web/v5.js.map +1 -1
  45. package/esm/web/v5.min.js +1 -0
  46. package/esm/web/v5.min.js.br +0 -0
  47. package/esm/web/v5.min.js.gz +0 -0
  48. package/package.json +23 -12
  49. package/code/session.mjs +0 -65
  50. package/esm/deno/index.mjs +0 -1502
  51. package/esm/deno/index.mjs.map +0 -1
  52. package/esm/deno/v4.mjs +0 -1496
  53. package/esm/deno/v4.mjs.map +0 -1
  54. package/esm/deno/v5.mjs +0 -1496
  55. package/esm/deno/v5.mjs.map +0 -1
  56. package/esm/web/index.min.mjs +0 -1
  57. package/esm/web/index.mjs +0 -1502
  58. package/esm/web/index.mjs.map +0 -1
  59. package/esm/web/v4.min.mjs +0 -1
  60. package/esm/web/v4.mjs +0 -1496
  61. package/esm/web/v4.mjs.map +0 -1
  62. package/esm/web/v5.min.mjs +0 -1
  63. package/esm/web/v5.mjs +0 -1496
  64. package/esm/web/v5.mjs.map +0 -1
package/cjs/v5.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var net = require('net');
5
+ var node_net = require('node:net');
6
6
 
7
7
  function encode_varint(n, a=[]) {
8
8
  do {
@@ -26,7 +26,7 @@ export function decode_varint_loop(u8, i=0) {
26
26
  */
27
27
 
28
28
 
29
- function decode_varint(u8, i=0) {
29
+ function decode_varint$1(u8, i=0) {
30
30
  let i0 = i;
31
31
  // unrolled for a max of 4 chains
32
32
  let n = (u8[i] & 0x7f) << 0;
@@ -42,45 +42,13 @@ function decode_varint(u8, i=0) {
42
42
  return [n, i, i0]
43
43
  }
44
44
 
45
- function _mqtt_raw_pkt_dispatch(decode_raw_pkt) {
46
- let u8 = new Uint8Array(0);
47
- return u8_buf => {
48
- u8 = 0 === u8.byteLength
49
- ? u8_buf : _u8_join(u8, u8_buf);
50
-
51
- const res = [];
52
- while (1) {
53
- const [len_body, len_vh] = decode_varint(u8, 1);
54
- const len_pkt = len_body + len_vh;
45
+ const mqtt_props = /* #__PURE__ */
46
+ init_mqtt_props();
55
47
 
56
- if ( u8.byteLength < len_pkt )
57
- return res
48
+ function init_mqtt_props() {
49
+ let mqtt_props = new Map();
58
50
 
59
- let b0 = u8[0];
60
- let u8_body = 0 === len_body ? null
61
- : u8.subarray(len_vh, len_pkt);
62
-
63
- u8 = u8.subarray(len_pkt);
64
-
65
- const pkt = decode_raw_pkt(b0, u8_body);
66
- if (undefined !== pkt && null !== pkt)
67
- res.push( pkt );
68
- }
69
- }
70
- }
71
-
72
- function _u8_join(a, b) {
73
- const alen = a.byteLength;
74
- const r = new Uint8Array(alen + b.byteLength);
75
- r.set(a, 0);
76
- r.set(b, alen);
77
- return r
78
- }
79
-
80
- const mqtt_props = new Map();
81
-
82
- {
83
- const entries = [
51
+ let entries = [
84
52
  [ 0x01, 'u8', 'payload_format_indicator'],
85
53
  [ 0x02, 'u32', 'message_expiry_interval'],
86
54
  [ 0x03, 'utf8', 'content_type'],
@@ -101,140 +69,279 @@ const mqtt_props = new Map();
101
69
  [ 0x21, 'u16', 'receive_maximum'],
102
70
  [ 0x22, 'u16', 'topic_alias_maximum'],
103
71
  [ 0x23, 'u16', 'topic_alias'],
104
- [ 0x24, 'u8', 'maximum_qo_s'],
72
+ [ 0x24, 'u8', 'maximum_qos'],
105
73
  [ 0x25, 'u8', 'retain_available'],
106
- [ 0x26, 'pair', 'user_properties', true],
74
+ [ 0x26, 'pair', 'user_properties', {op: 'kv_obj'}],
107
75
  [ 0x27, 'u32', 'maximum_packet_size'],
108
76
  [ 0x28, 'u8', 'wildcard_subscription_available'],
109
- [ 0x29, 'u8', 'subscription_identifiers_available', true],
77
+ [ 0x29, 'u8', 'subscription_identifiers_available', {op: 'u8_vec'}],
110
78
  [ 0x2A, 'u8', 'shared_subscription_available'],
111
79
  ];
112
80
 
113
- for (const [id, type, name, plural] of entries) {
114
- const prop_obj = {id, type, name};
115
- if (plural) prop_obj.plural = plural;
81
+ for (let [id, type, name, extra] of entries) {
82
+ let prop_obj = {id, type, name, ...extra};
116
83
  mqtt_props.set(prop_obj.id, prop_obj);
117
84
  mqtt_props.set(prop_obj.name, prop_obj);
118
85
  }
119
- }
120
-
121
- const as_utf8 = u8 =>
122
- new TextDecoder('utf-8').decode(u8);
123
86
 
124
- const step_from = idx =>
125
- (width, r) => ( r = idx, idx += width, r );
87
+ return mqtt_props
88
+ }
126
89
 
127
- class mqtt_type_reader {
128
- constructor(buf, idx=0) {
129
- this.buf = buf;
130
- this.step = step_from(idx);
90
+ class U8_Reason extends Number {
91
+ static of(v, pkt_kind, by_kind) {
92
+ let self = new this(v);
93
+ self.reason = by_kind?.[pkt_kind]?.get(v) || pkt_kind;
94
+ return self
131
95
  }
96
+ }
132
97
 
133
- _fork(buf, idx) {
134
- return { __proto__: this, buf, step: step_from(idx) }
98
+ class mqtt_reader_v4 {
99
+ static of(buf) { return this.prototype.of(buf) }
100
+ of(buf) {
101
+ let step = (width, k) => (k=0|step.k, step.k=k+width, k);
102
+ return {__proto__: this, buf, step}
135
103
  }
136
104
 
137
105
  has_more() {
138
- const {buf, step} = this;
139
- return buf.byteLength > step(0)
106
+ return this.buf.byteLength > (this.step.k|0)
140
107
  }
141
108
 
142
109
  u8() {
143
- const {buf, step} = this;
144
- return buf[step(1)]
110
+ return this.buf[this.step(1)]
145
111
  }
146
112
 
147
113
  u16() {
148
- const {buf, step} = this;
149
- const i = step(2);
114
+ let {buf, step} = this, i = step(2);
150
115
  return (buf[i]<<8) | buf[i+1]
151
116
  }
152
117
 
153
118
  u32() {
154
- const {buf, step} = this;
155
- const i = step(4);
119
+ let {buf, step} = this, i = step(4);
156
120
  return (buf[i]<<24) | (buf[i+1]<<16) | (buf[i+2]<<8) | buf[i+3]
157
121
  }
158
122
 
159
123
  vint() {
160
- const {buf, step} = this;
161
- const [n, vi, vi0] = decode_varint(buf, step(0));
124
+ let {buf, step} = this;
125
+ let [n, vi, vi0] = decode_varint$1(buf, step.k|0);
162
126
  step(vi - vi0);
163
127
  return n
164
128
  }
165
129
 
166
- vbuf() {
167
- const {buf, step} = this;
168
- const [n, vi, vi0] = decode_varint(buf, step(0));
169
- step(n + vi - vi0);
170
- return 0 === n ? null
171
- : buf.subarray(vi, step(0))
172
- }
173
-
174
130
  bin() {
175
- const {buf, step} = this;
176
- const i = step(2);
177
- const len = (buf[i]<<8) | buf[i+1];
178
- const i0 = step(len);
179
- return buf.subarray(i0, i0+len)
131
+ let {buf, step} = this, i = step(2);
132
+ let len = (buf[i]<<8) | buf[i+1];
133
+ i = step(len);
134
+ return buf.subarray(i, i+len)
180
135
  }
181
136
 
182
- utf8() { return as_utf8(this.bin()) }
183
- pair() { return [ as_utf8(this.bin()), as_utf8(this.bin()) ] }
137
+ utf8() { return new TextDecoder('utf-8').decode(this.bin()) }
138
+ pair() { return [ this.utf8(), this.utf8() ] }
184
139
 
185
- u8_flags(FlagsType) {
186
- const {buf, step} = this;
187
- return new FlagsType(buf[step(1)])
188
- }
140
+ flags(FlagsType) { return new FlagsType(this.buf[this.step(1)]) }
189
141
 
190
- u8_reason(fn_reason) {
191
- const {buf, step} = this;
192
- return fn_reason( buf[step(1)] )
142
+ reason(pkt_kind) {
143
+ let v = this.buf[this.step(1)];
144
+ if (null != v)
145
+ return U8_Reason.of(v, pkt_kind, this._reasons_by)
193
146
  }
194
147
 
195
148
  flush() {
196
- const {buf, step} = this;
149
+ let {buf, step} = this;
197
150
  this.step = this.buf = null;
198
- return buf.subarray(step(0))
151
+ return buf.subarray(step.k|0)
199
152
  }
200
153
 
154
+ }
155
+
156
+ class mqtt_reader_v5$1 extends mqtt_reader_v4 {
201
157
  props() {
202
- let sub = this.vbuf();
203
- return null === sub ? null
204
- : this._fork(sub, 0)._read_props([])
158
+ let {buf, step} = this;
159
+ let [n, vi, vi0] = decode_varint$1(buf, step.k|0);
160
+ step(n + vi - vi0);
161
+ if (0 === n) return null
162
+
163
+ let res={}, fork = this.of(buf.subarray(vi, step.k|0));
164
+ while (fork.has_more()) {
165
+ let pt = mqtt_props.get( fork.u8() )
166
+ , value = fork[pt.type]();
167
+ res[pt.name] = ! pt.op ? value
168
+ : fork[pt.op](res[pt.name], value);
169
+ }
170
+ return res
205
171
  }
206
172
 
207
- _read_props(lst) {
208
- while (this.has_more()) {
209
- let k = this.u8();
210
- let p = mqtt_props.get( k );
211
- let v = this[p.type]();
212
- lst.push([p.name, v]);
213
- }
214
- return lst
173
+ kv_obj(obj=Object.create(null), [k,v]) {
174
+ obj[k] = v;
175
+ return obj
215
176
  }
177
+ u8_vec(vec=[], u8) {
178
+ vec.push(u8);
179
+ return vec
180
+ }
181
+
182
+ /*
183
+ vbuf() {
184
+ let {buf, step} = this
185
+ let [n, vi, vi0] = decode_varint(buf, step.k|0)
186
+ step(n + vi - vi0)
187
+ return 0 === n ? null
188
+ : buf.subarray(vi, step.k|0)
189
+ }
190
+ */
216
191
  }
217
192
 
193
+ function mqtt_reader_info(mqtt_reader, ... info_fn_list) {
194
+ mqtt_reader = class extends mqtt_reader {
195
+ static reasons(pkt_type, ...reason_entries) {
196
+ let proto = this.prototype;
197
+ proto._reasons_by = {... proto._reasons_by};
218
198
 
199
+ let lut = (proto._reasons_by[pkt_type] ||= new Map());
200
+ for (let [u8, reason] of reason_entries)
201
+ lut.set( u8, reason );
219
202
 
220
- class U8_Reason extends Number {
221
- constructor(u8, reason) { super(u8); this.reason = reason; }
203
+ return this
204
+ }
205
+ };
206
+
207
+ for (let fn_info of info_fn_list)
208
+ fn_info(mqtt_reader);
209
+
210
+ return mqtt_reader
222
211
  }
223
212
 
224
- function bind_reason_lookup(reason_entries) {
225
- const reason_map = new Map();
226
- for (const [u8, reason] of reason_entries)
227
- reason_map.set( u8, new U8_Reason(u8, reason) );
213
+ class mqtt_writer_v4 {
214
+ static of() { return this.prototype.of() }
215
+ of() { return {__proto__: this, $:[]} }
216
+
217
+ static init() { return this }
218
+
219
+ as_pkt(pkt_id) { return this.pack([pkt_id]) }
220
+
221
+ push(...z) { this.$.push(...z); }
222
+ pack(hdr) {
223
+ let z, i, n=0, parts = this.$;
224
+ this.$ = false;
225
+ for (z of parts) n += z.length;
226
+
227
+ hdr = encode_varint(n, hdr);
228
+ i = hdr.length;
229
+
230
+ let pkt = new Uint8Array(i + n);
231
+ pkt.set(hdr, 0);
232
+ for (z of parts) {
233
+ pkt.set(z, i);
234
+ i += z.length;
235
+ }
236
+ return pkt
237
+ }
238
+
239
+ u8(v) { this.push([ v & 0xff ]); }
240
+ u16(v) { this.push([ (v>>>8) & 0xff, v & 0xff ]); }
241
+ u32(v) { this.push([ (v>>>24) & 0xff, (v>>>16) & 0xff, (v>>>8) & 0xff, v & 0xff ]); }
242
+ vint(v) { this.push( encode_varint(v) );}
243
+
244
+ bin(u8_buf) {
245
+ if (! u8_buf) return this.u16(0)
246
+ if ('string' === typeof u8_buf)
247
+ return this.utf8(u8_buf)
248
+
249
+ if (u8_buf.length !== u8_buf.byteLength)
250
+ u8_buf = new Uint8Array(u8_buf);
251
+
252
+ this.u16(u8_buf.byteLength);
253
+ this.push(u8_buf);
254
+ }
255
+
256
+ utf8(v) {
257
+ let u8_buf = new TextEncoder('utf-8').encode(v);
258
+ this.u16(u8_buf.byteLength);
259
+ this.push(u8_buf);
260
+ }
261
+ pair(k,v) { this.utf8(k); this.utf8(v); }
262
+
263
+ flags(v, enc_flags, b0=0) {
264
+ if (undefined !== v && isNaN(+v))
265
+ v = enc_flags(v, 0);
266
+
267
+ v |= b0;
268
+ this.push([v]);
269
+ return v
270
+ }
271
+
272
+ reason(v) { this.push([v | 0]); }
273
+
274
+ flush(buf) {
275
+ if (null != buf)
276
+ this.push(
277
+ 'string' === typeof buf
278
+ ? new TextEncoder('utf-8').encode(buf)
279
+ : buf );
228
280
 
229
- return reason_map.get.bind(reason_map)
281
+ this.push = false;
282
+ }
230
283
  }
231
284
 
232
- function mqtt_decode_connack(ns) {
285
+
286
+ class mqtt_writer_v5 extends mqtt_writer_v4 {
287
+ props(props) {
288
+ if (! props)
289
+ return this.u8(0)
290
+
291
+ if (! Array.isArray(props))
292
+ props = props.entries
293
+ ? Array.from(props.entries())
294
+ : Object.entries(props);
295
+
296
+ if (0 === props.length)
297
+ return this.u8(0)
298
+
299
+ let fork = this.of();
300
+ for (let [name, value] of props) {
301
+ let pt = mqtt_props.get(name);
302
+ fork[pt.op || 'one'](value, pt);
303
+ }
304
+ this.push(fork.pack());
305
+ }
306
+
307
+ one(value, pt) {
308
+ this.u8(pt.id);
309
+ this[pt.type](value);
310
+ }
311
+ kv_obj(obj, pt) {
312
+ for (let kv of Object.entries(obj)) {
313
+ this.u8(pt.id);
314
+ this.pair(kv);
315
+ }
316
+ }
317
+ u8_vec(vec, pt) {
318
+ for (let v of vec) {
319
+ this.u8(pt.id);
320
+ this.u8(v);
321
+ }
322
+ }
323
+ }
324
+
325
+ function mqtt_decode_connack(ns, mqtt_reader) {
233
326
  class _connack_flags_ extends Number {
234
327
  get session_present() { return this & 0x01 !== 0 }
235
328
  }
236
329
 
237
- const _connack_reason_ = bind_reason_lookup([
330
+ return ns[0x2] = (pkt, u8_body) => {
331
+ let rdr = mqtt_reader.of(u8_body);
332
+
333
+ pkt.flags =
334
+ rdr.flags(_connack_flags_);
335
+
336
+ pkt.reason = rdr.reason(pkt.type);
337
+ if (5 <= pkt.mqtt_level)
338
+ pkt.props = rdr.props();
339
+ return pkt }
340
+ }
341
+
342
+
343
+ function _connack_v4(mqtt_reader) {
344
+ mqtt_reader.reasons('connack',
238
345
  // MQTT 3.1.1
239
346
  [ 0x00, 'Success'],
240
347
  [ 0x01, 'Connection refused, unacceptable protocol version'],
@@ -242,7 +349,13 @@ function mqtt_decode_connack(ns) {
242
349
  [ 0x03, 'Connection refused, server unavailable'],
243
350
  [ 0x04, 'Connection refused, bad user name or password'],
244
351
  [ 0x05, 'Connection refused, not authorized'],
352
+ );
353
+ }
354
+
355
+ function _connack_v5(mqtt_reader) {
356
+ _connack_v4(mqtt_reader);
245
357
 
358
+ mqtt_reader.reasons('connack',
246
359
  // MQTT 5.0
247
360
  [ 0x81, 'Malformed Packet'],
248
361
  [ 0x82, 'Protocol Error'],
@@ -264,29 +377,17 @@ function mqtt_decode_connack(ns) {
264
377
  [ 0x9C, 'Use another server'],
265
378
  [ 0x9D, 'Server moved'],
266
379
  [ 0x9F, 'Connection rate exceeded'],
267
- ]);
268
-
269
-
270
- return ns[0x2] = (pkt, u8_body) => {
271
- const rdr = new mqtt_type_reader(u8_body, 0);
272
-
273
- pkt.flags =
274
- rdr.u8_flags(_connack_flags_);
275
-
276
- pkt.reason = rdr.u8_reason(_connack_reason_);
277
- if (5 <= pkt.mqtt_level)
278
- pkt.props = rdr.props();
279
- return pkt }
380
+ );
280
381
  }
281
382
 
282
- function mqtt_decode_publish(ns) {
383
+ function mqtt_decode_publish(ns, mqtt_reader) {
283
384
  return ns[0x3] = (pkt, u8_body) => {
284
- const {hdr} = pkt;
385
+ let {hdr} = pkt;
285
386
  pkt.dup = Boolean(hdr & 0x8);
286
387
  pkt.retain = Boolean(hdr & 0x1);
287
- const qos = pkt.qos = (hdr>>1) & 0x3;
388
+ let qos = pkt.qos = (hdr>>1) & 0x3;
288
389
 
289
- const rdr = new mqtt_type_reader(u8_body, 0);
390
+ let rdr = mqtt_reader.of(u8_body);
290
391
  pkt.topic = rdr.utf8();
291
392
  if (0 !== qos)
292
393
  pkt.pkt_id = rdr.u16();
@@ -298,73 +399,68 @@ function mqtt_decode_publish(ns) {
298
399
  return pkt }
299
400
  }
300
401
 
301
- function mqtt_decode_puback(ns) {
302
- const _puback_reason_ = bind_reason_lookup([
303
- [ 0x00, 'Success'],
304
-
305
- // MQTT 5.0
306
- [ 0x10, 'No matching subscribers'],
307
- [ 0x80, 'Unspecified error'],
308
- [ 0x83, 'Implementation specific error'],
309
- [ 0x87, 'Not authorized'],
310
- [ 0x90, 'Topic Name invalid'],
311
- [ 0x91, 'Packet identifier in use'],
312
- [ 0x97, 'Quota exceeded'],
313
- [ 0x99, 'Payload format invalid'],
314
- ]);
315
-
316
-
402
+ function mqtt_decode_puback(ns, mqtt_reader) {
317
403
  return ns[0x4] = (pkt, u8_body) => {
318
- const rdr = new mqtt_type_reader(u8_body, 0);
404
+ let rdr = mqtt_reader.of(u8_body);
319
405
 
320
406
  pkt.pkt_id = rdr.u16();
321
407
  if (5 <= pkt.mqtt_level) {
322
- pkt.reason = rdr.u8_reason(_puback_reason_);
408
+ pkt.reason = rdr.reason(pkt.type);
323
409
  pkt.props = rdr.props();
324
410
  }
325
411
 
326
412
  return pkt }
327
413
  }
328
414
 
329
- function mqtt_decode_pubxxx(ns) {
330
- const _pubxxx_reason_ = bind_reason_lookup([
331
- [ 0x00, 'Success' ],
332
- [ 0x92, 'Packet Identifier not found' ],
333
- ]);
334
-
335
- return ns[0x5] = ns[0x6] = ns[0x7] = (pkt, u8_body) => {
336
- const rdr = new mqtt_type_reader(u8_body, 0);
337
415
 
338
- pkt.pkt_id = rdr.u16();
339
- pkt.reason = rdr.u8_reason(_pubxxx_reason_);
340
- if (5 <= pkt.mqtt_level)
341
- pkt.props = rdr.props();
342
- return pkt }
416
+ function _puback_v5(mqtt_reader) {
417
+ mqtt_reader.reasons('puback',
418
+ // MQTT 5.0
419
+ [ 0x00, 'Success'],
420
+ [ 0x10, 'No matching subscribers'],
421
+ [ 0x80, 'Unspecified error'],
422
+ [ 0x83, 'Implementation specific error'],
423
+ [ 0x87, 'Not authorized'],
424
+ [ 0x90, 'Topic Name invalid'],
425
+ [ 0x91, 'Packet identifier in use'],
426
+ [ 0x97, 'Quota exceeded'],
427
+ [ 0x99, 'Payload format invalid'],
428
+ );
343
429
  }
344
430
 
345
- function _mqtt_decode_suback(_ack_reason_) {
431
+ function _mqtt_decode_suback(mqtt_reader) {
346
432
  return (pkt, u8_body) => {
347
- const rdr = new mqtt_type_reader(u8_body, 0);
433
+ let rdr = mqtt_reader.of(u8_body);
348
434
 
349
435
  pkt.pkt_id = rdr.u16();
350
436
  if (5 <= pkt.mqtt_level)
351
437
  pkt.props = rdr.props();
352
438
 
353
- const answers = pkt.answers = [];
439
+ let answers = pkt.answers = [];
354
440
  while (rdr.has_more())
355
441
  answers.push(
356
- rdr.u8_reason(_ack_reason_) );
442
+ rdr.reason(pkt.type) );
357
443
 
358
444
  return pkt }
359
445
  }
360
446
 
361
- function mqtt_decode_suback(ns) {
362
- const _suback_reason_ = bind_reason_lookup([
447
+ function mqtt_decode_suback(ns, mqtt_reader) {
448
+ return ns[0x9] = _mqtt_decode_suback(mqtt_reader)
449
+ }
450
+
451
+ function _suback_v4(mqtt_reader) {
452
+ mqtt_reader.reasons('suback',
363
453
  // MQTT 3.1.1
364
454
  [ 0x00, 'Granted QoS 0'],
365
455
  [ 0x01, 'Granted QoS 1'],
366
456
  [ 0x02, 'Granted QoS 2'],
457
+ );
458
+ }
459
+
460
+ function _suback_v5(mqtt_reader) {
461
+ _suback_v4(mqtt_reader);
367
462
 
463
+ mqtt_reader.reasons('suback',
368
464
  // MQTT 5.0
369
465
  [ 0x80, 'Unspecified error'],
370
466
  [ 0x83, 'Implementation specific error'],
@@ -375,13 +471,16 @@ function mqtt_decode_suback(ns) {
375
471
  [ 0x9E, 'Shared Subscriptions not supported'],
376
472
  [ 0xA1, 'Subscription Identifiers not supported'],
377
473
  [ 0xA2, 'Wildcard Subscriptions not supported'],
378
- ]);
474
+ );
475
+ }
379
476
 
380
- return ns[0x9] = _mqtt_decode_suback(_suback_reason_)
477
+ function mqtt_decode_unsuback(ns, mqtt_reader) {
478
+ return ns[0xb] = _mqtt_decode_suback(mqtt_reader)
381
479
  }
382
480
 
383
- function mqtt_decode_unsuback(ns) {
384
- const _unsuback_reason_ = bind_reason_lookup([
481
+ function _unsuback_v4(mqtt_reader) {
482
+ mqtt_reader.reasons('unsuback',
483
+ // MQTT 3.1.1
385
484
  [ 0x00, 'Success'],
386
485
  [ 0x11, 'No subscription existed'],
387
486
  [ 0x80, 'Unspecified error'],
@@ -389,17 +488,26 @@ function mqtt_decode_unsuback(ns) {
389
488
  [ 0x87, 'Not authorized'],
390
489
  [ 0x8F, 'Topic Filter invalid'],
391
490
  [ 0x91, 'Packet Identifier in use'],
392
- ]);
393
-
394
- return ns[0xb] = _mqtt_decode_suback(_unsuback_reason_)
491
+ );
395
492
  }
396
493
 
397
494
  function mqtt_decode_pingxxx(ns) {
398
495
  return ns[0xc] = ns[0xd] = pkt => pkt
399
496
  }
400
497
 
401
- function mqtt_decode_disconnect(ns) {
402
- const _disconnect_reason_ = bind_reason_lookup([
498
+ function mqtt_decode_disconnect(ns, mqtt_reader) {
499
+ return ns[0xe] = (pkt, u8_body) => {
500
+ if (u8_body && 5 <= pkt.mqtt_level) {
501
+ let rdr = mqtt_reader.of(u8_body);
502
+ pkt.reason = rdr.reason(pkt.type);
503
+ pkt.props = rdr.props();
504
+ }
505
+ return pkt }
506
+ }
507
+
508
+
509
+ function _disconnect_v5(mqtt_reader) {
510
+ mqtt_reader.reasons('disconnect',
403
511
  // MQTT 5.0
404
512
  [ 0x00, 'Normal disconnection'],
405
513
  [ 0x04, 'Disconnect with Will Message'],
@@ -430,181 +538,33 @@ function mqtt_decode_disconnect(ns) {
430
538
  [ 0xA0, 'Maximum connect time'],
431
539
  [ 0xA1, 'Subscription Identifiers not supported'],
432
540
  [ 0xA2, 'Wildcard Subscriptions not supported'],
433
- ]);
434
-
435
-
436
- return ns[0xe] = (pkt, u8_body) => {
437
- if (u8_body && 5 <= pkt.mqtt_level) {
438
- const rdr = new mqtt_type_reader(u8_body, 0);
439
- pkt.reason = rdr.u8_reason(_disconnect_reason_);
440
- pkt.props = rdr.props();
441
- }
442
- return pkt }
541
+ );
443
542
  }
444
543
 
445
- function mqtt_decode_auth(ns) {
446
- const _auth_reason_ = bind_reason_lookup([
447
- // MQTT 5.0
448
- [ 0x00, 'Success' ],
449
- [ 0x18, 'Continue authentication' ],
450
- [ 0x19, 'Re-authenticate' ],
451
- ]);
452
-
544
+ function mqtt_decode_auth(ns, mqtt_reader) {
453
545
  return ns[0xf] = (pkt, u8_body) => {
454
546
  if ( 5 <= pkt.mqtt_level ) {
455
- const rdr = new mqtt_type_reader(u8_body, 0);
456
- pkt.reason = rdr.u8_reason(_auth_reason_);
547
+ let rdr = mqtt_reader.of(u8_body);
548
+ pkt.reason = rdr.reason(pkt.type);
457
549
  pkt.props = rdr.props();
458
550
  }
459
551
  return pkt }
460
552
  }
461
553
 
462
- function mqtt_pkt_writer_pool() {
463
- const _pool_ = [];
464
- return host =>
465
- 0 === _pool_.length
466
- ? mqtt_pkt_writer(host, _pool_)
467
- : _pool_.pop()(host)
468
- }
469
-
470
- function mqtt_pkt_writer(host, _pool_) {
471
- // avoid GCing push/pull when they can be reused
472
- let n=0, rope=[];
473
- return install(host)
474
-
475
- function install(_host) {
476
- host = _host;
477
- host.push = push;
478
- host.pack = pack;
479
- }
480
-
481
- function push(u8) {
482
- rope.push(u8);
483
- n += u8.length;
484
- }
485
-
486
- function pack(hdr) {
487
- host = host.push = host.pack = null;
488
-
489
- const res = _mqtt_pkt_rope(hdr, n, rope);
490
- n=0; rope=[];
491
- if (undefined !== _pool_)
492
- _pool_.push(install);
493
-
494
- return res
495
- }
496
- }
497
-
498
-
499
- function _mqtt_pkt_rope(hdr, n, rope) {
500
- const header = encode_varint(n, hdr);
501
- let i = header.length;
502
-
503
- const pkt = new Uint8Array(n + i);
504
- pkt.set(header, 0);
505
- for (const vec of rope) {
506
- pkt.set(vec, i);
507
- i += vec.length;
508
- }
509
- return pkt
510
- }
511
-
512
- const _is_array = Array.isArray;
513
- const pack_utf8 = v => new TextEncoder('utf-8').encode(v);
514
- const pack_u16 = v => [ (v>>>8) & 0xff, v & 0xff ];
515
- const pack_u32 = v => [ (v>>>24) & 0xff, (v>>>16) & 0xff, (v>>>8) & 0xff, v & 0xff ];
516
-
517
- class mqtt_type_writer {
518
- constructor() {
519
- this._pkt_writer(this);
520
- }
521
-
522
- as_pkt(hdr) { return this.pack([hdr]) }
523
-
524
- u8(v) { this.push([ v & 0xff ]);}
525
- u16(v) { this.push( pack_u16(v) );}
526
- u32(v) { this.push( pack_u32(v) );}
527
- vint(v) { this.push( encode_varint(v) );}
528
-
529
- _u16_bin(u8_buf) {
530
- const {push} = this;
531
- push( pack_u16( u8_buf.byteLength ));
532
- push( u8_buf );
533
- }
534
-
535
- flush(buf) {
536
- if (null != buf)
537
- this.push(
538
- 'string' === typeof buf
539
- ? pack_utf8(buf) : buf );
540
-
541
- this.push = false;
542
- }
543
554
 
544
- bin(u8_buf) {
545
- if (! u8_buf) return this.u16(0)
546
- if ('string' === typeof u8_buf)
547
- return this.utf8(u8_buf)
548
-
549
- if (u8_buf.length !== u8_buf.byteLength)
550
- u8_buf = new Uint8Array(u8_buf);
551
- this._u16_bin(u8_buf);
552
- }
553
-
554
- utf8(v) { this._u16_bin( new TextEncoder('utf-8').encode(v) ); }
555
-
556
- pair(k,v) {
557
- this.utf8(k);
558
- this.utf8(v);
559
- }
560
-
561
- u8_flags(v, enc_flags, b0=0) {
562
- if (undefined !== v && isNaN(+v))
563
- v = enc_flags(v, 0);
564
-
565
- v |= b0;
566
- this.push([v]);
567
- return v
568
- }
569
-
570
- u8_reason(v) { this.push([v | 0]); }
571
-
572
- props(props) {
573
- if (! props)
574
- return this.u8(0)
575
-
576
- if (! _is_array(props))
577
- props = props.entries
578
- ? Array.from(props.entries())
579
- : Object.entries(props);
580
-
581
- if (0 === props.length)
582
- return this.u8(0)
583
-
584
- const wrt = this._fork();
585
- for (const [name, value] of props) {
586
- const {id, type} = mqtt_props.get(name);
587
- wrt.u8(id);
588
- wrt[type](value);
589
- }
590
-
591
- this.push(wrt.pack([]));
592
- }
593
-
594
- _fork() {
595
- let self = { __proto__: this };
596
- this._pkt_writer(self);
597
- return self
598
- }
555
+ function _auth_v5(mqtt_reader) {
556
+ mqtt_reader.reasons('auth',
557
+ // MQTT 5.0
558
+ [ 0x00, 'Success' ],
559
+ [ 0x18, 'Continue authentication' ],
560
+ [ 0x19, 'Re-authenticate' ],
561
+ );
599
562
  }
600
563
 
601
- mqtt_type_writer.prototype._pkt_writer =
602
- mqtt_pkt_writer_pool();
564
+ function mqtt_encode_connect(ns, mqtt_writer) {
565
+ const _c_mqtt_proto = new Uint8Array([
566
+ 0, 4, 0x4d, 0x51, 0x54, 0x54 ]);
603
567
 
604
- const _c_mqtt_proto = new Uint8Array([
605
- 0, 4, 0x4d, 0x51, 0x54, 0x54 ]);
606
-
607
- function mqtt_encode_connect(ns) {
608
568
  const _enc_flags_connect = flags => 0
609
569
  | ( flags.reserved ? 0x01 : 0 )
610
570
  | ( (flags.will_qos & 0x3) << 3 )
@@ -619,13 +579,13 @@ function mqtt_encode_connect(ns) {
619
579
  | ( will.retain ? 0x20 : 0 );
620
580
 
621
581
  return ns.connect = ( mqtt_level, pkt ) => {
622
- const wrt = new mqtt_type_writer();
582
+ let wrt = mqtt_writer.of(pkt);
623
583
 
624
584
  wrt.push(_c_mqtt_proto);
625
585
  wrt.u8( mqtt_level );
626
586
 
627
- const {will, username, password} = pkt;
628
- const flags = wrt.u8_flags(
587
+ let {will, username, password} = pkt;
588
+ let flags = wrt.flags(
629
589
  pkt.flags,
630
590
  _enc_flags_connect,
631
591
  0 | (username ? 0x80 : 0)
@@ -657,10 +617,10 @@ function mqtt_encode_connect(ns) {
657
617
  }
658
618
  }
659
619
 
660
- function mqtt_encode_publish(ns) {
620
+ function mqtt_encode_publish(ns, mqtt_writer) {
661
621
  return ns.publish = ( mqtt_level, pkt ) => {
662
- const qos = (pkt.qos & 0x3) << 1;
663
- const wrt = new mqtt_type_writer();
622
+ let qos = (pkt.qos & 0x3) << 1;
623
+ let wrt = mqtt_writer.of(pkt);
664
624
 
665
625
  wrt.utf8(pkt.topic);
666
626
  if (0 !== qos)
@@ -678,13 +638,13 @@ function mqtt_encode_publish(ns) {
678
638
  }
679
639
  }
680
640
 
681
- function mqtt_encode_puback(ns) {
641
+ function mqtt_encode_puback(ns, mqtt_writer) {
682
642
  return ns.puback = ( mqtt_level, pkt ) => {
683
- const wrt = new mqtt_type_writer();
643
+ let wrt = mqtt_writer.of(pkt);
684
644
 
685
645
  wrt.u16(pkt.pkt_id);
686
646
  if (5 <= mqtt_level) {
687
- wrt.u8_reason(pkt.reason);
647
+ wrt.reason(pkt.reason);
688
648
  wrt.props(pkt.props);
689
649
  }
690
650
 
@@ -692,32 +652,32 @@ function mqtt_encode_puback(ns) {
692
652
  }
693
653
  }
694
654
 
695
- function mqtt_encode_subscribe(ns) {
655
+ function mqtt_encode_subscribe(ns, mqtt_writer) {
696
656
  const _enc_subscribe_flags = opts => 0
697
657
  | ( opts.qos & 0x3 )
698
658
  | ( opts.retain ? 0x4 : 0 )
699
659
  | ( (opts.retain_handling & 0x3) << 2 );
700
660
 
701
661
  return ns.subscribe = ( mqtt_level, pkt ) => {
702
- const wrt = new mqtt_type_writer();
662
+ let wrt = mqtt_writer.of(pkt);
703
663
 
704
664
  wrt.u16(pkt.pkt_id);
705
665
  if (5 <= mqtt_level)
706
666
  wrt.props(pkt.props);
707
667
 
708
- const f0 = _enc_subscribe_flags(pkt);
709
- for (const each of pkt.topics) {
668
+ let f0 = _enc_subscribe_flags(pkt);
669
+ for (let each of pkt.topics) {
710
670
  if ('string' === typeof each) {
711
671
  wrt.utf8(each);
712
672
  wrt.u8(f0);
713
673
  } else {
714
674
  let [topic, opts] =
715
- _is_array(each) ? each
675
+ Array.isArray(each) ? each
716
676
  : [each.topic, each.opts];
717
677
 
718
678
  wrt.utf8(topic);
719
679
  if (undefined === opts) wrt.u8(f0);
720
- else wrt.u8_flags(opts, _enc_subscribe_flags);
680
+ else wrt.flags(opts, _enc_subscribe_flags);
721
681
  }
722
682
  }
723
683
 
@@ -725,15 +685,15 @@ function mqtt_encode_subscribe(ns) {
725
685
  }
726
686
  }
727
687
 
728
- function mqtt_encode_unsubscribe(ns) {
688
+ function mqtt_encode_unsubscribe(ns, mqtt_writer) {
729
689
  return ns.unsubscribe = ( mqtt_level, pkt ) => {
730
- const wrt = new mqtt_type_writer();
690
+ let wrt = mqtt_writer.of(pkt);
731
691
 
732
692
  wrt.u16(pkt.pkt_id);
733
693
  if (5 <= mqtt_level)
734
694
  wrt.props(pkt.props);
735
695
 
736
- for (const topic of pkt.topics)
696
+ for (let topic of pkt.topics)
737
697
  wrt.utf8(topic);
738
698
 
739
699
  return wrt.as_pkt(0xa2)
@@ -745,13 +705,13 @@ function mqtt_encode_pingxxx(ns) {
745
705
  ns.pingresp = () => new Uint8Array([ 0xd0, 0 ]);
746
706
  }
747
707
 
748
- function mqtt_encode_disconnect(ns) {
708
+ function mqtt_encode_disconnect(ns, mqtt_writer) {
749
709
  return ns.disconnect = ( mqtt_level, pkt ) => {
750
- const wrt = new mqtt_type_writer();
710
+ let wrt = mqtt_writer.of(pkt);
751
711
 
752
712
  if (pkt && 5 <= mqtt_level) {
753
713
  if (pkt.reason || pkt.props) {
754
- wrt.u8_reason(pkt.reason);
714
+ wrt.reason(pkt.reason);
755
715
  wrt.props(pkt.props);
756
716
  }
757
717
  }
@@ -760,185 +720,250 @@ function mqtt_encode_disconnect(ns) {
760
720
  }
761
721
  }
762
722
 
763
- function mqtt_encode_auth(ns) {
723
+ function mqtt_encode_auth(ns, mqtt_writer) {
764
724
  return ns.auth = ( mqtt_level, pkt ) => {
765
725
  if (5 > mqtt_level)
766
726
  throw new Error('Auth packets are only available after MQTT 5.x')
767
727
 
768
- const wrt = new mqtt_type_writer();
728
+ let wrt = mqtt_writer.of(pkt);
769
729
 
770
- wrt.u8_reason(pkt.reason);
730
+ wrt.reason(pkt.reason);
771
731
  wrt.props(pkt.props);
772
732
 
773
733
  return wrt.as_pkt(0xf0)
774
734
  }
775
735
  }
776
736
 
737
+ const mqtt_decode_v5 = [
738
+ mqtt_decode_connack,
739
+ mqtt_decode_publish,
740
+ mqtt_decode_puback,
741
+ mqtt_decode_suback,
742
+ mqtt_decode_unsuback,
743
+ mqtt_decode_pingxxx,
744
+ mqtt_decode_disconnect,
745
+ mqtt_decode_auth,
746
+ ];
747
+
748
+
749
+ const mqtt_encode_v5 = [
750
+ mqtt_encode_connect,
751
+ mqtt_encode_puback,
752
+ mqtt_encode_publish,
753
+ mqtt_encode_subscribe,
754
+ mqtt_encode_unsubscribe,
755
+ mqtt_encode_pingxxx,
756
+ mqtt_encode_disconnect,
757
+ mqtt_encode_auth,
758
+ ];
759
+
760
+ const mqtt_reader_v5 = /* #__PURE__ */
761
+ mqtt_reader_info(
762
+ mqtt_reader_v5$1,
763
+ _connack_v5,
764
+ _puback_v5,
765
+ _suback_v5,
766
+ _unsuback_v4,
767
+ _disconnect_v5,
768
+ _auth_v5,
769
+ );
770
+
771
+
772
+ const mqtt_opts_v5 =
773
+ { decode_fns: mqtt_decode_v5,
774
+ mqtt_reader: mqtt_reader_v5,
775
+ encode_fns: mqtt_encode_v5,
776
+ mqtt_writer: mqtt_writer_v5, };
777
+
778
+ /*
779
+ export function decode_varint_loop(u8, i=0) {
780
+ let i0 = i
781
+ let shift = 0, n = (u8[i] & 0x7f)
782
+ while ( 0x80 & u8[i++] )
783
+ n |= (u8[i] & 0x7f) << (shift += 7)
777
784
 
778
- function _bind_mqtt_decode(lst_decode_ops) {
779
- const by_id = [];
780
- for (const op of lst_decode_ops) op(by_id);
785
+ return [n, i, i0]
786
+ }
787
+ */
781
788
 
782
- return _pkt_ctx_ => _mqtt_raw_pkt_dispatch(
783
- (b0, u8_body) => {
784
- const decode_pkt = by_id[b0>>>4] || by_id[0];
785
- if (undefined !== decode_pkt)
786
- return decode_pkt({__proto__: _pkt_ctx_, b0}, u8_body)
787
- })
789
+
790
+ function decode_varint(u8, i=0) {
791
+ let i0 = i;
792
+ // unrolled for a max of 4 chains
793
+ let n = (u8[i] & 0x7f) << 0;
794
+ if ( 0x80 & u8[i++] ) {
795
+ n |= (u8[i] & 0x7f) << 7;
796
+ if ( 0x80 & u8[i++] ) {
797
+ n |= (u8[i] & 0x7f) << 14;
798
+ if ( 0x80 & u8[i++] ) {
799
+ n |= (u8[i] & 0x7f) << 21;
800
+ }
801
+ }
802
+ }
803
+ return [n, i, i0]
788
804
  }
789
805
 
806
+ function mqtt_raw_dispatch(opt) {
807
+ let u8 = new Uint8Array(0);
808
+ return u8_buf => {
809
+ u8 = 0 === u8.byteLength
810
+ ? u8_buf : _u8_join(u8, u8_buf);
790
811
 
791
- function _bind_mqtt_encode(lst_encode_ops) {
792
- const by_type = {};
793
- for (const op of lst_encode_ops) op(by_type);
812
+ let res = [];
813
+ while (1) {
814
+ let [len_body, len_vh] = decode_varint(u8, 1);
815
+ let len_pkt = len_body + len_vh;
794
816
 
795
- return ({mqtt_level}) => (type, pkt) =>
796
- by_type[type]( mqtt_level, pkt )
797
- }
817
+ if ( u8.byteLength < len_pkt )
818
+ return res
798
819
 
820
+ let b0 = u8[0];
821
+ let u8_body = 0 === len_body ? null
822
+ : u8.subarray(len_vh, len_pkt);
799
823
 
800
- const _pkt_types = ['reserved', 'connect', 'connack', 'publish', 'puback', 'pubrec', 'pubrel', 'pubcomp', 'subscribe', 'suback', 'unsubscribe', 'unsuback', 'pingreq', 'pingresp', 'disconnect', 'auth'];
801
- const _bind_pkt_ctx = _pkt_ctx_ =>
802
- Object.defineProperties(_pkt_ctx_ || {}, {
803
- hdr: {get() { return this.b0 & 0xf }},
804
- id: {get() { return this.b0 >>> 4 }},
805
- type: {get() { return _pkt_types[this.b0 >>> 4] }},
806
- });
824
+ u8 = u8.subarray(len_pkt);
807
825
 
808
- function _bind_mqtt_session_ctx(sess_decode, sess_encode, _pkt_ctx_) {
809
- sess_decode = _bind_mqtt_decode(sess_decode);
810
- sess_encode = _bind_mqtt_encode(sess_encode);
811
- _pkt_ctx_ = _bind_pkt_ctx(_pkt_ctx_);
826
+ let pkt = opt.decode_pkt(b0, u8_body, opt);
827
+ if (null != pkt)
828
+ res.push( pkt );
829
+ }
830
+ }
831
+ }
812
832
 
813
- return mqtt_level => _base_ => {
814
- _base_ = _base_ || {__proto__: _pkt_ctx_, mqtt_level, get _base_() { return _base_ }};
815
- return [ sess_decode(_base_), sess_encode(_base_), _base_ ] }
833
+ function _u8_join(a, b) {
834
+ let alen = a.byteLength, r = new Uint8Array(alen + b.byteLength);
835
+ r.set(a, 0);
836
+ r.set(b, alen);
837
+ return r
816
838
  }
817
839
 
818
- function mqtt_session_ctx(mqtt_level) {
819
- let {ctx} = mqtt_session_ctx;
820
- if (undefined === ctx ) {
821
- let as_utf8 = u8 =>
822
- new TextDecoder('utf-8').decode(u8);
823
-
824
- let std_pkt_api = {
825
- utf8(u8) { return as_utf8( u8 || this.payload ) },
826
- json(u8) { return JSON.parse( this.utf8(u8) || null ) },
827
- text(u8) { return this.utf8(u8) },
828
- };
829
-
830
- mqtt_session_ctx.ctx = ctx =
831
- _bind_mqtt_session_ctx(
832
- [ // lst_decode_ops
833
- mqtt_decode_connack,
834
- mqtt_decode_disconnect,
835
- mqtt_decode_publish,
836
- mqtt_decode_puback,
837
- mqtt_decode_pubxxx,
838
- mqtt_decode_pingxxx,
839
- mqtt_decode_suback,
840
- mqtt_decode_unsuback,
841
- mqtt_decode_auth, ],
842
-
843
- [ // lst_encode_ops
844
- mqtt_encode_connect,
845
- mqtt_encode_disconnect,
846
- mqtt_encode_publish,
847
- mqtt_encode_puback,
848
- mqtt_encode_pingxxx,
849
- mqtt_encode_subscribe,
850
- mqtt_encode_unsubscribe,
851
- mqtt_encode_auth, ],
852
-
853
- std_pkt_api );
854
- }
840
+ const _pkt_types = ['~', 'connect', 'connack', 'publish', 'puback', 'pubrec', 'pubrel', 'pubcomp', 'subscribe', 'suback', 'unsubscribe', 'unsuback', 'pingreq', 'pingresp', 'disconnect', 'auth'];
855
841
 
856
- return ctx(mqtt_level)
842
+ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
843
+ pkt_ctx = {
844
+ __proto__: pkt_ctx || opts.pkt_ctx,
845
+ mqtt_level,
846
+ get hdr() { return this.b0 & 0xf },
847
+ get id() { return this.b0 >>> 4 },
848
+ get type() { return _pkt_types[this.b0 >>> 4] },
849
+ };
850
+
851
+ let op, _decode_by_id=[], _encode_by_type={};
852
+ for (op of opts.encode_fns)
853
+ op(_encode_by_type, opts.mqtt_writer);
854
+ for (op of opts.decode_fns)
855
+ op(_decode_by_id, opts.mqtt_reader);
856
+
857
+ return {
858
+ pkt_ctx,
859
+
860
+ encode_pkt(type, pkt) {
861
+ return _encode_by_type[type]( mqtt_level, pkt ) },
862
+
863
+ decode_pkt(b0, u8_body) {
864
+ let fn_decode = _decode_by_id[b0>>>4] || _decode_by_id[0];
865
+ return fn_decode?.({__proto__: this.pkt_ctx, b0}, u8_body) },
866
+
867
+ mqtt_stream() {
868
+ let self = { __proto__: this, pkt_ctx: { __proto__: pkt_ctx } };
869
+ self.pkt_ctx._base_ = self.pkt_ctx;
870
+ self.decode = mqtt_raw_dispatch(self);
871
+ return self
872
+ },
873
+ }
857
874
  }
858
875
 
859
- function _mqtt_conn(client, [on_mqtt, pkt_future]) {
860
- let q0 = _tiny_deferred_queue();
861
- let q = _tiny_deferred_queue();
876
+ Object.freeze({ao_done: true});
877
+
878
+ function ao_defer_ctx(as_res = (...args) => args) {
879
+ let y,n,_pset = (a,b) => { y=a, n=b; };
880
+ return p =>(
881
+ p = new Promise(_pset)
882
+ , as_res(p, y, n)) }
862
883
 
863
- let _asy_send = async (...args) =>
864
- (await q)(...args);
865
- let _send = client._send = _asy_send;
884
+ const ao_defer_v = /* #__PURE__ */
885
+ ao_defer_ctx();
866
886
 
867
- let _ping = () => client._send('pingreq');
868
- let tid_ping, _is_set = false;
887
+ Promise.resolve({type:'init'});
888
+
889
+ function _mqtt_conn(client, [on_mqtt, pkt_future]) {
890
+ let _q_init = ao_defer_v(), _q_ready = ao_defer_v();
891
+ let _send_ready = async (...args) => (await _q_ready[0])(...args);
892
+ let _send_mqtt_pkt, _has_connected;
893
+ client._send = _send_ready;
869
894
 
870
895
  return {
871
- is_live: (() =>_asy_send !== _send)
872
- , is_set: (() =>_is_set)
896
+ async when_ready() {await _q_ready[0];}
873
897
 
874
- , reset() {
875
- tid_ping = clearInterval(tid_ping);
876
- client._send = _send = _asy_send;
877
- _is_set = false;
898
+ , ping: _ping_interval (() =>_send_mqtt_pkt?.('pingreq'))
878
899
 
879
- // call client.on_reconnect in next promise microtask
880
- _async_evt(client, client.on_reconnect);}
900
+ , reset(err) {
901
+ if (! _send_mqtt_pkt) {return}
881
902
 
882
- , ping(td) {
883
- tid_ping = clearInterval(tid_ping);
884
- if (td) {
885
- tid_ping = setInterval(_ping, 1000 * td);
886
- if (tid_ping.unref) {
887
- tid_ping.unref();} } }
903
+ if (err) {
904
+ _q_init[2](err);}
905
+
906
+ _send_mqtt_pkt = null;
907
+ _q_init = ao_defer_v();
908
+ client._send = _send_ready;
909
+
910
+ // call client.on_conn_reset in next promise microtask
911
+ client.conn_emit('on_disconnect', false===err, err);}
888
912
 
889
913
  , async send_connect(... args) {
890
- if (_asy_send === _send) {
891
- _send = await q0;}
914
+ if (! _send_mqtt_pkt) {
915
+ await _q_init[0]; }// _send_mqtt_pkt is set before fulfilled
892
916
 
893
917
  // await connack response
894
- let res = await _send(...args);
918
+ let res = await _send_mqtt_pkt(...args);
919
+ if (0 == res[0].reason) {
920
+ _has_connected = true;
921
+ // resolve _q_ready[0] with _send_mqtt_pkt closure
922
+ _q_ready[1](client._send = _send_mqtt_pkt);
923
+ _q_ready = ao_defer_v();
924
+ client.conn_emit('on_ready');}
895
925
 
896
- client._send = _send;
897
- q.notify(_send);
898
926
  return res}
899
927
 
900
- , set(mqtt_session, send_u8_pkt) {
901
- _is_set = true;
902
-
903
- let [mqtt_decode, mqtt_encode] = mqtt_session;
928
+ , is_set: (() =>!! _send_mqtt_pkt)
929
+ , set(mqtt_ctx, send_u8_pkt) {
930
+ if (_send_mqtt_pkt) {
931
+ throw new Error('Already connected')}
904
932
 
933
+ mqtt_ctx = mqtt_ctx.mqtt_stream();
934
+ let sess_ctx = {mqtt: client};
905
935
  let on_mqtt_chunk = u8_buf =>
906
- on_mqtt(
907
- mqtt_decode(u8_buf),
908
- {mqtt: client});
936
+ on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx);
909
937
 
910
- _send = async (type, pkt, key) => {
938
+ _send_mqtt_pkt = async (type, pkt, key) => {
911
939
  let res = undefined !== key
912
940
  ? pkt_future(key) : true;
913
941
 
914
942
  await send_u8_pkt(
915
- mqtt_encode(type, pkt));
943
+ mqtt_ctx.encode_pkt(type, pkt));
916
944
 
917
945
  return res};
918
946
 
919
-
920
- q0.notify(_send);
947
+ _q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
921
948
 
922
949
  // call client.on_live in next promise microtask
923
- _async_evt(client, client.on_live);
924
-
950
+ client.conn_emit('on_live', _has_connected);
925
951
  return on_mqtt_chunk} } }
926
952
 
927
953
 
928
- async function _async_evt(obj, evt) {
929
- // microtask break lookup
930
- if (undefined !== evt) {
931
- await evt.call(obj, await obj);
932
- }
933
- }
934
- function _tiny_deferred_queue() {
935
- let q = []; // tiny resetting deferred queue
936
- q.then = y => { q.push(y); };
937
- q.notify = v => {
938
- for (let fn of q.splice(0,q.length))
939
- fn(v); };
940
- return q
941
- }
954
+ function _ping_interval(send_ping) {
955
+ let tid;
956
+ return (( td ) => {
957
+ tid = clearInterval(tid);
958
+ if (td) {
959
+ tid = setInterval(send_ping, 1000 * td);
960
+
961
+
962
+
963
+
964
+ // ensure the interval allows the NodeJS event loop to exit
965
+ tid.unref?.();
966
+ return true} }) }
942
967
 
943
968
  function parse(str, loose) {
944
969
  if (str instanceof RegExp) return { keys:false, pattern:str };
@@ -972,7 +997,7 @@ function parse(str, loose) {
972
997
  function _ignore(pkt, params, ctx) {ctx.done = true;}
973
998
 
974
999
  function _mqtt_topic_router() {
975
- let pri_lsts = [[],[]];
1000
+ let pri_lsts = [[],[]], rm = Symbol();
976
1001
  let find = topic => _mqtt_routes_iter(pri_lsts, topic);
977
1002
 
978
1003
  return {find,
@@ -996,8 +1021,7 @@ function _mqtt_topic_router() {
996
1021
 
997
1022
  , remove(topic_route, priority) {
998
1023
  let lst = pri_lsts[priority ? 0 : 1];
999
- lst = lst.filter(e => e.key !== topic_route);
1000
- pri_lsts[priority ? 0 : 1] = lst;}
1024
+ return _mqtt_route_remove([lst], topic_route)}
1001
1025
 
1002
1026
  , clear(priority) {
1003
1027
  pri_lsts[priority ? 0 : 1] = [];
@@ -1006,9 +1030,13 @@ function _mqtt_topic_router() {
1006
1030
 
1007
1031
  , async invoke(pkt, ctx) {
1008
1032
  ctx.idx = 0;
1033
+ ctx.rm = rm;
1009
1034
 
1010
1035
  for (let [fn, params] of find(pkt.topic)) {
1011
- await fn(pkt, params, ctx);
1036
+ let res = await fn(pkt, params, ctx);
1037
+
1038
+ if (rm === res) {
1039
+ _mqtt_route_remove(pri_lsts, fn);}
1012
1040
 
1013
1041
  if (ctx.done) {
1014
1042
  break}
@@ -1054,6 +1082,14 @@ function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
1054
1082
  params[ keys[i] ] = match[1+i];}
1055
1083
  return [tgt, params]}
1056
1084
 
1085
+
1086
+ function _mqtt_route_remove(all_route_lists, query) {
1087
+ let match = route => route===query || route.tgt===query || route.key===query;
1088
+ for (let lst of all_route_lists) {
1089
+ let i = lst.findIndex(match);
1090
+ if (0 <= i) {return !! lst.splice(i,1)} }
1091
+ return false}
1092
+
1057
1093
  const _mqtt_cmdid_dispatch ={
1058
1094
  create(target) {
1059
1095
  return {__proto__: this, target, hashbelt: [new Map()]} }
@@ -1146,20 +1182,38 @@ function _mqtt_dispatch(opt, target) {
1146
1182
  _disp_.rotate_belt(rotate_n);
1147
1183
  rotate_ts = rotate_td + Date.now();} } }
1148
1184
 
1149
- class MQTTBaseClient {
1185
+ class MQTTError extends Error {
1186
+ constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
1187
+ super(`[0x${reason.toString(16)}] ${reason.reason}`);
1188
+ this.mqtt_pkt = mqtt_pkt;
1189
+ this.reason = reason;} }
1190
+
1191
+ class MQTTBase {
1150
1192
  constructor(opt={}) {
1151
1193
  this._conn_ = _mqtt_conn(this,
1152
1194
  this._init_dispatch(opt, this)); }
1153
1195
 
1196
+ async conn_emit(evt, arg, err_arg) {
1197
+ this.log_conn?.(evt, arg, err_arg);
1198
+ try {
1199
+ let fn_evt = this[await evt]; // microtask break
1200
+ if (fn_evt) {
1201
+ await fn_evt.call(this, this, arg, err_arg);}
1202
+ else if (err_arg) {
1203
+ await this.on_error(err_arg, evt);} }
1204
+ catch (err) {
1205
+ this.on_error(err, evt);} }
1206
+
1207
+ on_error(err, err_path) {
1208
+ console.warn('[[u8-mqtt error: %s]]', err_path, err); }
1209
+
1154
1210
  // Handshaking Packets
1155
1211
 
1156
1212
  async connect(pkt={}) {
1157
- let {client_id: cid} = pkt;
1158
- if (! cid) {
1159
- pkt.client_id = cid = this.init_client_id(['u8-mqtt--', '']);}
1160
- else if (Array.isArray(cid)) {
1213
+ let cid = pkt.client_id || ['u8-mqtt--', ''];
1214
+ if (Array.isArray(cid)) {
1161
1215
  pkt.client_id = cid = this.init_client_id(cid);}
1162
- else {this.client_id = cid;}
1216
+ this.client_id = cid;
1163
1217
 
1164
1218
  if (null == pkt.keep_alive) {
1165
1219
  pkt.keep_alive = 60;}
@@ -1167,13 +1221,16 @@ class MQTTBaseClient {
1167
1221
  let res = await this._conn_
1168
1222
  .send_connect('connect', pkt, 'connack');
1169
1223
 
1224
+ if (0 != res[0].reason) {
1225
+ throw new this.MQTTError(res[0])}
1226
+
1170
1227
  // TODO: merge with server's keep_alive frequency
1171
1228
  this._conn_.ping(pkt.keep_alive);
1172
1229
  return res}
1173
1230
 
1174
1231
  async disconnect(pkt={}) {
1175
1232
  let res = await this._send('disconnect', pkt);
1176
- this._conn_.reset();
1233
+ this._conn_.reset(false);
1177
1234
  return res}
1178
1235
 
1179
1236
  auth(pkt={}) {
@@ -1187,8 +1244,9 @@ class MQTTBaseClient {
1187
1244
  pkt = _as_topics(pkt, ex);
1188
1245
  return this._send('subscribe', pkt, pkt)}
1189
1246
  _sub_chain(topic, ex) {
1247
+ let res = this.subscribe([[ topic ]], ex);
1190
1248
  let subs = this.subs ||(this.subs = new Map());
1191
- subs.set(topic, this.subscribe([[ topic ]], ex));
1249
+ subs.set((res.topic = topic), (subs.last = res));
1192
1250
  return this }// fluent api -- return this and track side effects
1193
1251
 
1194
1252
  // alias: unsub
@@ -1282,22 +1340,19 @@ class MQTTBaseClient {
1282
1340
  return this.router = _mqtt_topic_router()}
1283
1341
 
1284
1342
  _init_dispatch(opt) {
1285
- let router = this._init_router(opt, this);
1286
-
1287
1343
  let tgt ={
1288
1344
  __proto__: opt.on_mqtt_type || {}
1289
- , router};
1290
-
1291
- if (! tgt.mqtt_publish) {
1292
- tgt.mqtt_publish = router.invoke;}
1345
+ , router: this._init_router(opt, this)};
1293
1346
 
1347
+ tgt.mqtt_publish ||= tgt.router.invoke;
1294
1348
  return _mqtt_dispatch(this, tgt)} }
1295
1349
 
1296
1350
 
1297
1351
  {
1298
- let p = MQTTBaseClient.prototype;
1352
+ let p = MQTTBase.prototype;
1299
1353
  Object.assign(p,{
1300
- pub: p.publish
1354
+ MQTTError
1355
+ , pub: p.publish
1301
1356
  , sub: p.subscribe
1302
1357
  , unsub: p.unsubscribe
1303
1358
  , sub_topic: p.subscribe_topic
@@ -1353,7 +1408,7 @@ async function _pub(self, pkt, pub_opt) {
1353
1408
 
1354
1409
  if (pub_opt) {
1355
1410
  if (pub_opt.props) {
1356
- pkt.props = props;}
1411
+ pkt.props = pub_opt.props;}
1357
1412
  if (pub_opt.xform) {
1358
1413
  pkt = pub_opt.xform(pkt) || pkt;} }
1359
1414
 
@@ -1376,45 +1431,67 @@ async function _pub(self, pkt, pub_opt) {
1376
1431
  , oqr: (self, topic, msg, pub_opt) =>
1377
1432
  _pub(self, {topic, msg, arg: 'msg', qos:1, retain: 1}, pub_opt)} ); }
1378
1433
 
1379
- class MQTTCoreClient extends MQTTBaseClient {
1380
- static _with_session(mqtt_session) {
1381
- this.prototype._mqtt_session = mqtt_session;}
1434
+ const pkt_api = {
1435
+ utf8(u8) { return new TextDecoder('utf-8').decode(u8 || this.payload ) },
1436
+ json(u8) { return JSON.parse( this.utf8(u8) || null ) },
1437
+ text(u8) { return this.utf8(u8) },
1438
+ };
1382
1439
 
1440
+ class MQTTCore extends MQTTBase {
1383
1441
  constructor(opt={}) {
1384
1442
  super(opt);
1385
- this.with_live(opt.on_live);
1386
- this.with_reconnect(opt.on_reconnect);}
1387
-
1443
+ this.with(opt);}
1388
1444
 
1389
- // on_live(client) ::
1390
- with_live(on_live) {
1391
- if (on_live) {
1392
- this.on_live = on_live;}
1445
+ static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
1446
+ let self = class extends this {};
1447
+ self.prototype.mqtt_ctx =
1448
+ mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
1449
+ return self}
1393
1450
 
1451
+ with(fns_ns) {
1452
+ for (let [k,v] of Object.entries(fns_ns)) {
1453
+ if ('function' === typeof v) {this[k] = v;} }
1394
1454
  return this}
1395
1455
 
1396
- // on_reconnect(client) ::
1397
- with_reconnect(on_reconnect) {
1398
- if (on_reconnect) {
1399
- this.on_reconnect = on_reconnect;
1456
+ //log_conn(evt, arg, err_arg) ::
1457
+ //console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
1400
1458
 
1401
- if (! this._conn_.is_set) {
1402
- on_reconnect(this);} }
1459
+ on_live(client, is_reconnect) {
1460
+ if (is_reconnect) {
1461
+ return client.connect()} }
1403
1462
 
1404
- return this}
1463
+ //on_reconnect(client) ::
1464
+
1465
+ _use_conn(fn_reconnect) {
1466
+ return (this.reconnect = fn_reconnect)?.()}
1467
+ with_autoreconnect(opt=2000) {
1468
+ if (opt.toFixed) {opt ={delay: opt};}
1469
+ return this.with({
1470
+ on_reconnect() {
1471
+ this.delay(opt.delay || 2000)
1472
+ .then(this.reconnect)
1473
+ .then(opt.reconnect, opt.error);} }) }
1405
1474
 
1475
+ on_disconnect(client, intentional) {
1476
+ if (! intentional) {
1477
+ return client.on_reconnect?.()} }
1478
+
1479
+ delay(ms) {
1480
+ return new Promise(done => setTimeout(done, ms)) }
1406
1481
 
1407
1482
  with_async_iter(async_iter, write_u8_pkt) {
1408
1483
  let on_mqtt_chunk = this._conn_.set(
1409
- this._mqtt_session(),
1484
+ this.mqtt_ctx,
1410
1485
  write_u8_pkt);
1411
1486
 
1412
1487
  this._msg_loop = ((async () => {
1413
- async_iter = await async_iter;
1414
- for await (let chunk of async_iter)
1415
- on_mqtt_chunk(chunk);
1416
-
1417
- this._conn_.reset();})());
1488
+ try {
1489
+ async_iter = await async_iter;
1490
+ for await (let chunk of async_iter)
1491
+ on_mqtt_chunk(chunk);
1492
+ this._conn_.reset();}
1493
+ catch (err) {
1494
+ this._conn_.reset(err);} })());
1418
1495
 
1419
1496
  return this}
1420
1497
 
@@ -1434,16 +1511,17 @@ class MQTTCoreClient extends MQTTBaseClient {
1434
1511
 
1435
1512
 
1436
1513
 
1514
+
1437
1515
 
1438
1516
  with_tcp(port, hostname) {
1439
1517
  if (!Number.isFinite(port)) {
1440
1518
  ({port, hostname} = new URL(port));}
1441
1519
 
1442
- let sock = net.connect(port, hostname);
1443
- return this.with_stream(sock)}
1520
+ return this._use_conn (() =>
1521
+ this.with_stream(
1522
+ node_net.connect(port, hostname)) ) }
1444
1523
 
1445
1524
 
1446
-
1447
1525
  with_stream(read_stream, write_stream) {
1448
1526
  if (undefined === write_stream) {
1449
1527
  write_stream = read_stream;}
@@ -1452,14 +1530,12 @@ class MQTTCoreClient extends MQTTBaseClient {
1452
1530
  u8_pkt => write_stream.write(u8_pkt)) }
1453
1531
 
1454
1532
 
1455
-
1456
-
1457
1533
  with_websock(websock) {
1458
- if (null == websock) {
1459
- websock = 'ws://127.0.0.1:9001';}
1460
-
1461
- if (websock.origin || 'string' === typeof websock) {
1462
- websock = new WebSocket(new URL(websock), ['mqtt']);}
1534
+ if (! websock?.send) {
1535
+ websock = new URL(websock || 'ws://127.0.0.1:9001');
1536
+ return this._use_conn (() =>
1537
+ this.with_websock(
1538
+ new WebSocket(websock, ['mqtt'])) ) }
1463
1539
 
1464
1540
  websock.binaryType = 'arraybuffer';
1465
1541
 
@@ -1468,39 +1544,44 @@ class MQTTCoreClient extends MQTTBaseClient {
1468
1544
  if (0 !== readyState) {
1469
1545
  throw new Error('Invalid WebSocket readyState') }
1470
1546
 
1471
- ready = new Promise( y =>
1472
- websock.addEventListener('open', y, {once: true}));}
1547
+ ready = new Promise(fn => websock.onopen = fn); }
1473
1548
 
1474
1549
 
1475
1550
  let {_conn_} = this;
1476
1551
  let on_mqtt_chunk = _conn_.set(
1477
- this._mqtt_session(),
1552
+ this.mqtt_ctx,
1478
1553
  async u8_pkt =>(
1479
1554
  await ready
1480
1555
  , websock.send(u8_pkt)) );
1481
1556
 
1482
- websock.addEventListener('close',
1483
- (() => {
1484
- delete websock.onmessage;
1485
- _conn_.reset();})
1486
-
1487
- , {once: true});
1557
+ websock.onmessage = evt =>(on_mqtt_chunk(new Uint8Array(evt.data)));
1558
+ websock.onclose = evt => {
1559
+ if (! evt.wasClean) {
1560
+ var err = new Error('websocket connection close');
1561
+ err.code = evt.code;
1562
+ err.reason = evt.reason;}
1488
1563
 
1489
- websock.onmessage = evt =>
1490
- on_mqtt_chunk(
1491
- new Uint8Array(evt.data));
1564
+ _conn_.reset(err);};
1492
1565
 
1493
1566
  return this} }
1494
1567
 
1495
- class MQTTClient_v5 extends MQTTCoreClient {
1496
- _mqtt_session() { return mqtt_session_ctx(5)() }
1497
- }
1568
+ const MQTTClient_v4 = /* #__PURE__ */
1569
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v5);
1570
+
1571
+ const MQTTClient_v5 = /* #__PURE__ */
1572
+ MQTTCore.mqtt_ctx(5, mqtt_opts_v5);
1573
+
1574
+ const mqtt_v4 = opt =>
1575
+ new MQTTClient_v4(opt);
1498
1576
 
1499
- const mqtt_v5 = opt => new MQTTClient_v5(opt);
1577
+ const mqtt_v5 = opt =>
1578
+ new MQTTClient_v5(opt);
1500
1579
 
1501
1580
  exports.MQTTClient = MQTTClient_v5;
1581
+ exports.MQTTClient_v4 = MQTTClient_v4;
1502
1582
  exports.MQTTClient_v5 = MQTTClient_v5;
1503
1583
  exports["default"] = mqtt_v5;
1504
1584
  exports.mqtt = mqtt_v5;
1585
+ exports.mqtt_v4 = mqtt_v4;
1505
1586
  exports.mqtt_v5 = mqtt_v5;
1506
1587
  //# sourceMappingURL=v5.cjs.map