u8-mqtt 0.5.3 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +1 -1
  2. package/cjs/basic-v4.cjs +283 -277
  3. package/cjs/basic-v4.cjs.map +1 -1
  4. package/cjs/basic-v5.cjs +297 -281
  5. package/cjs/basic-v5.cjs.map +1 -1
  6. package/cjs/full-v4.cjs +295 -289
  7. package/cjs/full-v4.cjs.map +1 -1
  8. package/cjs/full-v5.cjs +309 -293
  9. package/cjs/full-v5.cjs.map +1 -1
  10. package/cjs/index.cjs +310 -295
  11. package/cjs/index.cjs.map +1 -1
  12. package/cjs/v4.cjs +295 -289
  13. package/cjs/v4.cjs.map +1 -1
  14. package/cjs/v5.cjs +309 -293
  15. package/cjs/v5.cjs.map +1 -1
  16. package/code/_cmdid_dispatch.jsy +45 -69
  17. package/code/_conn.jsy +96 -72
  18. package/code/_dispatch.jsy +36 -28
  19. package/code/_utils.jsy +17 -0
  20. package/code/base.jsy +33 -61
  21. package/code/core.jsy +73 -51
  22. package/code/router_path.jsy +2 -1
  23. package/esm/basic-v4.js +283 -277
  24. package/esm/basic-v4.js.map +1 -1
  25. package/esm/basic-v5.js +297 -281
  26. package/esm/basic-v5.js.map +1 -1
  27. package/esm/deno/basic-v4.js +287 -281
  28. package/esm/deno/basic-v4.js.map +1 -1
  29. package/esm/deno/basic-v5.js +301 -285
  30. package/esm/deno/basic-v5.js.map +1 -1
  31. package/esm/deno/full-v4.js +299 -293
  32. package/esm/deno/full-v4.js.map +1 -1
  33. package/esm/deno/full-v5.js +313 -297
  34. package/esm/deno/full-v5.js.map +1 -1
  35. package/esm/deno/index.js +314 -298
  36. package/esm/deno/index.js.map +1 -1
  37. package/esm/deno/v4.js +299 -293
  38. package/esm/deno/v4.js.map +1 -1
  39. package/esm/deno/v5.js +313 -297
  40. package/esm/deno/v5.js.map +1 -1
  41. package/esm/full-v4.js +295 -289
  42. package/esm/full-v4.js.map +1 -1
  43. package/esm/full-v5.js +309 -293
  44. package/esm/full-v5.js.map +1 -1
  45. package/esm/index.js +310 -294
  46. package/esm/index.js.map +1 -1
  47. package/esm/node/basic-v4.js +283 -277
  48. package/esm/node/basic-v4.js.map +1 -1
  49. package/esm/node/basic-v4.mjs +283 -277
  50. package/esm/node/basic-v4.mjs.map +1 -1
  51. package/esm/node/basic-v5.js +297 -281
  52. package/esm/node/basic-v5.js.map +1 -1
  53. package/esm/node/basic-v5.mjs +297 -281
  54. package/esm/node/basic-v5.mjs.map +1 -1
  55. package/esm/node/full-v4.js +295 -289
  56. package/esm/node/full-v4.js.map +1 -1
  57. package/esm/node/full-v4.mjs +295 -289
  58. package/esm/node/full-v4.mjs.map +1 -1
  59. package/esm/node/full-v5.js +309 -293
  60. package/esm/node/full-v5.js.map +1 -1
  61. package/esm/node/full-v5.mjs +309 -293
  62. package/esm/node/full-v5.mjs.map +1 -1
  63. package/esm/node/index.js +310 -294
  64. package/esm/node/index.js.map +1 -1
  65. package/esm/node/index.mjs +310 -294
  66. package/esm/node/index.mjs.map +1 -1
  67. package/esm/node/v4.js +295 -289
  68. package/esm/node/v4.js.map +1 -1
  69. package/esm/node/v4.mjs +295 -289
  70. package/esm/node/v4.mjs.map +1 -1
  71. package/esm/node/v5.js +309 -293
  72. package/esm/node/v5.js.map +1 -1
  73. package/esm/node/v5.mjs +309 -293
  74. package/esm/node/v5.mjs.map +1 -1
  75. package/esm/v4.js +295 -289
  76. package/esm/v4.js.map +1 -1
  77. package/esm/v5.js +309 -293
  78. package/esm/v5.js.map +1 -1
  79. package/esm/web/basic-v4.js +283 -277
  80. package/esm/web/basic-v4.js.map +1 -1
  81. package/esm/web/basic-v4.min.js +1 -1
  82. package/esm/web/basic-v4.min.js.br +0 -0
  83. package/esm/web/basic-v4.min.js.gz +0 -0
  84. package/esm/web/basic-v5.js +297 -281
  85. package/esm/web/basic-v5.js.map +1 -1
  86. package/esm/web/basic-v5.min.js +1 -1
  87. package/esm/web/basic-v5.min.js.br +0 -0
  88. package/esm/web/basic-v5.min.js.gz +0 -0
  89. package/esm/web/full-v4.js +295 -289
  90. package/esm/web/full-v4.js.map +1 -1
  91. package/esm/web/full-v4.min.js +1 -1
  92. package/esm/web/full-v4.min.js.br +0 -0
  93. package/esm/web/full-v4.min.js.gz +0 -0
  94. package/esm/web/full-v5.js +309 -293
  95. package/esm/web/full-v5.js.map +1 -1
  96. package/esm/web/full-v5.min.js +1 -1
  97. package/esm/web/full-v5.min.js.br +0 -0
  98. package/esm/web/full-v5.min.js.gz +0 -0
  99. package/esm/web/index.js +310 -294
  100. package/esm/web/index.js.map +1 -1
  101. package/esm/web/index.min.js +1 -1
  102. package/esm/web/index.min.js.br +0 -0
  103. package/esm/web/index.min.js.gz +0 -0
  104. package/esm/web/v4.js +295 -289
  105. package/esm/web/v4.js.map +1 -1
  106. package/esm/web/v4.min.js +1 -1
  107. package/esm/web/v4.min.js.br +0 -0
  108. package/esm/web/v4.min.js.gz +0 -0
  109. package/esm/web/v5.js +309 -293
  110. package/esm/web/v5.js.map +1 -1
  111. package/esm/web/v5.min.js +1 -1
  112. package/esm/web/v5.min.js.br +0 -0
  113. package/esm/web/v5.min.js.gz +0 -0
  114. package/package.json +7 -8
