u8-mqtt 0.1.3 → 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 +632 -557
  3. package/cjs/index.cjs.map +1 -1
  4. package/cjs/v4.cjs +479 -662
  5. package/cjs/v4.cjs.map +1 -1
  6. package/cjs/v5.cjs +631 -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 +4 -4
  13. package/code/v4.mjs +6 -6
  14. package/code/v5.mjs +14 -6
  15. package/esm/deno/index.js +635 -562
  16. package/esm/deno/index.js.map +1 -1
  17. package/esm/deno/v4.js +486 -669
  18. package/esm/deno/v4.js.map +1 -1
  19. package/esm/deno/v5.js +637 -558
  20. package/esm/deno/v5.js.map +1 -1
  21. package/esm/node/index.js +628 -555
  22. package/esm/node/index.js.map +1 -1
  23. package/esm/node/index.mjs +628 -555
  24. package/esm/node/index.mjs.map +1 -1
  25. package/esm/node/v4.js +479 -662
  26. package/esm/node/v4.js.map +1 -1
  27. package/esm/node/v4.mjs +479 -662
  28. package/esm/node/v4.mjs.map +1 -1
  29. package/esm/node/v5.js +630 -551
  30. package/esm/node/v5.js.map +1 -1
  31. package/esm/node/v5.mjs +630 -551
  32. package/esm/node/v5.mjs.map +1 -1
  33. package/esm/web/index.js +630 -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 +481 -664
  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 +632 -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 +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/web/v4.mjs DELETED
