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