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