u8-mqtt 0.1.3 → 0.3.1

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