@@ -617,88 +617,15 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
617
617
  }
618
618
  }
619
619
 
620
- function ao_defer_ctx(as_res = (...args) => args) {
621
- let y,n,_pset = (a,b) => { y=a, n=b; };
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
- const ao_defer_v = /* #__PURE__ */
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(send_ping, 1000 * td);
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
- const _mqtt_cmdid_dispatch ={
711
- create(target) {
712
- return {__proto__: this, target, hashbelt: [new Map()]} }
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
- , bind_pkt_future(_pkt_id=100) {
715
- let {hashbelt} = this;
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
- return (( pkt_or_key ) => {
722
- if ('string' === typeof pkt_or_key) {
723
- _tmp_ = pkt_or_key;}
724
- else {
725
- _pkt_id = (_pkt_id + 1) & 0xffff;
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
- return new Promise(_by_key)}) }
702
+ return new Promise(_ftr_by_key)}
729
703
 
730
- , answer(key, pkt) {
731
- for (let map of this.hashbelt) {
732
- let answer_monad = map.get(key);
733
- if (undefined !== answer_monad) {
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
- answer_monad([pkt, /*err*/]); // option/maybe monad
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
- cmdids[pkt.id](_disp_, pkt, ctx); }
716
+ _mqtt_cmdids[pkt.id](target, answer, pkt, ctx);}
812
717
 
813
- if (Date.now() > rotate_ts) {
814
- _disp_.rotate_belt(rotate_n);
815
- rotate_ts = rotate_td + Date.now();} } }
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 ('string' !== typeof cid) {
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 res = await this._conn_
860
- .send_connect('connect', pkt, 'connack');
861
-
862
- if (0 != res[0].reason) {
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 res = await this._send('disconnect', pkt);
871
- this._conn_.reset(false);
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
- return this._send('auth', pkt, 'auth')}
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 ('function' === typeof pub_opt) {
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 {msg} = pkt;
916
- switch (typeof msg) {
917
- case 'function':
918
- pub_opt = {...pub_opt, fn_encode: msg};
919
- // flow into 'undefined' case
920
- case 'undefined':
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 : void 0 ) }// key
819
+ pkt.qos ? pkt : null ) }// key
938
820
 
939
821
 
940
822
  // Internal API
941
823
 
942
- /* async _send(type, pkt) -- provided by _conn_ and transport */
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(this, target)}
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_(self=this) {
955
- self._once_ = _=>0;
956
- let p = self.prototype;
837
+ static _once_(klass=this) {
838
+ klass._once_ = _=>0;
839
+ var alias, name, p = klass.prototype;
957
840
  p.MQTTError = MQTTError;
958
- for (let alias of self._aliases().split(/\s+/)) {
959
- alias = alias.split(':');
960
- let fn = alias[1] && p[alias[1]];
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 pkt_api = {
987
- utf8(u8) { return new TextDecoder('utf-8').decode(u8 || this.payload ) },
988
- json(u8) { return JSON.parse( this.utf8(u8) || null ) },
989
- text(u8) { return this.utf8(u8) },
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
+ opt = {...opt_default, ...opt};
983
+ super();
984
+ this.with(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 self = class extends this {};
995
- self.prototype.mqtt_ctx =
998
+ let klass = class extends this {};
999
+ klass.prototype.mqtt_ctx =
996
1000
  mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
997
- return self}
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
- let on_mqtt_chunk = this._conn_.set(
1043
- this.mqtt_ctx,
1044
- write_u8_pkt);
1045
-
1046
- this._msg_loop = ((async () => {
1047
- try {
1048
- async_iter = await async_iter;
1049
- for await (let chunk of async_iter)
1050
- on_mqtt_chunk(chunk);
1051
- this._conn_.reset();}
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 ready, {readyState} = websock;
1134
+ let ws_ready, readyState = websock.readyState;
1126
1135
  if (1 !== readyState) {
1127
1136
  if (0 !== readyState) {
1128
- throw new Error('Invalid WebSocket readyState') }
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
- let {_conn_} = this;
1134
- let on_mqtt_chunk = _conn_.set(
1135
- this.mqtt_ctx,
1136
- async u8_pkt =>(
1137
- await ready
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
- websock.onmessage = evt =>(on_mqtt_chunk(new Uint8Array(evt.data)));
1141
- websock.onclose = evt => {
1142
- if (! evt.wasClean) {
1143
- var err = new Error('websocket connection close');
1144
- err.code = evt.code;
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
- _conn_.reset(err);};
1153
+ conn.reset(err);}; } );
1148
1154
 
1149
1155
  return this} }
1150
1156
 
1151
- const version = '0.5.3-node';
1157
+ const version = '0.6.1-node';
1152
1158
 
1153
1159
  const MQTTClient_v4 = /* #__PURE__ */
1154
1160
  MQTTCore.mqtt_ctx(4, mqtt_opts_v4);