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