u8-mqtt 0.1.2 → 0.3.0

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