@@ -1,1496 +0,0 @@
1
- function encode_varint(n, a=[]) {
2
- do {
3
- const ni = n & 0x7f;
4
- n >>>= 7;
5
- a.push( ni | (0===n ? 0 : 0x80) );
6
- } while (n > 0)
7
- return a
8
- }
9
-
10
-
11
- /*
12
- export function decode_varint_loop(u8, i=0) {
13
- let i0 = i
14
- let shift = 0, n = (u8[i] & 0x7f)
15
- while ( 0x80 & u8[i++] )
16
- n |= (u8[i] & 0x7f) << (shift += 7)
17
-
18
- return [n, i, i0]
19
- }
20
- */
21
-
22
-
23
- function decode_varint(u8, i=0) {
24
- let i0 = i;
25
- // unrolled for a max of 4 chains
26
- let n = (u8[i] & 0x7f) << 0;
27
- if ( 0x80 & u8[i++] ) {
28
- n |= (u8[i] & 0x7f) << 7;
29
- if ( 0x80 & u8[i++] ) {
30
- n |= (u8[i] & 0x7f) << 14;
31
- if ( 0x80 & u8[i++] ) {
32
- n |= (u8[i] & 0x7f) << 21;
33
- }
34
- }
35
- }
36
- return [n, i, i0]
37
- }
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);
112
- }
113
- }
114
-
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) }
129
- }
130
-
131
- has_more() {
132
- const {buf, step} = this;
133
- return buf.byteLength > step(0)
134
- }
135
-
136
- u8() {
137
- const {buf, step} = this;
138
- return buf[step(1)]
139
- }
140
-
141
- u16() {
142
- const {buf, step} = this;
143
- const i = step(2);
144
- return (buf[i]<<8) | buf[i+1]
145
- }
146
-
147
- u32() {
148
- const {buf, step} = this;
149
- const i = step(4);
150
- return (buf[i]<<24) | (buf[i+1]<<16) | (buf[i+2]<<8) | buf[i+3]
151
- }
152
-
153
- vint() {
154
- const {buf, step} = this;
155
- const [n, vi, vi0] = decode_varint(buf, step(0));
156
- step(vi - vi0);
157
- return n
158
- }
159
-
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
- 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)
174
- }
175
-
176
- utf8() { return as_utf8(this.bin()) }
177
- pair() { return [ as_utf8(this.bin()), as_utf8(this.bin()) ] }
178
-
179
- u8_flags(FlagsType) {
180
- const {buf, step} = this;
181
- return new FlagsType(buf[step(1)])
182
- }
183
-
184
- u8_reason(fn_reason) {
185
- const {buf, step} = this;
186
- return fn_reason( buf[step(1)] )
187
- }
188
-
189
- flush() {
190
- const {buf, step} = this;
191
- this.step = this.buf = null;
192
- return buf.subarray(step(0))
193
- }
194
-
195
- props() {
196
- let sub = this.vbuf();
197
- return null === sub ? null
198
- : this._fork(sub, 0)._read_props([])
199
- }
200
-
201
- _read_props(lst) {
202
- while (this.has_more()) {
203
- let k = this.u8();
204
- let p = mqtt_props.get( k );
205
- let v = this[p.type]();
206
- lst.push([p.name, v]);
207
- }
208
- return lst
209
- }
210
- }
211
-
212
-
213
-
214
- class U8_Reason extends Number {
215
- constructor(u8, reason) { super(u8); this.reason = reason; }
216
- }
217
-
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) );
222
-
223
- return reason_map.get.bind(reason_map)
224
- }
225
-
226
- function mqtt_decode_connack(ns) {
227
- class _connack_flags_ extends Number {
228
- get session_present() { return this & 0x01 !== 0 }
229
- }
230
-
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'],
239
-
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
- ]);
262
-
263
-
264
- return ns[0x2] = (pkt, u8_body) => {
265
- const rdr = new mqtt_type_reader(u8_body, 0);
266
-
267
- pkt.flags =
268
- rdr.u8_flags(_connack_flags_);
269
-
270
- pkt.reason = rdr.u8_reason(_connack_reason_);
271
- if (5 <= pkt.mqtt_level)
272
- pkt.props = rdr.props();
273
- return pkt }
274
- }
275
-
276
- function mqtt_decode_publish(ns) {
277
- return ns[0x3] = (pkt, u8_body) => {
278
- const {hdr} = pkt;
279
- pkt.dup = Boolean(hdr & 0x8);
280
- pkt.retain = Boolean(hdr & 0x1);
281
- const qos = pkt.qos = (hdr>>1) & 0x3;
282
-
283
- const rdr = new mqtt_type_reader(u8_body, 0);
284
- pkt.topic = rdr.utf8();
285
- if (0 !== qos)
286
- pkt.pkt_id = rdr.u16();
287
-
288
- if (5 <= pkt.mqtt_level)
289
- pkt.props = rdr.props();
290
-
291
- pkt.payload = rdr.flush();
292
- return pkt }
293
- }
294
-
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
-
311
- return ns[0x4] = (pkt, u8_body) => {
312
- const rdr = new mqtt_type_reader(u8_body, 0);
313
-
314
- pkt.pkt_id = rdr.u16();
315
- if (5 <= pkt.mqtt_level) {
316
- pkt.reason = rdr.u8_reason(_puback_reason_);
317
- pkt.props = rdr.props();
318
- }
319
-
320
- return pkt }
321
- }
322
-
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_) {
340
- return (pkt, u8_body) => {
341
- const rdr = new mqtt_type_reader(u8_body, 0);
342
-
343
- pkt.pkt_id = rdr.u16();
344
- if (5 <= pkt.mqtt_level)
345
- pkt.props = rdr.props();
346
-
347
- const answers = pkt.answers = [];
348
- while (rdr.has_more())
349
- answers.push(
350
- rdr.u8_reason(_ack_reason_) );
351
-
352
- return pkt }
353
- }
354
-
355
- function mqtt_decode_suback(ns) {
356
- const _suback_reason_ = bind_reason_lookup([
357
- // MQTT 3.1.1
358
- [ 0x00, 'Granted QoS 0'],
359
- [ 0x01, 'Granted QoS 1'],
360
- [ 0x02, 'Granted QoS 2'],
361
-
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_)
375
- }
376
-
377
- function mqtt_decode_unsuback(ns) {
378
- const _unsuback_reason_ = bind_reason_lookup([
379
- [ 0x00, 'Success'],
380
- [ 0x11, 'No subscription existed'],
381
- [ 0x80, 'Unspecified error'],
382
- [ 0x83, 'Implementation specific error'],
383
- [ 0x87, 'Not authorized'],
384
- [ 0x8F, 'Topic Filter invalid'],
385
- [ 0x91, 'Packet Identifier in use'],
386
- ]);
387
-
388
- return ns[0xb] = _mqtt_decode_suback(_unsuback_reason_)
389
- }
390
-
391
- function mqtt_decode_pingxxx(ns) {
392
- return ns[0xc] = ns[0xd] = pkt => pkt
393
- }
394
-
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
-
430
- return ns[0xe] = (pkt, u8_body) => {
431
- if (u8_body && 5 <= pkt.mqtt_level) {
432
- const rdr = new mqtt_type_reader(u8_body, 0);
433
- pkt.reason = rdr.u8_reason(_disconnect_reason_);
434
- pkt.props = rdr.props();
435
- }
436
- return pkt }
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_);
451
- pkt.props = rdr.props();
452
- }
453
- return pkt }
454
- }
455
-
456
- function mqtt_pkt_writer_pool() {
457
- const _pool_ = [];
458
- return host =>
459
- 0 === _pool_.length
460
- ? mqtt_pkt_writer(host, _pool_)
461
- : _pool_.pop()(host)
462
- }
463
-
464
- function mqtt_pkt_writer(host, _pool_) {
465
- // avoid GCing push/pull when they can be reused
466
- let n=0, rope=[];
467
- return install(host)
468
-
469
- function install(_host) {
470
- host = _host;
471
- host.push = push;
472
- host.pack = pack;
473
- }
474
-
475
- function push(u8) {
476
- rope.push(u8);
477
- n += u8.length;
478
- }
479
-
480
- function pack(hdr) {
481
- host = host.push = host.pack = null;
482
-
483
- const res = _mqtt_pkt_rope(hdr, n, rope);
484
- n=0; rope=[];
485
- if (undefined !== _pool_)
486
- _pool_.push(install);
487
-
488
- return res
489
- }
490
- }
491
-
492
-
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
- const _enc_flags_connect = flags => 0
603
- | ( flags.reserved ? 0x01 : 0 )
604
- | ( (flags.will_qos & 0x3) << 3 )
605
- | ( flags.clean_start ? 0x02 : 0 )
606
- | ( flags.will_flag ? 0x04 : 0 )
607
- | ( flags.will_retain ? 0x20 : 0 )
608
- | ( flags.password ? 0x40 : 0 )
609
- | ( flags.username ? 0x80 : 0 );
610
-
611
- const _enc_flags_will = will => 0x4
612
- | ( (will.qos & 0x3) << 3 )
613
- | ( will.retain ? 0x20 : 0 );
614
-
615
- return ns.connect = ( mqtt_level, pkt ) => {
616
- const wrt = new mqtt_type_writer();
617
-
618
- wrt.push(_c_mqtt_proto);
619
- wrt.u8( mqtt_level );
620
-
621
- const {will, username, password} = pkt;
622
- const flags = wrt.u8_flags(
623
- pkt.flags,
624
- _enc_flags_connect,
625
- 0 | (username ? 0x80 : 0)
626
- | (password ? 0x40 : 0)
627
- | (will ? _enc_flags_will(will) : 0) );
628
-
629
- wrt.u16(pkt.keep_alive);
630
-
631
- if (5 <= mqtt_level)
632
- wrt.props(pkt.props);
633
-
634
-
635
- wrt.utf8(pkt.client_id);
636
- if (flags & 0x04) { // .will_flag
637
- if (5 <= mqtt_level)
638
- wrt.props(will.props);
639
-
640
- wrt.utf8(will.topic);
641
- wrt.bin(will.payload);
642
- }
643
-
644
- if (flags & 0x80) // .username
645
- wrt.utf8(username);
646
-
647
- if (flags & 0x40) // .password
648
- wrt.bin(password);
649
-
650
- return wrt.as_pkt(0x10)
651
- }
652
- }
653
-
654
- function mqtt_encode_publish(ns) {
655
- return ns.publish = ( mqtt_level, pkt ) => {
656
- const qos = (pkt.qos & 0x3) << 1;
657
- const wrt = new mqtt_type_writer();
658
-
659
- wrt.utf8(pkt.topic);
660
- if (0 !== qos)
661
- wrt.u16(pkt.pkt_id);
662
-
663
- if ( 5 <= mqtt_level) {
664
- wrt.props(pkt.props);
665
- wrt.flush(pkt.payload);
666
- } else {
667
- wrt.flush(pkt.payload);
668
- }
669
-
670
- return wrt.as_pkt(
671
- 0x30 | qos | (pkt.dup ? 0x8 : 0) | (pkt.retain ? 0x1 : 0) )
672
- }
673
- }
674
-
675
- function mqtt_encode_puback(ns) {
676
- return ns.puback = ( mqtt_level, pkt ) => {
677
- const wrt = new mqtt_type_writer();
678
-
679
- wrt.u16(pkt.pkt_id);
680
- if (5 <= mqtt_level) {
681
- wrt.u8_reason(pkt.reason);
682
- wrt.props(pkt.props);
683
- }
684
-
685
- return wrt.as_pkt(0x40)
686
- }
687
- }
688
-
689
- function mqtt_encode_subscribe(ns) {
690
- const _enc_subscribe_flags = opts => 0
691
- | ( opts.qos & 0x3 )
692
- | ( opts.retain ? 0x4 : 0 )
693
- | ( (opts.retain_handling & 0x3) << 2 );
694
-
695
- return ns.subscribe = ( mqtt_level, pkt ) => {
696
- const wrt = new mqtt_type_writer();
697
-
698
- wrt.u16(pkt.pkt_id);
699
- if (5 <= mqtt_level)
700
- wrt.props(pkt.props);
701
-
702
- const f0 = _enc_subscribe_flags(pkt);
703
- for (const each of pkt.topics) {
704
- if ('string' === typeof each) {
705
- wrt.utf8(each);
706
- wrt.u8(f0);
707
- } else {
708
- let [topic, opts] =
709
- _is_array(each) ? each
710
- : [each.topic, each.opts];
711
-
712
- wrt.utf8(topic);
713
- if (undefined === opts) wrt.u8(f0);
714
- else wrt.u8_flags(opts, _enc_subscribe_flags);
715
- }
716
- }
717
-
718
- return wrt.as_pkt(0x82)
719
- }
720
- }
721
-
722
- function mqtt_encode_unsubscribe(ns) {
723
- return ns.unsubscribe = ( mqtt_level, pkt ) => {
724
- const wrt = new mqtt_type_writer();
725
-
726
- wrt.u16(pkt.pkt_id);
727
- if (5 <= mqtt_level)
728
- wrt.props(pkt.props);
729
-
730
- for (const topic of pkt.topics)
731
- wrt.utf8(topic);
732
-
733
- return wrt.as_pkt(0xa2)
734
- }
735
- }
736
-
737
- function mqtt_encode_pingxxx(ns) {
738
- ns.pingreq = () => new Uint8Array([ 0xc0, 0 ]);
739
- ns.pingresp = () => new Uint8Array([ 0xd0, 0 ]);
740
- }
741
-
742
- function mqtt_encode_disconnect(ns) {
743
- return ns.disconnect = ( mqtt_level, pkt ) => {
744
- const wrt = new mqtt_type_writer();
745
-
746
- if (pkt && 5 <= mqtt_level) {
747
- if (pkt.reason || pkt.props) {
748
- wrt.u8_reason(pkt.reason);
749
- wrt.props(pkt.props);
750
- }
751
- }
752
-
753
- return wrt.as_pkt(0xe0)
754
- }
755
- }
756
-
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')
761
-
762
- const wrt = new mqtt_type_writer();
763
-
764
- wrt.u8_reason(pkt.reason);
765
- wrt.props(pkt.props);
766
-
767
- return wrt.as_pkt(0xf0)
768
- }
769
- }
770
-
771
-
772
- function _bind_mqtt_decode(lst_decode_ops) {
773
- const by_id = [];
774
- for (const op of lst_decode_ops) op(by_id);
775
-
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
- }
783
-
784
-
785
- function _bind_mqtt_encode(lst_encode_ops) {
786
- const by_type = {};
787
- for (const op of lst_encode_ops) op(by_type);
788
-
789
- return ({mqtt_level}) => (type, pkt) =>
790
- by_type[type]( mqtt_level, pkt )
791
- }
792
-
793
-
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
- });
801
-
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_);
806
-
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
- }
811
-
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
- }
849
-
850
- return ctx(mqtt_level)
851
- }
852
-
853
- function _mqtt_conn(client, [on_mqtt, pkt_future]) {
854
- let q0 = _tiny_deferred_queue();
855
- let q = _tiny_deferred_queue();
856
-
857
- let _asy_send = async (...args) =>
858
- (await q)(...args);
859
- let _send = client._send = _asy_send;
860
-
861
- let _ping = () => client._send('pingreq');
862
- let tid_ping, _is_set = false;
863
-
864
- return {
865
- is_live: (() =>_asy_send !== _send)
866
- , is_set: (() =>_is_set)
867
-
868
- , reset() {
869
- tid_ping = clearInterval(tid_ping);
870
- client._send = _send = _asy_send;
871
- _is_set = false;
872
-
873
- // call client.on_reconnect in next promise microtask
874
- _async_evt(client, client.on_reconnect);}
875
-
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();} } }
882
-
883
- , async send_connect(... args) {
884
- if (_asy_send === _send) {
885
- _send = await q0;}
886
-
887
- // await connack response
888
- let res = await _send(...args);
889
-
890
- client._send = _send;
891
- q.notify(_send);
892
- return res}
893
-
894
- , set(mqtt_session, send_u8_pkt) {
895
- _is_set = true;
896
-
897
- let [mqtt_decode, mqtt_encode] = mqtt_session;
898
-
899
- let on_mqtt_chunk = u8_buf =>
900
- on_mqtt(
901
- mqtt_decode(u8_buf),
902
- {mqtt: client});
903
-
904
- _send = async (type, pkt, key) => {
905
- let res = undefined !== key
906
- ? pkt_future(key) : true;
907
-
908
- await send_u8_pkt(
909
- mqtt_encode(type, pkt));
910
-
911
- return res};
912
-
913
-
914
- q0.notify(_send);
915
-
916
- // call client.on_live in next promise microtask
917
- _async_evt(client, client.on_live);
918
-
919
- return on_mqtt_chunk} } }
920
-
921
-
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
- }
936
-
937
- function parse(str, loose) {
938
- if (str instanceof RegExp) return { keys:false, pattern:str };
939
- var c, o, tmp, ext, keys=[], pattern='', arr = str.split('/');
940
- arr[0] || arr.shift();
941
-
942
- while (tmp = arr.shift()) {
943
- c = tmp[0];
944
- if (c === '*') {
945
- keys.push('wild');
946
- pattern += '/(.*)';
947
- } else if (c === ':') {
948
- o = tmp.indexOf('?', 1);
949
- ext = tmp.indexOf('.', 1);
950
- keys.push( tmp.substring(1, !!~o ? o : !!~ext ? ext : tmp.length) );
951
- pattern += !!~o && !~ext ? '(?:/([^/]+?))?' : '/([^/]+?)';
952
- if (!!~ext) pattern += (!!~o ? '?' : '') + '\\' + tmp.substring(ext);
953
- } else {
954
- pattern += '/' + tmp;
955
- }
956
- }
957
-
958
- return {
959
- keys: keys,
960
- pattern: new RegExp('^' + pattern + (loose ? '(?=$|\/)' : '\/?$'), 'i')
961
- };
962
- }
963
-
964
- // Use [regexparam][] for url-like topic parsing
965
-
966
- function _ignore(pkt, params, ctx) {ctx.done = true;}
967
-
968
- function _mqtt_topic_router() {
969
- let pri_lsts = [[],[]];
970
- let find = topic => _mqtt_routes_iter(pri_lsts, topic);
971
-
972
- return {find,
973
-
974
- add(topic_route, ...args) {
975
- let fn = args.pop();
976
- let priority = args.pop();
977
-
978
- if ('function' !== typeof fn) {
979
- if (false === fn) {
980
- fn = _ignore;}
981
- else throw new TypeError()}
982
-
983
- let rte = parse(
984
- topic_route.replace(/[+#]$/, '*'));
985
-
986
- rte.key = topic_route;
987
- rte.tgt = fn;
988
- pri_lsts[priority ? 0 : 1].push(rte);
989
- return this}
990
-
991
- , remove(topic_route, priority) {
992
- let lst = pri_lsts[priority ? 0 : 1];
993
- lst = lst.filter(e => e.key !== topic_route);
994
- pri_lsts[priority ? 0 : 1] = lst;}
995
-
996
- , clear(priority) {
997
- pri_lsts[priority ? 0 : 1] = [];
998
- if (null == priority) {
999
- pri_lsts[1] = [];} }
1000
-
1001
- , async invoke(pkt, ctx) {
1002
- ctx.idx = 0;
1003
-
1004
- for (let [fn, params] of find(pkt.topic)) {
1005
- await fn(pkt, params, ctx);
1006
-
1007
- if (ctx.done) {
1008
- break}
1009
- else ctx.idx++;}
1010
-
1011
- let {pkt_id, qos} = pkt;
1012
- if (1 === qos) {
1013
- await ctx.mqtt._send('puback', {pkt_id});} } } }
1014
-
1015
-
1016
- function * _mqtt_routes_iter(all_route_lists, topic) {
1017
- for (let route_list of all_route_lists) {
1018
- for (let route of route_list) {
1019
- let res = _mqtt_route_match_one(topic, route);
1020
- if (undefined !== res) {
1021
- yield res;} } } }
1022
-
1023
-
1024
- function _mqtt_route_match_one(topic, {keys, pattern, tgt}) {
1025
- let match = '/' !== topic[0]
1026
- ? pattern.exec('/'+topic)
1027
- : pattern.exec(topic);
1028
-
1029
- if (null === match) {
1030
- return}
1031
-
1032
- if (false === keys) {
1033
- let {groups} = match;
1034
- if (! groups) {
1035
- return [tgt]}
1036
-
1037
- let params = {};
1038
- for (let k in groups) {
1039
- params[k] = groups[k];}
1040
-
1041
- return [tgt, params]}
1042
-
1043
- if (0 === keys.length) {
1044
- return [tgt]}
1045
-
1046
- let params = {};
1047
- for (let i=0; i<keys.length; i++) {
1048
- params[ keys[i] ] = match[1+i];}
1049
- return [tgt, params]}
1050
-
1051
- const _mqtt_cmdid_dispatch ={
1052
- create(target) {
1053
- return {__proto__: this, target, hashbelt: [new Map()]} }
1054
-
1055
- , bind_pkt_future(_pkt_id=100) {
1056
- let {hashbelt} = this;
1057
-
1058
- let _tmp_; // use _tmp_ to reuse _by_key closure
1059
- let _by_key = answer_monad =>
1060
- hashbelt[0].set(_tmp_, answer_monad);
1061
-
1062
- return (( pkt_or_key ) => {
1063
- if ('string' === typeof pkt_or_key) {
1064
- _tmp_ = pkt_or_key;}
1065
- else {
1066
- _pkt_id = (_pkt_id + 1) & 0xffff;
1067
- _tmp_ = pkt_or_key.pkt_id = _pkt_id;}
1068
-
1069
- return new Promise(_by_key)}) }
1070
-
1071
- , answer(key, pkt) {
1072
- for (let map of this.hashbelt) {
1073
- let answer_monad = map.get(key);
1074
- if (undefined !== answer_monad) {
1075
- map.delete(key);
1076
-
1077
- answer_monad([pkt, /*err*/]); // option/maybe monad
1078
- return true} }
1079
- return false}
1080
-
1081
- , rotate_belt(n) {
1082
- let {hashbelt} = this;
1083
- hashbelt.unshift(new Map());
1084
- for (let old of hashbelt.splice(n || 5)) {
1085
- for (let answer_monad of old.values()) {
1086
- answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
1087
-
1088
- , cmdids: ((() => {
1089
- return [
1090
- (() =>{} )// 0x0 reserved
1091
- , by_evt // 0x1 connect
1092
- , by_type // 0x2 connack
1093
- , by_evt // 0x3 publish
1094
- , by_id // 0x4 puback
1095
- , by_id // 0x5 pubrec
1096
- , by_id // 0x6 pubrel
1097
- , by_id // 0x7 pubcomp
1098
- , by_evt // 0x8 subscribe
1099
- , by_id // 0x9 suback
1100
- , by_evt // 0xa unsubscribe
1101
- , by_id // 0xb unsuback
1102
- , by_type // 0xc pingreq
1103
- , by_type // 0xd pingresp
1104
- , by_evt // 0xe disconnect
1105
- , by_type ]// 0xf auth
1106
-
1107
-
1108
- function by_id(disp, pkt) {
1109
- disp.answer(pkt.pkt_id, pkt); }
1110
-
1111
- function by_type(disp, pkt, ctx) {
1112
- disp.answer(pkt.type, pkt);
1113
- by_evt(disp, pkt, ctx);}
1114
-
1115
- async function by_evt({target}, pkt, ctx) {
1116
- let fn = target[`mqtt_${pkt.type}`]
1117
- || target.mqtt_pkt;
1118
-
1119
- if (undefined !== fn) {
1120
- await fn.call(target, pkt, ctx);} } })()) };
1121
-
1122
- function _mqtt_dispatch(opt, target) {
1123
- let _disp_ = _mqtt_cmdid_dispatch.create(target);
1124
- let { cmdids } = _disp_;
1125
-
1126
- // default rotate at 1s across 5 buckets
1127
- let { td: rotate_td=1000, n: rotate_n=5 } =
1128
- opt && opt.rotate || {};
1129
-
1130
- let rotate_ts = rotate_td + Date.now();
1131
-
1132
- return [on_mqtt,
1133
- _disp_.bind_pkt_future()]
1134
-
1135
- function on_mqtt(pkt_list, ctx) {
1136
- for (let pkt of pkt_list) {
1137
- cmdids[pkt.id](_disp_, pkt, ctx); }
1138
-
1139
- if (Date.now() > rotate_ts) {
1140
- _disp_.rotate_belt(rotate_n);
1141
- rotate_ts = rotate_td + Date.now();} } }
1142
-
1143
- class MQTTBaseClient {
1144
- constructor(opt={}) {
1145
- this._conn_ = _mqtt_conn(this,
1146
- this._init_dispatch(opt, this)); }
1147
-
1148
- // Handshaking Packets
1149
-
1150
- 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)) {
1155
- pkt.client_id = cid = this.init_client_id(cid);}
1156
- else {this.client_id = cid;}
1157
-
1158
- if (null == pkt.keep_alive) {
1159
- pkt.keep_alive = 60;}
1160
-
1161
- let res = await this._conn_
1162
- .send_connect('connect', pkt, 'connack');
1163
-
1164
- // TODO: merge with server's keep_alive frequency
1165
- this._conn_.ping(pkt.keep_alive);
1166
- return res}
1167
-
1168
- async disconnect(pkt={}) {
1169
- let res = await this._send('disconnect', pkt);
1170
- this._conn_.reset();
1171
- return res}
1172
-
1173
- auth(pkt={}) {
1174
- return this._send('auth', pkt, 'auth')}
1175
-
1176
- ping() {return this._send('pingreq', null, 'pingresp')}
1177
-
1178
-
1179
- // alias: sub
1180
- subscribe(pkt, ex) {
1181
- pkt = _as_topics(pkt, ex);
1182
- return this._send('subscribe', pkt, pkt)}
1183
- _sub_chain(topic, ex) {
1184
- let subs = this.subs ||(this.subs = new Map());
1185
- subs.set(topic, this.subscribe([[ topic ]], ex));
1186
- return this }// fluent api -- return this and track side effects
1187
-
1188
- // alias: unsub
1189
- unsubscribe(pkt, ex) {
1190
- pkt = _as_topics(pkt, ex);
1191
- return this._send('unsubscribe', pkt, pkt)}
1192
-
1193
- get on_topic() {return this.router.add}
1194
-
1195
- // alias: sub_topic
1196
- subscribe_topic(topic_route, ...args) {
1197
- this.router.add(topic_route, true, args.pop() );// handler
1198
- let topic = this.topic_for(topic_route);
1199
- return this._sub_chain(topic, args.pop() ) }// ex
1200
-
1201
- // alias: unsub_topic
1202
- unsubscribe_topic(topic_route) {
1203
- this.router.remove(topic_route, true);
1204
- let topic = this.topic_for(topic_route);
1205
- return this.unsubscribe([[ topic ]]) }
1206
-
1207
- // alias: shared_sub
1208
- shared_subscribe(group, topic_route, ...args) {
1209
- this.router.add(topic_route, true, args.pop() );// handler
1210
- let topic = this.topic_for(topic_route);
1211
- if (null != group) {
1212
- topic = `$share/${group}/${topic}`;}
1213
- return this._sub_chain(topic, args.pop() ) }// ex
1214
-
1215
- // alias: shared_unsub
1216
- shared_unsubscribe(group, topic_route) {
1217
- this.router.remove(topic_route, true);
1218
- let topic = this.topic_for(topic_route);
1219
- if (null != group) {
1220
- topic = `$share/${group}/${topic}`;}
1221
- return this.unsubscribe([[ topic ]]) }
1222
-
1223
- topic_for(topic_route) {
1224
- return topic_route.replace(/[:*].*$/, '#')}
1225
-
1226
-
1227
- // alias: pub
1228
- publish(pkt, pub_opt) {return _pub(this, pkt, pub_opt)}
1229
- post(topic, payload, pub_opt) {return _pub.m(this, topic, payload, pub_opt)}
1230
- send(topic, payload, pub_opt) {return _pub.mq(this, topic, payload, pub_opt)}
1231
- store(topic, payload, pub_opt) {return _pub.mqr(this, topic, payload, pub_opt)}
1232
-
1233
- json_post(topic, msg, pub_opt) {return _pub.o(this, topic, msg, pub_opt)}
1234
- json_send(topic, msg, pub_opt) {return _pub.oq(this, topic, msg, pub_opt)}
1235
- json_store(topic, msg, pub_opt) {return _pub.oqr(this, topic, msg, pub_opt)}
1236
-
1237
- obj_post(topic, msg, pub_opt) {return _pub.o(this, topic, msg, pub_opt)}
1238
- obj_send(topic, msg, pub_opt) {return _pub.oq(this, topic, msg, pub_opt)}
1239
- obj_store(topic, msg, pub_opt) {return _pub.oqr(this, topic, msg, pub_opt)}
1240
-
1241
-
1242
-
1243
- // Utility Methods
1244
-
1245
- init_client_id(parts) {
1246
- let cid = this.client_id;
1247
-
1248
- if (undefined === cid) {
1249
- this.client_id = cid = (
1250
-
1251
- this.sess_client_id(parts)
1252
-
1253
-
1254
- );}
1255
-
1256
- return cid}
1257
-
1258
- new_client_id(parts) {
1259
- return [parts[0], Math.random().toString(36).slice(2), parts[1]].join('')}
1260
-
1261
-
1262
- sess_client_id(parts) {
1263
- let key = `client_id ${parts.join('')}`;
1264
- let cid = sessionStorage.getItem(key);
1265
- if (null == cid) {
1266
- cid = this.new_client_id(parts);
1267
- sessionStorage.setItem(key, cid);}
1268
- return cid}
1269
-
1270
-
1271
- // Internal API
1272
-
1273
- /* async _send(type, pkt) -- provided by _conn_ and transport */
1274
-
1275
- _init_router(opt) {
1276
- return this.router = _mqtt_topic_router()}
1277
-
1278
- _init_dispatch(opt) {
1279
- let router = this._init_router(opt, this);
1280
-
1281
- let tgt ={
1282
- __proto__: opt.on_mqtt_type || {}
1283
- , router};
1284
-
1285
- if (! tgt.mqtt_publish) {
1286
- tgt.mqtt_publish = router.invoke;}
1287
-
1288
- return _mqtt_dispatch(this, tgt)} }
1289
-
1290
-
1291
- {
1292
- let p = MQTTBaseClient.prototype;
1293
- Object.assign(p,{
1294
- pub: p.publish
1295
- , sub: p.subscribe
1296
- , unsub: p.unsubscribe
1297
- , sub_topic: p.subscribe_topic
1298
- , unsub_topic: p.unsubscribe_topic
1299
- , shared_sub: p.shared_subscribe
1300
- , shared_unsub: p.shared_unsubscribe} );
1301
-
1302
- /*
1303
- p.on_mqtt_type = {
1304
- mqtt_auth(pkt, ctx) ::
1305
- mqtt_connect(pkt, ctx) ::
1306
- mqtt_connack(pkt, ctx) ::
1307
- mqtt_disconnect(pkt, ctx) ::
1308
-
1309
- mqtt_publish(pkt, ctx)
1310
- mqtt_subscribe(pkt, ctx) ::
1311
- mqtt_unsubscribe(pkt, ctx) ::
1312
-
1313
- mqtt_pingreq(pkt, ctx) ::
1314
- mqtt_pingresp(pkt, ctx) ::
1315
- }
1316
- */}
1317
-
1318
-
1319
- function _as_topics(pkt, ex) {
1320
- if ('string' === typeof pkt) {
1321
- return {topics:[pkt], ... ex}}
1322
- if (pkt[Symbol.iterator]) {
1323
- return {topics:[... pkt], ... ex}}
1324
- return ex ? {...pkt, ...ex} : pkt}
1325
-
1326
-
1327
- async function _pub(self, pkt, pub_opt) {
1328
- if (undefined === pkt.payload) {
1329
- if ('function' === typeof pub_opt) {
1330
- pub_opt = {fn_encode: pub_opt};}
1331
-
1332
- let {msg} = pkt;
1333
- switch (typeof msg) {
1334
- case 'function':
1335
- pub_opt = {...pub_opt, fn_encode: msg};
1336
- // flow into 'undefined' case
1337
- case 'undefined':
1338
- // return a single-value closure to publish packets
1339
- return v => _pub(self, {...pkt, [pkt.arg || 'payload']: v}, pub_opt)
1340
-
1341
- default:
1342
- // Encode payload from msg; fn_encode allows alternative to JSON.stringify
1343
- let {fn_encode} = pub_opt || {};
1344
- pkt.payload = fn_encode
1345
- ? await fn_encode(msg)
1346
- : JSON.stringify(msg);} }
1347
-
1348
- if (pub_opt) {
1349
- if (pub_opt.props) {
1350
- pkt.props = pub_opt.props;}
1351
- if (pub_opt.xform) {
1352
- pkt = pub_opt.xform(pkt) || pkt;} }
1353
-
1354
- return self._send('publish', pkt,
1355
- pkt.qos ? pkt : void 0 ) }// key
1356
-
1357
- {
1358
- Object.assign(_pub,{
1359
- m: (self, topic, payload, pub_opt) =>
1360
- _pub(self, {topic, payload, qos:0}, pub_opt)
1361
- , mq: (self, topic, payload, pub_opt) =>
1362
- _pub(self, {topic, payload, qos:1}, pub_opt)
1363
- , mqr: (self, topic, payload, pub_opt) =>
1364
- _pub(self, {topic, payload, qos:1, retain: 1}, pub_opt)
1365
-
1366
- , o: (self, topic, msg, pub_opt) =>
1367
- _pub(self, {topic, msg, arg: 'msg', qos:0}, pub_opt)
1368
- , oq: (self, topic, msg, pub_opt) =>
1369
- _pub(self, {topic, msg, arg: 'msg', qos:1}, pub_opt)
1370
- , oqr: (self, topic, msg, pub_opt) =>
1371
- _pub(self, {topic, msg, arg: 'msg', qos:1, retain: 1}, pub_opt)} ); }
1372
-
1373
- class MQTTCoreClient extends MQTTBaseClient {
1374
- static _with_session(mqtt_session) {
1375
- this.prototype._mqtt_session = mqtt_session;}
1376
-
1377
- constructor(opt={}) {
1378
- super(opt);
1379
- this.with_live(opt.on_live);
1380
- this.with_reconnect(opt.on_reconnect);}
1381
-
1382
-
1383
- // on_live(client) ::
1384
- with_live(on_live) {
1385
- if (on_live) {
1386
- this.on_live = on_live;}
1387
-
1388
- return this}
1389
-
1390
- // on_reconnect(client) ::
1391
- with_reconnect(on_reconnect) {
1392
- if (on_reconnect) {
1393
- this.on_reconnect = on_reconnect;
1394
-
1395
- if (! this._conn_.is_set) {
1396
- on_reconnect(this);} }
1397
-
1398
- return this}
1399
-
1400
-
1401
- with_async_iter(async_iter, write_u8_pkt) {
1402
- let on_mqtt_chunk = this._conn_.set(
1403
- this._mqtt_session(),
1404
- write_u8_pkt);
1405
-
1406
- 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();})());
1412
-
1413
- return this}
1414
-
1415
-
1416
-
1417
-
1418
-
1419
-
1420
-
1421
-
1422
-
1423
-
1424
-
1425
-
1426
-
1427
-
1428
-
1429
-
1430
-
1431
-
1432
-
1433
-
1434
-
1435
-
1436
-
1437
-
1438
-
1439
-
1440
-
1441
-
1442
-
1443
-
1444
-
1445
-
1446
-
1447
-
1448
-
1449
-
1450
-
1451
- 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']);}
1457
-
1458
- websock.binaryType = 'arraybuffer';
1459
-
1460
- let ready, {readyState} = websock;
1461
- if (1 !== readyState) {
1462
- if (0 !== readyState) {
1463
- throw new Error('Invalid WebSocket readyState') }
1464
-
1465
- ready = new Promise( y =>
1466
- websock.addEventListener('open', y, {once: true}));}
1467
-
1468
-
1469
- let {_conn_} = this;
1470
- let on_mqtt_chunk = _conn_.set(
1471
- this._mqtt_session(),
1472
- async u8_pkt =>(
1473
- await ready
1474
- , websock.send(u8_pkt)) );
1475
-
1476
- websock.addEventListener('close',
1477
- (() => {
1478
- delete websock.onmessage;
1479
- _conn_.reset();})
1480
-
1481
- , {once: true});
1482
-
1483
- websock.onmessage = evt =>
1484
- on_mqtt_chunk(
1485
- new Uint8Array(evt.data));
1486
-
1487
- return this} }
1488
-
1489
- class MQTTClient_v4 extends MQTTCoreClient {
1490
- _mqtt_session() { return mqtt_session_ctx(4)() }
1491
- }
1492
-
1493
- const mqtt_v4 = opt => new MQTTClient_v4(opt);
1494
-
1495
- export { MQTTClient_v4 as MQTTClient, MQTTClient_v4, mqtt_v4 as default, mqtt_v4 as mqtt, mqtt_v4 };
1496
- //# sourceMappingURL=v4.mjs.map