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