u8-mqtt 0.5.2 → 0.6.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.
- package/README.md +23 -6
- package/cjs/basic-v4.cjs +293 -284
- package/cjs/basic-v4.cjs.map +1 -1
- package/cjs/basic-v5.cjs +307 -288
- package/cjs/basic-v5.cjs.map +1 -1
- package/cjs/full-v4.cjs +1538 -0
- package/cjs/full-v4.cjs.map +1 -0
- package/cjs/full-v5.cjs +1812 -0
- package/cjs/full-v5.cjs.map +1 -0
- package/cjs/index.cjs +320 -302
- package/cjs/index.cjs.map +1 -1
- package/cjs/v4.cjs +305 -296
- package/cjs/v4.cjs.map +1 -1
- package/cjs/v5.cjs +319 -300
- package/cjs/v5.cjs.map +1 -1
- package/code/_cmdid_dispatch.jsy +45 -69
- package/code/_conn.jsy +96 -72
- package/code/_dispatch.jsy +36 -28
- package/code/_utils.jsy +17 -0
- package/code/base.jsy +35 -63
- package/code/core.jsy +78 -56
- package/code/full-v4.js +20 -0
- package/code/full-v5.js +29 -0
- package/code/router_path.jsy +2 -1
- package/esm/basic-v4.js +293 -284
- package/esm/basic-v4.js.map +1 -1
- package/esm/basic-v5.js +307 -288
- package/esm/basic-v5.js.map +1 -1
- package/esm/deno/basic-v4.js +297 -288
- package/esm/deno/basic-v4.js.map +1 -1
- package/esm/deno/basic-v5.js +311 -292
- package/esm/deno/basic-v5.js.map +1 -1
- package/esm/deno/full-v4.js +1526 -0
- package/esm/deno/full-v4.js.map +1 -0
- package/esm/deno/full-v5.js +1798 -0
- package/esm/deno/full-v5.js.map +1 -0
- package/esm/deno/index.js +324 -305
- package/esm/deno/index.js.map +1 -1
- package/esm/deno/v4.js +309 -300
- package/esm/deno/v4.js.map +1 -1
- package/esm/deno/v5.js +323 -304
- package/esm/deno/v5.js.map +1 -1
- package/esm/full-v4.js +1526 -0
- package/esm/full-v4.js.map +1 -0
- package/esm/full-v5.js +1798 -0
- package/esm/full-v5.js.map +1 -0
- package/esm/index.js +320 -301
- package/esm/index.js.map +1 -1
- package/esm/node/basic-v4.js +293 -284
- package/esm/node/basic-v4.js.map +1 -1
- package/esm/node/basic-v4.mjs +293 -284
- package/esm/node/basic-v4.mjs.map +1 -1
- package/esm/node/basic-v5.js +307 -288
- package/esm/node/basic-v5.js.map +1 -1
- package/esm/node/basic-v5.mjs +307 -288
- package/esm/node/basic-v5.mjs.map +1 -1
- package/esm/node/full-v4.js +1529 -0
- package/esm/node/full-v4.js.map +1 -0
- package/esm/node/full-v4.mjs +1529 -0
- package/esm/node/full-v4.mjs.map +1 -0
- package/esm/node/full-v5.js +1801 -0
- package/esm/node/full-v5.js.map +1 -0
- package/esm/node/full-v5.mjs +1801 -0
- package/esm/node/full-v5.mjs.map +1 -0
- package/esm/node/index.js +320 -301
- package/esm/node/index.js.map +1 -1
- package/esm/node/index.mjs +320 -301
- package/esm/node/index.mjs.map +1 -1
- package/esm/node/v4.js +305 -296
- package/esm/node/v4.js.map +1 -1
- package/esm/node/v4.mjs +305 -296
- package/esm/node/v4.mjs.map +1 -1
- package/esm/node/v5.js +319 -300
- package/esm/node/v5.js.map +1 -1
- package/esm/node/v5.mjs +319 -300
- package/esm/node/v5.mjs.map +1 -1
- package/esm/v4.js +305 -296
- package/esm/v4.js.map +1 -1
- package/esm/v5.js +319 -300
- package/esm/v5.js.map +1 -1
- package/esm/web/basic-v4.js +293 -284
- package/esm/web/basic-v4.js.map +1 -1
- package/esm/web/basic-v4.min.js +1 -1
- package/esm/web/basic-v4.min.js.br +0 -0
- package/esm/web/basic-v4.min.js.gz +0 -0
- package/esm/web/basic-v5.js +307 -288
- package/esm/web/basic-v5.js.map +1 -1
- package/esm/web/basic-v5.min.js +1 -1
- package/esm/web/basic-v5.min.js.br +0 -0
- package/esm/web/basic-v5.min.js.gz +0 -0
- package/esm/web/full-v4.js +1526 -0
- package/esm/web/full-v4.js.map +1 -0
- package/esm/web/full-v4.min.js +1 -0
- package/esm/web/full-v4.min.js.br +0 -0
- package/esm/web/full-v4.min.js.gz +0 -0
- package/esm/web/full-v5.js +1798 -0
- package/esm/web/full-v5.js.map +1 -0
- package/esm/web/full-v5.min.js +1 -0
- package/esm/web/full-v5.min.js.br +0 -0
- package/esm/web/full-v5.min.js.gz +0 -0
- package/esm/web/index.js +320 -301
- package/esm/web/index.js.map +1 -1
- package/esm/web/index.min.js +1 -1
- package/esm/web/index.min.js.br +0 -0
- package/esm/web/index.min.js.gz +0 -0
- package/esm/web/v4.js +305 -296
- package/esm/web/v4.js.map +1 -1
- package/esm/web/v4.min.js +1 -1
- package/esm/web/v4.min.js.br +0 -0
- package/esm/web/v4.min.js.gz +0 -0
- package/esm/web/v5.js +319 -300
- package/esm/web/v5.js.map +1 -1
- package/esm/web/v5.min.js +1 -1
- package/esm/web/v5.min.js.br +0 -0
- package/esm/web/v5.min.js.gz +0 -0
- package/package.json +7 -8
package/esm/basic-v4.js
CHANGED
|
@@ -599,6 +599,9 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
|
|
|
599
599
|
return _encode_by_type[type]( mqtt_level, pkt ) },
|
|
600
600
|
|
|
601
601
|
decode_pkt(b0, u8_body) {
|
|
602
|
+
if (b0.map) // Uint8Array in first arg
|
|
603
|
+
return mqtt_raw_dispatch(this)(b0)[0]
|
|
604
|
+
|
|
602
605
|
let fn_decode = _decode_by_id[b0>>>4] || _decode_by_id[0];
|
|
603
606
|
return fn_decode?.({__proto__: this.pkt_ctx, b0}, u8_body) },
|
|
604
607
|
|
|
@@ -611,88 +614,15 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
|
|
|
611
614
|
}
|
|
612
615
|
}
|
|
613
616
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
return p =>(
|
|
617
|
-
p = new Promise(_pset)
|
|
618
|
-
, as_res(p, y, n)) }
|
|
619
|
-
|
|
620
|
-
const ao_defer_v = /* #__PURE__ */
|
|
621
|
-
ao_defer_ctx();
|
|
622
|
-
|
|
623
|
-
Promise.resolve({type:'init'});
|
|
624
|
-
|
|
625
|
-
function _mqtt_conn(client, [on_mqtt, pkt_future]) {
|
|
626
|
-
let _q_init = ao_defer_v(), _q_ready = ao_defer_v();
|
|
627
|
-
let _send_ready = async (...args) => (await _q_ready[0])(...args);
|
|
628
|
-
let _send_mqtt_pkt, _has_connected;
|
|
629
|
-
client._send = _send_ready;
|
|
630
|
-
|
|
631
|
-
return {
|
|
632
|
-
async when_ready() {await _q_ready[0];}
|
|
633
|
-
|
|
634
|
-
, ping: _ping_interval (() =>_send_mqtt_pkt?.('pingreq'))
|
|
635
|
-
|
|
636
|
-
, reset(err) {
|
|
637
|
-
if (! _send_mqtt_pkt) {return}
|
|
638
|
-
|
|
639
|
-
if (err) {
|
|
640
|
-
_q_init[2](err);}
|
|
641
|
-
|
|
642
|
-
_send_mqtt_pkt = null;
|
|
643
|
-
_q_init = ao_defer_v();
|
|
644
|
-
client._send = _send_ready;
|
|
645
|
-
|
|
646
|
-
// call client.on_conn_reset in next promise microtask
|
|
647
|
-
client.conn_emit('on_disconnect', false===err, err);}
|
|
648
|
-
|
|
649
|
-
, async send_connect(... args) {
|
|
650
|
-
if (! _send_mqtt_pkt) {
|
|
651
|
-
await _q_init[0]; }// _send_mqtt_pkt is set before fulfilled
|
|
617
|
+
const _isfn = v => typeof v === 'function';
|
|
618
|
+
const _isstr = v => typeof v === 'string';
|
|
652
619
|
|
|
653
|
-
|
|
654
|
-
let res = await _send_mqtt_pkt(...args);
|
|
655
|
-
if (0 == res[0].reason) {
|
|
656
|
-
_has_connected = true;
|
|
657
|
-
// resolve _q_ready[0] with _send_mqtt_pkt closure
|
|
658
|
-
_q_ready[1](client._send = _send_mqtt_pkt);
|
|
659
|
-
_q_ready = ao_defer_v();
|
|
660
|
-
client.conn_emit('on_ready');}
|
|
661
|
-
|
|
662
|
-
return res}
|
|
663
|
-
|
|
664
|
-
, is_set: (() =>!! _send_mqtt_pkt)
|
|
665
|
-
, set(mqtt_ctx, send_u8_pkt) {
|
|
666
|
-
if (_send_mqtt_pkt) {
|
|
667
|
-
throw new Error('Already connected')}
|
|
668
|
-
|
|
669
|
-
mqtt_ctx = mqtt_ctx.mqtt_stream();
|
|
670
|
-
let sess_ctx = {mqtt: client};
|
|
671
|
-
let on_mqtt_chunk = u8_buf =>
|
|
672
|
-
on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx);
|
|
673
|
-
|
|
674
|
-
_send_mqtt_pkt = async (type, pkt, key) => {
|
|
675
|
-
let res = undefined !== key
|
|
676
|
-
? pkt_future(key) : true;
|
|
677
|
-
|
|
678
|
-
await send_u8_pkt(
|
|
679
|
-
mqtt_ctx.encode_pkt(type, pkt));
|
|
680
|
-
|
|
681
|
-
return res};
|
|
682
|
-
|
|
683
|
-
_q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
|
|
684
|
-
|
|
685
|
-
// call client.on_live in next promise microtask
|
|
686
|
-
client.conn_emit('on_live', _has_connected);
|
|
687
|
-
return on_mqtt_chunk} } }
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
function _ping_interval(send_ping) {
|
|
620
|
+
function _interval(fn_callback) {
|
|
691
621
|
let tid;
|
|
692
622
|
return (( td ) => {
|
|
693
623
|
tid = clearInterval(tid);
|
|
694
624
|
if (td) {
|
|
695
|
-
tid = setInterval(
|
|
625
|
+
tid = setInterval(fn_callback, 1000 * td);
|
|
696
626
|
|
|
697
627
|
|
|
698
628
|
|
|
@@ -701,172 +631,129 @@ function _ping_interval(send_ping) {
|
|
|
701
631
|
tid.unref?.();
|
|
702
632
|
return true} }) }
|
|
703
633
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
634
|
+
async function _mqtt_cmd_evt(target, answer, pkt, ctx) {
|
|
635
|
+
/* target : on_mqtt_type = {
|
|
636
|
+
mqtt_pkt(pkt, ctx) {}, // generic
|
|
637
|
+
|
|
638
|
+
mqtt_auth(pkt, ctx) {},
|
|
639
|
+
mqtt_connect(pkt, ctx) {},
|
|
640
|
+
mqtt_connack(pkt, ctx) {},
|
|
641
|
+
mqtt_disconnect(pkt, ctx) {},
|
|
642
|
+
|
|
643
|
+
mqtt_publish(pkt, ctx) {},
|
|
644
|
+
mqtt_subscribe(pkt, ctx) {},
|
|
645
|
+
mqtt_unsubscribe(pkt, ctx) {},
|
|
646
|
+
|
|
647
|
+
mqtt_pingreq(pkt, ctx) {},
|
|
648
|
+
mqtt_pingresp(pkt, ctx) {},
|
|
649
|
+
} */
|
|
650
|
+
|
|
651
|
+
let pkt_fn = target[`mqtt_${pkt.type}`] || target.mqtt_pkt;
|
|
652
|
+
await pkt_fn?.call(target, pkt, ctx);}
|
|
653
|
+
|
|
654
|
+
function _mqtt_cmd_type(target, answer, pkt, ctx) {
|
|
655
|
+
answer(pkt.type, pkt);
|
|
656
|
+
_mqtt_cmd_evt(target, answer, pkt, ctx);}
|
|
657
|
+
|
|
658
|
+
function _mqtt_cmd_id(target, answer, pkt) {
|
|
659
|
+
answer(pkt.pkt_id, pkt);}
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
const _mqtt_cmdids =[
|
|
663
|
+
_ => {} // 0x0 reserved
|
|
664
|
+
, _mqtt_cmd_evt // 0x1 connect
|
|
665
|
+
, _mqtt_cmd_type // 0x2 connack
|
|
666
|
+
, _mqtt_cmd_evt // 0x3 publish
|
|
667
|
+
, _mqtt_cmd_id // 0x4 puback
|
|
668
|
+
, _mqtt_cmd_id // 0x5 pubrec
|
|
669
|
+
, _mqtt_cmd_id // 0x6 pubrel
|
|
670
|
+
, _mqtt_cmd_id // 0x7 pubcomp
|
|
671
|
+
, _mqtt_cmd_evt // 0x8 subscribe
|
|
672
|
+
, _mqtt_cmd_id // 0x9 suback
|
|
673
|
+
, _mqtt_cmd_evt // 0xa unsubscribe
|
|
674
|
+
, _mqtt_cmd_id // 0xb unsuback
|
|
675
|
+
, _mqtt_cmd_type // 0xc pingreq
|
|
676
|
+
, _mqtt_cmd_type // 0xd pingresp
|
|
677
|
+
, _mqtt_cmd_evt // 0xe disconnect
|
|
678
|
+
, _mqtt_cmd_type ];// 0xf auth
|
|
707
679
|
|
|
708
|
-
,
|
|
709
|
-
|
|
680
|
+
function _mqtt_dispatch(opt, target) {
|
|
681
|
+
let hashbelt=[], rotate_ts=0;
|
|
682
|
+
// default rotate at 1s across 5 buckets
|
|
683
|
+
let { td: rotate_td=1000, n: rotate_n=5 } = opt?.rotate || {};
|
|
710
684
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
685
|
+
// Promise / future scaffolding
|
|
686
|
+
let _pkt_id=100, _ftr_key; // use _ftr_key to reuse _by_key closure
|
|
687
|
+
let _ftr_by_key = fn_answer => hashbelt[0].set(_ftr_key, fn_answer);
|
|
714
688
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
_tmp_ = pkt_or_key;}
|
|
718
|
-
else {
|
|
719
|
-
_pkt_id = (_pkt_id + 1) & 0xffff;
|
|
720
|
-
_tmp_ = pkt_or_key.pkt_id = _pkt_id;}
|
|
689
|
+
on_mqtt([]); // init hashbelt and rotate_ts
|
|
690
|
+
return [on_mqtt, pkt_future]
|
|
721
691
|
|
|
722
|
-
return new Promise(_by_key)}) }
|
|
723
692
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
693
|
+
function pkt_future(pkt_or_key) {
|
|
694
|
+
if (! _isstr(pkt_or_key)) {
|
|
695
|
+
_pkt_id = (_pkt_id + 1) & 0xffff; // 16-bit unsigned short
|
|
696
|
+
_ftr_key = pkt_or_key.pkt_id = _pkt_id;}
|
|
697
|
+
else _ftr_key = pkt_or_key;
|
|
698
|
+
|
|
699
|
+
return new Promise(_ftr_by_key)}
|
|
700
|
+
|
|
701
|
+
function answer(key, pkt) {
|
|
702
|
+
for (let map of hashbelt) {
|
|
703
|
+
let fn_answer = map.get(key);
|
|
704
|
+
if (fn_answer) {
|
|
728
705
|
map.delete(key);
|
|
729
706
|
|
|
730
|
-
|
|
707
|
+
fn_answer([pkt, /*err*/]); // option/maybe monad
|
|
731
708
|
return true} }
|
|
732
709
|
return false}
|
|
733
710
|
|
|
734
|
-
, rotate_belt(n) {
|
|
735
|
-
let {hashbelt} = this;
|
|
736
|
-
hashbelt.unshift(new Map());
|
|
737
|
-
for (let old of hashbelt.splice(n || 5)) {
|
|
738
|
-
for (let answer_monad of old.values()) {
|
|
739
|
-
answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
|
|
740
|
-
|
|
741
|
-
, cmdids: ((() => {
|
|
742
|
-
return [
|
|
743
|
-
(() =>{} )// 0x0 reserved
|
|
744
|
-
, by_evt // 0x1 connect
|
|
745
|
-
, by_type // 0x2 connack
|
|
746
|
-
, by_evt // 0x3 publish
|
|
747
|
-
, by_id // 0x4 puback
|
|
748
|
-
, by_id // 0x5 pubrec
|
|
749
|
-
, by_id // 0x6 pubrel
|
|
750
|
-
, by_id // 0x7 pubcomp
|
|
751
|
-
, by_evt // 0x8 subscribe
|
|
752
|
-
, by_id // 0x9 suback
|
|
753
|
-
, by_evt // 0xa unsubscribe
|
|
754
|
-
, by_id // 0xb unsuback
|
|
755
|
-
, by_type // 0xc pingreq
|
|
756
|
-
, by_type // 0xd pingresp
|
|
757
|
-
, by_evt // 0xe disconnect
|
|
758
|
-
, by_type ]// 0xf auth
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
function by_id(disp, pkt) {
|
|
762
|
-
disp.answer(pkt.pkt_id, pkt); }
|
|
763
|
-
|
|
764
|
-
function by_type(disp, pkt, ctx) {
|
|
765
|
-
disp.answer(pkt.type, pkt);
|
|
766
|
-
by_evt(disp, pkt, ctx);}
|
|
767
|
-
|
|
768
|
-
async function by_evt({target}, pkt, ctx) {
|
|
769
|
-
let fn = target[`mqtt_${pkt.type}`]
|
|
770
|
-
|| target.mqtt_pkt;
|
|
771
|
-
|
|
772
|
-
await fn?.call(target, pkt, ctx);} })()) };
|
|
773
|
-
|
|
774
|
-
/*
|
|
775
|
-
on_mqtt_type = {
|
|
776
|
-
mqtt_auth(pkt, ctx) ::
|
|
777
|
-
mqtt_connect(pkt, ctx) ::
|
|
778
|
-
mqtt_connack(pkt, ctx) ::
|
|
779
|
-
mqtt_disconnect(pkt, ctx) ::
|
|
780
|
-
|
|
781
|
-
mqtt_publish(pkt, ctx)
|
|
782
|
-
mqtt_subscribe(pkt, ctx) ::
|
|
783
|
-
mqtt_unsubscribe(pkt, ctx) ::
|
|
784
|
-
|
|
785
|
-
mqtt_pingreq(pkt, ctx) ::
|
|
786
|
-
mqtt_pingresp(pkt, ctx) ::
|
|
787
|
-
}
|
|
788
|
-
*/
|
|
789
|
-
|
|
790
|
-
function _mqtt_dispatch(opt, target) {
|
|
791
|
-
let _disp_ = _mqtt_cmdid_dispatch.create(target);
|
|
792
|
-
let { cmdids } = _disp_;
|
|
793
|
-
|
|
794
|
-
// default rotate at 1s across 5 buckets
|
|
795
|
-
let { td: rotate_td=1000, n: rotate_n=5 } =
|
|
796
|
-
opt && opt.rotate || {};
|
|
797
|
-
|
|
798
|
-
let rotate_ts = rotate_td + Date.now();
|
|
799
|
-
|
|
800
|
-
return [on_mqtt,
|
|
801
|
-
_disp_.bind_pkt_future()]
|
|
802
|
-
|
|
803
711
|
function on_mqtt(pkt_list, ctx) {
|
|
804
712
|
for (let pkt of pkt_list) {
|
|
805
|
-
|
|
713
|
+
_mqtt_cmdids[pkt.id](target, answer, pkt, ctx);}
|
|
806
714
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
715
|
+
// rotate after rotate_ts
|
|
716
|
+
let now = Date.now();
|
|
717
|
+
if (now > rotate_ts) {
|
|
718
|
+
rotate_ts = rotate_td + now;
|
|
719
|
+
hashbelt.unshift(new Map());
|
|
720
|
+
while (hashbelt.length > rotate_n) {
|
|
721
|
+
for (let fn_answer of hashbelt.pop().values()) {
|
|
722
|
+
fn_answer([/*pkt*/, 'expired']); } } } } }// option/maybe monad
|
|
810
723
|
|
|
811
724
|
class MQTTError extends Error {
|
|
812
725
|
constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
|
|
726
|
+
// use hex-encoded reasons to match MQTT spec documentation
|
|
813
727
|
super(`[0x${reason.toString(16)}] ${reason.reason}`);
|
|
814
728
|
this.mqtt_pkt = mqtt_pkt;
|
|
815
729
|
this.reason = reason;} }
|
|
816
730
|
|
|
817
731
|
class MQTTBase {
|
|
818
|
-
constructor(opt={}) {
|
|
819
|
-
this.with(opt);
|
|
820
|
-
this._conn_ = _mqtt_conn(this,
|
|
821
|
-
this._init_dispatch(opt, this)); }
|
|
822
|
-
|
|
823
|
-
with(fns_ns) {
|
|
824
|
-
for (let [k,v] of Object.entries(fns_ns)) {
|
|
825
|
-
if ('function' === typeof v) {this[k] = v;} }
|
|
826
|
-
return this}
|
|
827
|
-
|
|
828
|
-
async conn_emit(evt, arg, err_arg) {
|
|
829
|
-
this.log_conn?.(evt, arg, err_arg);
|
|
830
|
-
try {
|
|
831
|
-
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
832
|
-
if (fn_evt) {
|
|
833
|
-
await fn_evt.call(this, this, arg, err_arg);}
|
|
834
|
-
else if (err_arg) {throw err_arg} }
|
|
835
|
-
catch (err) {
|
|
836
|
-
this.on_error(err, evt);} }
|
|
837
|
-
|
|
838
|
-
on_error(err, evt) {
|
|
839
|
-
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
840
|
-
|
|
841
732
|
// Handshaking Packets
|
|
842
|
-
|
|
843
733
|
async connect(pkt={}) {
|
|
844
|
-
let cid = pkt.client_id
|
|
845
|
-
if (
|
|
734
|
+
let cid = pkt.client_id;
|
|
735
|
+
if (! _isstr(cid)) {
|
|
846
736
|
// see init_client_id implementation in core.jsy
|
|
847
|
-
pkt.client_id = cid = this.init_client_id(cid);}
|
|
737
|
+
pkt.client_id = cid = this.client_id || this.init_client_id(cid);}
|
|
848
738
|
this.client_id = cid;
|
|
849
739
|
|
|
850
740
|
if (null == pkt.keep_alive) {
|
|
851
741
|
pkt.keep_alive = 60;}
|
|
852
742
|
|
|
853
|
-
let
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
throw new this.MQTTError(res[0])}
|
|
858
|
-
|
|
859
|
-
// TODO: merge with server's keep_alive frequency
|
|
860
|
-
this._conn_.ping(pkt.keep_alive);
|
|
861
|
-
return res}
|
|
743
|
+
let response = await this._send0('connect', pkt, 'connack');
|
|
744
|
+
if (0 != response[0].reason) {// compare to 0 to coerce to number
|
|
745
|
+
throw new this.MQTTError(response[0])}
|
|
746
|
+
return this.conn.on_conn(pkt, response)}
|
|
862
747
|
|
|
863
748
|
async disconnect(pkt={}) {
|
|
864
|
-
let
|
|
865
|
-
this.
|
|
866
|
-
return res}
|
|
749
|
+
let response = await this._send0('disconnect', pkt);
|
|
750
|
+
return this.conn.on_dis(pkt, response)}
|
|
867
751
|
|
|
868
|
-
auth(pkt={}) {
|
|
869
|
-
|
|
752
|
+
async auth(pkt={}) {
|
|
753
|
+
let response = await this._send0('auth', pkt, 'auth');
|
|
754
|
+
if (response[0].reason) {
|
|
755
|
+
throw new this.MQTTError(response[0])}
|
|
756
|
+
return this.conn.on_auth(pkt, response)}
|
|
870
757
|
|
|
871
758
|
ping() {return this._send('pingreq', null, 'pingresp')}
|
|
872
759
|
puback({pkt_id}) {return this._send('puback', {pkt_id})}
|
|
@@ -903,20 +790,18 @@ class MQTTBase {
|
|
|
903
790
|
// alias: publish -- because 'pub' is shorter for semantic aliases above
|
|
904
791
|
async pub(pkt, pub_opt) {
|
|
905
792
|
if (undefined === pkt.payload) {
|
|
906
|
-
if (
|
|
793
|
+
if (_isfn(pub_opt)) {
|
|
794
|
+
// pub_opt as a function is fn_encode value
|
|
907
795
|
pub_opt = {fn_encode: pub_opt};}
|
|
908
796
|
|
|
909
|
-
let
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
// return a single-value closure to publish packets
|
|
916
|
-
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
797
|
+
let msg = pkt.msg, fn_encode = pub_opt?.fn_encode;
|
|
798
|
+
if (null == msg || _isfn(msg)) {
|
|
799
|
+
// when msg is a function, return closure using fn_encode
|
|
800
|
+
if (msg) {pub_opt = {...pub_opt, fn_encode: msg};}
|
|
801
|
+
// return a single-value closure to publish packets
|
|
802
|
+
return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)}
|
|
917
803
|
|
|
918
804
|
// Encode payload from msg; fn_encode allows alternative to JSON.stringify
|
|
919
|
-
let {fn_encode} = pub_opt || {};
|
|
920
805
|
pkt.payload = fn_encode
|
|
921
806
|
? await fn_encode(msg)
|
|
922
807
|
: JSON.stringify(msg);}
|
|
@@ -928,31 +813,31 @@ class MQTTBase {
|
|
|
928
813
|
pkt = pub_opt.xform(pkt) || pkt;} }
|
|
929
814
|
|
|
930
815
|
return this._send('publish', pkt,
|
|
931
|
-
pkt.qos ? pkt :
|
|
816
|
+
pkt.qos ? pkt : null ) }// key
|
|
932
817
|
|
|
933
818
|
|
|
934
819
|
// Internal API
|
|
935
820
|
|
|
936
|
-
/* async
|
|
821
|
+
/* async _send0(type, pkt) -- provided by conn and transport */
|
|
822
|
+
/* async _send(type, pkt) -- provided by conn and transport */
|
|
937
823
|
|
|
938
824
|
_init_dispatch(opt) {
|
|
939
825
|
this.constructor?._once_();
|
|
940
826
|
let target ={__proto__: opt.on_mqtt_type};
|
|
941
827
|
target.mqtt_publish ||=
|
|
942
828
|
this._init_router?.(opt, this, target);
|
|
943
|
-
return _mqtt_dispatch(
|
|
829
|
+
return _mqtt_dispatch(opt, target)}
|
|
944
830
|
|
|
945
831
|
static _aliases() {
|
|
946
832
|
return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'}
|
|
947
833
|
|
|
948
|
-
static _once_(
|
|
949
|
-
|
|
950
|
-
|
|
834
|
+
static _once_(klass=this) {
|
|
835
|
+
klass._once_ = _=>0;
|
|
836
|
+
var alias, name, p = klass.prototype;
|
|
951
837
|
p.MQTTError = MQTTError;
|
|
952
|
-
for (
|
|
953
|
-
alias = alias.split(':');
|
|
954
|
-
|
|
955
|
-
if (fn) {p[alias[0]] = fn;} } } }
|
|
838
|
+
for (alias of klass._aliases().split(/\s+/)) {
|
|
839
|
+
[alias, name] = alias.split(':');
|
|
840
|
+
p[alias] = p[name];} } }
|
|
956
841
|
|
|
957
842
|
|
|
958
843
|
function _as_topics(pkt, ex, topic_prefix) {
|
|
@@ -977,43 +862,177 @@ function _as_topics(pkt, ex, topic_prefix) {
|
|
|
977
862
|
pkt.topics = pkt.topics.map(_prefix_topics);}
|
|
978
863
|
return pkt}
|
|
979
864
|
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
865
|
+
const _defer_obj = o =>(
|
|
866
|
+
o.p = new Promise((a,e) => { o.a=a; o.e=e; })
|
|
867
|
+
, o);
|
|
868
|
+
|
|
869
|
+
function _dfn_reset(client, attr, fn_after) {
|
|
870
|
+
// a resetable deferred for a function
|
|
871
|
+
let self = {set}, afn = async (...args) => (await self.p)(...args);
|
|
872
|
+
return set()
|
|
873
|
+
|
|
874
|
+
function set() {
|
|
875
|
+
if (afn !== client[attr]) {
|
|
876
|
+
_defer_obj(self).p.then(fn_after, _=>0);
|
|
877
|
+
client[attr] = afn;}
|
|
878
|
+
return self} }
|
|
879
|
+
|
|
880
|
+
function _mqtt_conn(opt, client, [on_mqtt, pkt_future]) {
|
|
881
|
+
let _abort;
|
|
882
|
+
let _dfn_send0 = _dfn_reset(client, '_send0', // client._send0 getter/setter
|
|
883
|
+
_=> client.conn_emit('on_live', conn.has_connected));
|
|
884
|
+
let _dfn_ready = _dfn_reset(client, '_send', // client._send getter/setter
|
|
885
|
+
_=> client.conn_emit('on_ready'));
|
|
886
|
+
let _keep_alive_ival = _interval (() =>client._send0('pingreq') );// resettable interval for keep_alive ping
|
|
887
|
+
|
|
888
|
+
let conn = Object.create({
|
|
889
|
+
ping: (td=conn.keep_alive) => _keep_alive_ival(td)
|
|
890
|
+
|
|
891
|
+
, on_conn(pkt, response) {
|
|
892
|
+
conn.has_connected = true;
|
|
893
|
+
conn.keep_alive = opt.keep_alive || response[0].props?.server_keep_alive || pkt.keep_alive;
|
|
894
|
+
client.conn_emit('on_conn');
|
|
895
|
+
return opt.use_auth
|
|
896
|
+
? response // wait on enhanced authentication step
|
|
897
|
+
: conn.on_auth(null, response) }// otherwise, connect is also auth
|
|
898
|
+
|
|
899
|
+
, on_auth(pkt, response) {
|
|
900
|
+
_dfn_ready.a(_dfn_send0.p);
|
|
901
|
+
if (0 != opt.keep_alive) {
|
|
902
|
+
conn.ping();}
|
|
903
|
+
client.conn_emit('on_auth', !pkt);
|
|
904
|
+
return response}
|
|
905
|
+
|
|
906
|
+
, on_dis(pkt, response) {
|
|
907
|
+
conn.reset(false);
|
|
908
|
+
return response}
|
|
909
|
+
|
|
910
|
+
, reset(err) {
|
|
911
|
+
if (err) {
|
|
912
|
+
_dfn_send0.e(err); }// send error to uses of _send0 (connect, auth)
|
|
913
|
+
_abort.e(err); // abort in-progress connections
|
|
914
|
+
|
|
915
|
+
delete conn.is_set;
|
|
916
|
+
conn.ready = handshake();
|
|
917
|
+
client.conn_emit('on_disconnect', false===err, err);}
|
|
918
|
+
|
|
919
|
+
, abort() {
|
|
920
|
+
_dfn_ready.e(err); // abort all messages awaiting ready state
|
|
921
|
+
return conn.reset(err)}
|
|
922
|
+
|
|
923
|
+
, async setup(gate, send_u8_pkt, init_msg_loop) {
|
|
924
|
+
if (conn.is_set) {
|
|
925
|
+
throw new Error() }// already in-progress
|
|
926
|
+
|
|
927
|
+
conn.is_set = true;
|
|
928
|
+
await gate;
|
|
929
|
+
|
|
930
|
+
// setup send/recv MQTT parsing context
|
|
931
|
+
let mqtt_ctx = client.mqtt_ctx.mqtt_stream();
|
|
932
|
+
|
|
933
|
+
{// setup inbound message loop
|
|
934
|
+
let sess_ctx = {mqtt: client}; // mutable session context
|
|
935
|
+
let on_mqtt_chunk = u8 => on_mqtt(mqtt_ctx.decode(u8), sess_ctx);
|
|
936
|
+
init_msg_loop(on_mqtt_chunk, conn);}
|
|
937
|
+
|
|
938
|
+
// setup outbound message path and transport connection
|
|
939
|
+
send_u8_pkt = await send_u8_pkt;
|
|
940
|
+
_dfn_send0.a(
|
|
941
|
+
async (type, pkt, key) => {
|
|
942
|
+
let res = undefined !== key
|
|
943
|
+
? pkt_future(key) : true;
|
|
944
|
+
|
|
945
|
+
await send_u8_pkt(
|
|
946
|
+
mqtt_ctx.encode_pkt(type, pkt));
|
|
947
|
+
return res} ); } });
|
|
948
|
+
|
|
949
|
+
conn.ready = handshake();
|
|
950
|
+
return conn
|
|
951
|
+
|
|
952
|
+
async function handshake() {
|
|
953
|
+
_abort = _defer_obj({});
|
|
954
|
+
|
|
955
|
+
_keep_alive_ival(0); // clearInterval on keep alive ping
|
|
956
|
+
_dfn_send0.set(); // reset client._send0 if necessary
|
|
957
|
+
_dfn_ready.set(); // reset client._send if necessary
|
|
958
|
+
|
|
959
|
+
try {
|
|
960
|
+
// set client._send0 as passtrhough after transport connection
|
|
961
|
+
client._send0 = await Promise.race([_dfn_send0.p, _abort.p]);
|
|
962
|
+
|
|
963
|
+
// set client._send as passtrhough after ready
|
|
964
|
+
client._send = await Promise.race([_dfn_ready.p, _abort.p]);
|
|
965
|
+
return true}
|
|
966
|
+
catch (err) {
|
|
967
|
+
return false} } }
|
|
968
|
+
|
|
969
|
+
const pkt_api ={
|
|
970
|
+
utf8(u8) {return new TextDecoder('utf-8').decode(u8 || this.payload )}
|
|
971
|
+
, json(u8) {return JSON.parse( this.utf8(u8) || null )}
|
|
972
|
+
, text(u8) {return this.utf8(u8)} };
|
|
973
|
+
|
|
974
|
+
const opt_default ={
|
|
975
|
+
sess_stg: globalThis.sessionStorage};
|
|
985
976
|
|
|
986
977
|
class MQTTCore extends MQTTBase {
|
|
978
|
+
constructor(opt) {
|
|
979
|
+
super();
|
|
980
|
+
this.with(opt);
|
|
981
|
+
opt ={...opt_default, ...opt};
|
|
982
|
+
// settings for MQTTCore
|
|
983
|
+
this.sess_stg = opt.sess_stg;
|
|
984
|
+
// setup connection and dispatch
|
|
985
|
+
this.conn = _mqtt_conn(opt, this,
|
|
986
|
+
this._init_dispatch(opt)); }
|
|
987
|
+
|
|
988
|
+
with(fns_ns) {
|
|
989
|
+
for (let [k,v] of Object.entries(fns_ns)) {
|
|
990
|
+
if (_isfn(v)) {this[k] = v;} }
|
|
991
|
+
return this}
|
|
992
|
+
|
|
993
|
+
|
|
987
994
|
static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
|
|
988
|
-
let
|
|
989
|
-
|
|
995
|
+
let klass = class extends this {};
|
|
996
|
+
klass.prototype.mqtt_ctx =
|
|
990
997
|
mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
|
|
991
|
-
return
|
|
998
|
+
return klass}
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
async conn_emit(evt, arg, err_arg) {
|
|
1002
|
+
this.log_conn?.(evt, arg, err_arg);
|
|
1003
|
+
try {
|
|
1004
|
+
let fn_evt = this[await evt]; // microtask break using `await evt`
|
|
1005
|
+
if (fn_evt) {
|
|
1006
|
+
await fn_evt.call(this, this, arg, err_arg);}
|
|
1007
|
+
else if (err_arg) {throw err_arg} }
|
|
1008
|
+
catch (err) {
|
|
1009
|
+
this.on_error(err, evt);} }
|
|
1010
|
+
|
|
1011
|
+
on_error(err, evt) {
|
|
1012
|
+
console.warn('[[u8-mqtt error: %s]]', evt, err); }
|
|
1013
|
+
log_conn(evt, arg, err_arg) {
|
|
1014
|
+
console.info('[[u8-mqtt conn: %s]]', evt, arg, err_arg); }
|
|
992
1015
|
|
|
993
1016
|
|
|
994
1017
|
// automatic Client Id for connect()
|
|
995
1018
|
init_client_id(parts=['u8-mqtt--','']) {
|
|
996
|
-
let sess_stg=this.sess_stg;
|
|
1019
|
+
let sess_stg = this.sess_stg;
|
|
997
1020
|
let key, cid = sess_stg?.getItem(key=parts.join(' '));
|
|
998
1021
|
if (! cid) {
|
|
999
1022
|
cid = parts.join(Math.random().toString(36).slice(2));
|
|
1000
1023
|
sess_stg?.setItem(key, cid);}
|
|
1001
1024
|
return cid}
|
|
1002
1025
|
|
|
1003
|
-
get sess_stg() {return globalThis.sessionStorage}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
//on_error(err, evt) ::
|
|
1007
|
-
// console.warn @ '[[u8-mqtt error: %s]]', evt, err
|
|
1008
|
-
|
|
1009
|
-
//log_conn(evt, arg, err_arg) ::
|
|
1010
|
-
// console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
|
|
1011
1026
|
|
|
1012
1027
|
on_live(client, is_reconnect) {
|
|
1013
1028
|
if (is_reconnect) {
|
|
1014
1029
|
return client.connect()} }
|
|
1015
1030
|
|
|
1016
|
-
//
|
|
1031
|
+
// on_ready(client) ::
|
|
1032
|
+
// on_reconnect(client) ::
|
|
1033
|
+
on_disconnect(client, intentional) {
|
|
1034
|
+
if (! intentional) {
|
|
1035
|
+
return client.on_reconnect?.()} }
|
|
1017
1036
|
|
|
1018
1037
|
_use_conn(fn_reconnect) {
|
|
1019
1038
|
return (this.reconnect = fn_reconnect)?.()}
|
|
@@ -1025,27 +1044,20 @@ class MQTTCore extends MQTTBase {
|
|
|
1025
1044
|
.then(this.reconnect)
|
|
1026
1045
|
.then(opt.reconnect, opt.error);} }) }
|
|
1027
1046
|
|
|
1028
|
-
on_disconnect(client, intentional) {
|
|
1029
|
-
if (! intentional) {
|
|
1030
|
-
return client.on_reconnect?.()} }
|
|
1031
|
-
|
|
1032
1047
|
delay(ms) {
|
|
1033
1048
|
return new Promise(done => setTimeout(done, ms)) }
|
|
1034
1049
|
|
|
1035
1050
|
with_async_iter(async_iter, write_u8_pkt) {
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
catch (err) {
|
|
1047
|
-
this._conn_.reset(err);} })());
|
|
1048
|
-
|
|
1051
|
+
this.conn.setup(async_iter,
|
|
1052
|
+
write_u8_pkt,
|
|
1053
|
+
async (on_mqtt_chunk, conn) => {
|
|
1054
|
+
try {
|
|
1055
|
+
async_iter = await async_iter;
|
|
1056
|
+
for await (let chunk of async_iter)
|
|
1057
|
+
on_mqtt_chunk(chunk);
|
|
1058
|
+
conn.reset();}
|
|
1059
|
+
catch (err) {
|
|
1060
|
+
conn.reset(err);} } );
|
|
1049
1061
|
return this}
|
|
1050
1062
|
|
|
1051
1063
|
|
|
@@ -1116,33 +1128,30 @@ class MQTTCore extends MQTTBase {
|
|
|
1116
1128
|
|
|
1117
1129
|
websock.binaryType = 'arraybuffer';
|
|
1118
1130
|
|
|
1119
|
-
let
|
|
1131
|
+
let ws_ready, readyState = websock.readyState;
|
|
1120
1132
|
if (1 !== readyState) {
|
|
1121
1133
|
if (0 !== readyState) {
|
|
1122
|
-
throw new Error('
|
|
1123
|
-
|
|
1124
|
-
ready = new Promise(fn => websock.onopen = fn); }
|
|
1134
|
+
throw new Error('WS readyState') }
|
|
1125
1135
|
|
|
1136
|
+
ws_ready = new Promise(ready => websock.onopen = ready); }
|
|
1126
1137
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
, websock.send(u8_pkt)) );
|
|
1138
|
+
this.conn.setup(ws_ready,
|
|
1139
|
+
u8_pkt => websock.send(u8_pkt),
|
|
1140
|
+
(on_mqtt_chunk, conn) => {
|
|
1141
|
+
websock.onmessage = evt =>(
|
|
1142
|
+
on_mqtt_chunk(new Uint8Array(evt.data)) );
|
|
1133
1143
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
err.reason = evt.reason;}
|
|
1144
|
+
websock.onclose = evt => {
|
|
1145
|
+
if (! evt.wasClean) {
|
|
1146
|
+
var err = new Error('websocket close');
|
|
1147
|
+
err.code = evt.code;
|
|
1148
|
+
err.reason = evt.reason;}
|
|
1140
1149
|
|
|
1141
|
-
|
|
1150
|
+
conn.reset(err);}; } );
|
|
1142
1151
|
|
|
1143
1152
|
return this} }
|
|
1144
1153
|
|
|
1145
|
-
const version = '0.
|
|
1154
|
+
const version = '0.6.0';
|
|
1146
1155
|
|
|
1147
1156
|
const MQTTClient_v4 = /* #__PURE__ */
|
|
1148
1157
|
MQTTCore.mqtt_ctx(4, mqtt_opts_v4);
|