u8-mqtt 0.1.3 → 0.3.1

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