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.
Files changed (113) hide show
  1. package/cjs/basic-v4.cjs +283 -277
  2. package/cjs/basic-v4.cjs.map +1 -1
  3. package/cjs/basic-v5.cjs +297 -281
  4. package/cjs/basic-v5.cjs.map +1 -1
  5. package/cjs/full-v4.cjs +295 -289
  6. package/cjs/full-v4.cjs.map +1 -1
  7. package/cjs/full-v5.cjs +309 -293
  8. package/cjs/full-v5.cjs.map +1 -1
  9. package/cjs/index.cjs +310 -295
  10. package/cjs/index.cjs.map +1 -1
  11. package/cjs/v4.cjs +295 -289
  12. package/cjs/v4.cjs.map +1 -1
  13. package/cjs/v5.cjs +309 -293
  14. package/cjs/v5.cjs.map +1 -1
  15. package/code/_cmdid_dispatch.jsy +45 -69
  16. package/code/_conn.jsy +96 -72
  17. package/code/_dispatch.jsy +36 -28
  18. package/code/_utils.jsy +17 -0
  19. package/code/base.jsy +33 -61
  20. package/code/core.jsy +73 -51
  21. package/code/router_path.jsy +2 -1
  22. package/esm/basic-v4.js +283 -277
  23. package/esm/basic-v4.js.map +1 -1
  24. package/esm/basic-v5.js +297 -281
  25. package/esm/basic-v5.js.map +1 -1
  26. package/esm/deno/basic-v4.js +287 -281
  27. package/esm/deno/basic-v4.js.map +1 -1
  28. package/esm/deno/basic-v5.js +301 -285
  29. package/esm/deno/basic-v5.js.map +1 -1
  30. package/esm/deno/full-v4.js +299 -293
  31. package/esm/deno/full-v4.js.map +1 -1
  32. package/esm/deno/full-v5.js +313 -297
  33. package/esm/deno/full-v5.js.map +1 -1
  34. package/esm/deno/index.js +314 -298
  35. package/esm/deno/index.js.map +1 -1
  36. package/esm/deno/v4.js +299 -293
  37. package/esm/deno/v4.js.map +1 -1
  38. package/esm/deno/v5.js +313 -297
  39. package/esm/deno/v5.js.map +1 -1
  40. package/esm/full-v4.js +295 -289
  41. package/esm/full-v4.js.map +1 -1
  42. package/esm/full-v5.js +309 -293
  43. package/esm/full-v5.js.map +1 -1
  44. package/esm/index.js +310 -294
  45. package/esm/index.js.map +1 -1
  46. package/esm/node/basic-v4.js +283 -277
  47. package/esm/node/basic-v4.js.map +1 -1
  48. package/esm/node/basic-v4.mjs +283 -277
  49. package/esm/node/basic-v4.mjs.map +1 -1
  50. package/esm/node/basic-v5.js +297 -281
  51. package/esm/node/basic-v5.js.map +1 -1
  52. package/esm/node/basic-v5.mjs +297 -281
  53. package/esm/node/basic-v5.mjs.map +1 -1
  54. package/esm/node/full-v4.js +295 -289
  55. package/esm/node/full-v4.js.map +1 -1
  56. package/esm/node/full-v4.mjs +295 -289
  57. package/esm/node/full-v4.mjs.map +1 -1
  58. package/esm/node/full-v5.js +309 -293
  59. package/esm/node/full-v5.js.map +1 -1
  60. package/esm/node/full-v5.mjs +309 -293
  61. package/esm/node/full-v5.mjs.map +1 -1
  62. package/esm/node/index.js +310 -294
  63. package/esm/node/index.js.map +1 -1
  64. package/esm/node/index.mjs +310 -294
  65. package/esm/node/index.mjs.map +1 -1
  66. package/esm/node/v4.js +295 -289
  67. package/esm/node/v4.js.map +1 -1
  68. package/esm/node/v4.mjs +295 -289
  69. package/esm/node/v4.mjs.map +1 -1
  70. package/esm/node/v5.js +309 -293
  71. package/esm/node/v5.js.map +1 -1
  72. package/esm/node/v5.mjs +309 -293
  73. package/esm/node/v5.mjs.map +1 -1
  74. package/esm/v4.js +295 -289
  75. package/esm/v4.js.map +1 -1
  76. package/esm/v5.js +309 -293
  77. package/esm/v5.js.map +1 -1
  78. package/esm/web/basic-v4.js +283 -277
  79. package/esm/web/basic-v4.js.map +1 -1
  80. package/esm/web/basic-v4.min.js +1 -1
  81. package/esm/web/basic-v4.min.js.br +0 -0
  82. package/esm/web/basic-v4.min.js.gz +0 -0
  83. package/esm/web/basic-v5.js +297 -281
  84. package/esm/web/basic-v5.js.map +1 -1
  85. package/esm/web/basic-v5.min.js +1 -1
  86. package/esm/web/basic-v5.min.js.br +0 -0
  87. package/esm/web/basic-v5.min.js.gz +0 -0
  88. package/esm/web/full-v4.js +295 -289
  89. package/esm/web/full-v4.js.map +1 -1
  90. package/esm/web/full-v4.min.js +1 -1
  91. package/esm/web/full-v4.min.js.br +0 -0
  92. package/esm/web/full-v4.min.js.gz +0 -0
  93. package/esm/web/full-v5.js +309 -293
  94. package/esm/web/full-v5.js.map +1 -1
  95. package/esm/web/full-v5.min.js +1 -1
  96. package/esm/web/full-v5.min.js.br +0 -0
  97. package/esm/web/full-v5.min.js.gz +0 -0
  98. package/esm/web/index.js +310 -294
  99. package/esm/web/index.js.map +1 -1
  100. package/esm/web/index.min.js +1 -1
  101. package/esm/web/index.min.js.br +0 -0
  102. package/esm/web/index.min.js.gz +0 -0
  103. package/esm/web/v4.js +295 -289
  104. package/esm/web/v4.js.map +1 -1
  105. package/esm/web/v4.min.js +1 -1
  106. package/esm/web/v4.min.js.br +0 -0
  107. package/esm/web/v4.min.js.gz +0 -0
  108. package/esm/web/v5.js +309 -293
  109. package/esm/web/v5.js.map +1 -1
  110. package/esm/web/v5.min.js +1 -1
  111. package/esm/web/v5.min.js.br +0 -0
  112. package/esm/web/v5.min.js.gz +0 -0
  113. package/package.json +7 -8
@@ -614,88 +614,15 @@ function mqtt_pkt_ctx(mqtt_level, opts, pkt_ctx) {
614
614
  }
615
615
  }
616
616
 
617
- function ao_defer_ctx(as_res = (...args) => args) {
618
- let y,n,_pset = (a,b) => { y=a, n=b; };
619
- return p =>(
620
- p = new Promise(_pset)
621
- , as_res(p, y, n)) }
617
+ const _isfn = v => typeof v === 'function';
618
+ const _isstr = v => typeof v === 'string';
622
619
 
623
- const ao_defer_v = /* #__PURE__ */
624
- ao_defer_ctx();
625
-
626
- Promise.resolve({type:'init'});
627
-
628
- function _mqtt_conn(client, [on_mqtt, pkt_future]) {
629
- let _q_init = ao_defer_v(), _q_ready = ao_defer_v();
630
- let _send_ready = async (...args) => (await _q_ready[0])(...args);
631
- let _send_mqtt_pkt, _has_connected;
632
- client._send = _send_ready;
633
-
634
- return {
635
- async when_ready() {await _q_ready[0];}
636
-
637
- , ping: _ping_interval (() =>_send_mqtt_pkt?.('pingreq'))
638
-
639
- , reset(err) {
640
- if (! _send_mqtt_pkt) {return}
641
-
642
- if (err) {
643
- _q_init[2](err);}
644
-
645
- _send_mqtt_pkt = null;
646
- _q_init = ao_defer_v();
647
- client._send = _send_ready;
648
-
649
- // call client.on_conn_reset in next promise microtask
650
- client.conn_emit('on_disconnect', false===err, err);}
651
-
652
- , async send_connect(... args) {
653
- if (! _send_mqtt_pkt) {
654
- await _q_init[0]; }// _send_mqtt_pkt is set before fulfilled
655
-
656
- // await connack response
657
- let res = await _send_mqtt_pkt(...args);
658
- if (0 == res[0].reason) {
659
- _has_connected = true;
660
- // resolve _q_ready[0] with _send_mqtt_pkt closure
661
- _q_ready[1](client._send = _send_mqtt_pkt);
662
- _q_ready = ao_defer_v();
663
- client.conn_emit('on_ready');}
664
-
665
- return res}
666
-
667
- , is_set: (() =>!! _send_mqtt_pkt)
668
- , set(mqtt_ctx, send_u8_pkt) {
669
- if (_send_mqtt_pkt) {
670
- throw new Error('Already connected')}
671
-
672
- mqtt_ctx = mqtt_ctx.mqtt_stream();
673
- let sess_ctx = {mqtt: client};
674
- let on_mqtt_chunk = u8_buf =>
675
- on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx);
676
-
677
- _send_mqtt_pkt = async (type, pkt, key) => {
678
- let res = undefined !== key
679
- ? pkt_future(key) : true;
680
-
681
- await send_u8_pkt(
682
- mqtt_ctx.encode_pkt(type, pkt));
683
-
684
- return res};
685
-
686
- _q_init[1](_send_mqtt_pkt); // resolve _q_init with _send_mqtt_pkt closure
687
-
688
- // call client.on_live in next promise microtask
689
- client.conn_emit('on_live', _has_connected);
690
- return on_mqtt_chunk} } }
691
-
692
-
693
- function _ping_interval(send_ping) {
620
+ function _interval(fn_callback) {
694
621
  let tid;
695
622
  return (( td ) => {
696
623
  tid = clearInterval(tid);
697
624
  if (td) {
698
- tid = setInterval(send_ping, 1000 * td);
625
+ tid = setInterval(fn_callback, 1000 * td);
699
626
 
700
627
  // ensure the interval allows the Deno event loop to exit
701
628
  Deno.unrefTimer(tid);
@@ -704,148 +631,108 @@ function _ping_interval(send_ping) {
704
631
 
705
632
  return true} }) }
706
633
 
707
- const _mqtt_cmdid_dispatch ={
708
- create(target) {
709
- return {__proto__: this, target, hashbelt: [new Map()]} }
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
679
+
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 || {};
684
+
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);
710
688
 
711
- , bind_pkt_future(_pkt_id=100) {
712
- let {hashbelt} = this;
689
+ on_mqtt([]); // init hashbelt and rotate_ts
690
+ return [on_mqtt, pkt_future]
713
691
 
714
- let _tmp_; // use _tmp_ to reuse _by_key closure
715
- let _by_key = answer_monad =>
716
- hashbelt[0].set(_tmp_, answer_monad);
717
692
 
718
- return (( pkt_or_key ) => {
719
- if ('string' === typeof pkt_or_key) {
720
- _tmp_ = pkt_or_key;}
721
- else {
722
- _pkt_id = (_pkt_id + 1) & 0xffff;
723
- _tmp_ = pkt_or_key.pkt_id = _pkt_id;}
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;
724
698
 
725
- return new Promise(_by_key)}) }
699
+ return new Promise(_ftr_by_key)}
726
700
 
727
- , answer(key, pkt) {
728
- for (let map of this.hashbelt) {
729
- let answer_monad = map.get(key);
730
- if (undefined !== answer_monad) {
701
+ function answer(key, pkt) {
702
+ for (let map of hashbelt) {
703
+ let fn_answer = map.get(key);
704
+ if (fn_answer) {
731
705
  map.delete(key);
732
706
 
733
- answer_monad([pkt, /*err*/]); // option/maybe monad
707
+ fn_answer([pkt, /*err*/]); // option/maybe monad
734
708
  return true} }
735
709
  return false}
736
710
 
737
- , rotate_belt(n) {
738
- let {hashbelt} = this;
739
- hashbelt.unshift(new Map());
740
- for (let old of hashbelt.splice(n || 5)) {
741
- for (let answer_monad of old.values()) {
742
- answer_monad([/*pkt*/, 'expired']); } } }// option/maybe monad
743
-
744
- , cmdids: ((() => {
745
- return [
746
- (() =>{} )// 0x0 reserved
747
- , by_evt // 0x1 connect
748
- , by_type // 0x2 connack
749
- , by_evt // 0x3 publish
750
- , by_id // 0x4 puback
751
- , by_id // 0x5 pubrec
752
- , by_id // 0x6 pubrel
753
- , by_id // 0x7 pubcomp
754
- , by_evt // 0x8 subscribe
755
- , by_id // 0x9 suback
756
- , by_evt // 0xa unsubscribe
757
- , by_id // 0xb unsuback
758
- , by_type // 0xc pingreq
759
- , by_type // 0xd pingresp
760
- , by_evt // 0xe disconnect
761
- , by_type ]// 0xf auth
762
-
763
-
764
- function by_id(disp, pkt) {
765
- disp.answer(pkt.pkt_id, pkt); }
766
-
767
- function by_type(disp, pkt, ctx) {
768
- disp.answer(pkt.type, pkt);
769
- by_evt(disp, pkt, ctx);}
770
-
771
- async function by_evt({target}, pkt, ctx) {
772
- let fn = target[`mqtt_${pkt.type}`]
773
- || target.mqtt_pkt;
774
-
775
- await fn?.call(target, pkt, ctx);} })()) };
776
-
777
- /*
778
- on_mqtt_type = {
779
- mqtt_auth(pkt, ctx) ::
780
- mqtt_connect(pkt, ctx) ::
781
- mqtt_connack(pkt, ctx) ::
782
- mqtt_disconnect(pkt, ctx) ::
783
-
784
- mqtt_publish(pkt, ctx)
785
- mqtt_subscribe(pkt, ctx) ::
786
- mqtt_unsubscribe(pkt, ctx) ::
787
-
788
- mqtt_pingreq(pkt, ctx) ::
789
- mqtt_pingresp(pkt, ctx) ::
790
- }
791
- */
792
-
793
- function _mqtt_dispatch(opt, target) {
794
- let _disp_ = _mqtt_cmdid_dispatch.create(target);
795
- let { cmdids } = _disp_;
796
-
797
- // default rotate at 1s across 5 buckets
798
- let { td: rotate_td=1000, n: rotate_n=5 } =
799
- opt && opt.rotate || {};
800
-
801
- let rotate_ts = rotate_td + Date.now();
802
-
803
- return [on_mqtt,
804
- _disp_.bind_pkt_future()]
805
-
806
711
  function on_mqtt(pkt_list, ctx) {
807
712
  for (let pkt of pkt_list) {
808
- cmdids[pkt.id](_disp_, pkt, ctx); }
713
+ _mqtt_cmdids[pkt.id](target, answer, pkt, ctx);}
809
714
 
810
- if (Date.now() > rotate_ts) {
811
- _disp_.rotate_belt(rotate_n);
812
- rotate_ts = rotate_td + Date.now();} } }
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
813
723
 
814
724
  class MQTTError extends Error {
815
725
  constructor(mqtt_pkt, reason=mqtt_pkt.reason) {
726
+ // use hex-encoded reasons to match MQTT spec documentation
816
727
  super(`[0x${reason.toString(16)}] ${reason.reason}`);
817
728
  this.mqtt_pkt = mqtt_pkt;
818
729
  this.reason = reason;} }
819
730
 
820
731
  class MQTTBase {
821
- constructor(opt={}) {
822
- this.with(opt);
823
- this._conn_ = _mqtt_conn(this,
824
- this._init_dispatch(opt, this)); }
825
-
826
- with(fns_ns) {
827
- for (let [k,v] of Object.entries(fns_ns)) {
828
- if ('function' === typeof v) {this[k] = v;} }
829
- return this}
830
-
831
- async conn_emit(evt, arg, err_arg) {
832
- this.log_conn?.(evt, arg, err_arg);
833
- try {
834
- let fn_evt = this[await evt]; // microtask break using `await evt`
835
- if (fn_evt) {
836
- await fn_evt.call(this, this, arg, err_arg);}
837
- else if (err_arg) {throw err_arg} }
838
- catch (err) {
839
- this.on_error(err, evt);} }
840
-
841
- on_error(err, evt) {
842
- console.warn('[[u8-mqtt error: %s]]', evt, err); }
843
-
844
732
  // Handshaking Packets
845
-
846
733
  async connect(pkt={}) {
847
734
  let cid = pkt.client_id;
848
- if ('string' !== typeof cid) {
735
+ if (! _isstr(cid)) {
849
736
  // see init_client_id implementation in core.jsy
850
737
  pkt.client_id = cid = this.client_id || this.init_client_id(cid);}
851
738
  this.client_id = cid;
@@ -853,23 +740,20 @@ class MQTTBase {
853
740
  if (null == pkt.keep_alive) {
854
741
  pkt.keep_alive = 60;}
855
742
 
856
- let res = await this._conn_
857
- .send_connect('connect', pkt, 'connack');
858
-
859
- if (0 != res[0].reason) {
860
- throw new this.MQTTError(res[0])}
861
-
862
- // TODO: merge with server's keep_alive frequency
863
- this._conn_.ping(pkt.keep_alive);
864
- 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)}
865
747
 
866
748
  async disconnect(pkt={}) {
867
- let res = await this._send('disconnect', pkt);
868
- this._conn_.reset(false);
869
- return res}
749
+ let response = await this._send0('disconnect', pkt);
750
+ return this.conn.on_dis(pkt, response)}
870
751
 
871
- auth(pkt={}) {
872
- return this._send('auth', pkt, 'auth')}
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)}
873
757
 
874
758
  ping() {return this._send('pingreq', null, 'pingresp')}
875
759
  puback({pkt_id}) {return this._send('puback', {pkt_id})}
@@ -906,20 +790,18 @@ class MQTTBase {
906
790
  // alias: publish -- because 'pub' is shorter for semantic aliases above
907
791
  async pub(pkt, pub_opt) {
908
792
  if (undefined === pkt.payload) {
909
- if ('function' === typeof pub_opt) {
793
+ if (_isfn(pub_opt)) {
794
+ // pub_opt as a function is fn_encode value
910
795
  pub_opt = {fn_encode: pub_opt};}
911
796
 
912
- let {msg} = pkt;
913
- switch (typeof msg) {
914
- case 'function':
915
- pub_opt = {...pub_opt, fn_encode: msg};
916
- // flow into 'undefined' case
917
- case 'undefined':
918
- // return a single-value closure to publish packets
919
- 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)}
920
803
 
921
804
  // Encode payload from msg; fn_encode allows alternative to JSON.stringify
922
- let {fn_encode} = pub_opt || {};
923
805
  pkt.payload = fn_encode
924
806
  ? await fn_encode(msg)
925
807
  : JSON.stringify(msg);}
@@ -931,31 +813,31 @@ class MQTTBase {
931
813
  pkt = pub_opt.xform(pkt) || pkt;} }
932
814
 
933
815
  return this._send('publish', pkt,
934
- pkt.qos ? pkt : void 0 ) }// key
816
+ pkt.qos ? pkt : null ) }// key
935
817
 
936
818
 
937
819
  // Internal API
938
820
 
939
- /* async _send(type, pkt) -- provided by _conn_ and transport */
821
+ /* async _send0(type, pkt) -- provided by conn and transport */
822
+ /* async _send(type, pkt) -- provided by conn and transport */
940
823
 
941
824
  _init_dispatch(opt) {
942
825
  this.constructor?._once_();
943
826
  let target ={__proto__: opt.on_mqtt_type};
944
827
  target.mqtt_publish ||=
945
828
  this._init_router?.(opt, this, target);
946
- return _mqtt_dispatch(this, target)}
829
+ return _mqtt_dispatch(opt, target)}
947
830
 
948
831
  static _aliases() {
949
832
  return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'}
950
833
 
951
- static _once_(self=this) {
952
- self._once_ = _=>0;
953
- let p = self.prototype;
834
+ static _once_(klass=this) {
835
+ klass._once_ = _=>0;
836
+ var alias, name, p = klass.prototype;
954
837
  p.MQTTError = MQTTError;
955
- for (let alias of self._aliases().split(/\s+/)) {
956
- alias = alias.split(':');
957
- let fn = alias[1] && p[alias[1]];
958
- if (fn) {p[alias[0]] = fn;} } } }
838
+ for (alias of klass._aliases().split(/\s+/)) {
839
+ [alias, name] = alias.split(':');
840
+ p[alias] = p[name];} } }
959
841
 
960
842
 
961
843
  function _as_topics(pkt, ex, topic_prefix) {
@@ -980,37 +862,167 @@ function _as_topics(pkt, ex, topic_prefix) {
980
862
  pkt.topics = pkt.topics.map(_prefix_topics);}
981
863
  return pkt}
982
864
 
983
- const pkt_api = {
984
- utf8(u8) { return new TextDecoder('utf-8').decode(u8 || this.payload ) },
985
- json(u8) { return JSON.parse( this.utf8(u8) || null ) },
986
- text(u8) { return this.utf8(u8) },
987
- };
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};
988
976
 
989
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
+
990
994
  static mqtt_ctx(mqtt_level, mqtt_opts, pkt_ctx=pkt_api) {
991
- let self = class extends this {};
992
- self.prototype.mqtt_ctx =
995
+ let klass = class extends this {};
996
+ klass.prototype.mqtt_ctx =
993
997
  mqtt_pkt_ctx(mqtt_level, mqtt_opts, pkt_ctx);
994
- return self}
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); }
995
1015
 
996
1016
 
997
1017
  // automatic Client Id for connect()
998
1018
  init_client_id(parts=['u8-mqtt--','']) {
999
- let sess_stg=this.sess_stg;
1019
+ let sess_stg = this.sess_stg;
1000
1020
  let key, cid = sess_stg?.getItem(key=parts.join(' '));
1001
1021
  if (! cid) {
1002
1022
  cid = parts.join(Math.random().toString(36).slice(2));
1003
1023
  sess_stg?.setItem(key, cid);}
1004
1024
  return cid}
1005
1025
 
1006
- get sess_stg() {return globalThis.sessionStorage}
1007
-
1008
-
1009
- //on_error(err, evt) ::
1010
- // console.warn @ '[[u8-mqtt error: %s]]', evt, err
1011
-
1012
- //log_conn(evt, arg, err_arg) ::
1013
- // console.info @ '[[u8-mqtt log: %s]]', evt, arg, err_arg
1014
1026
 
1015
1027
  on_live(client, is_reconnect) {
1016
1028
  if (is_reconnect) {
@@ -1036,19 +1048,16 @@ class MQTTCore extends MQTTBase {
1036
1048
  return new Promise(done => setTimeout(done, ms)) }
1037
1049
 
1038
1050
  with_async_iter(async_iter, write_u8_pkt) {
1039
- let on_mqtt_chunk = this._conn_.set(
1040
- this.mqtt_ctx,
1041
- write_u8_pkt);
1042
-
1043
- this._msg_loop = ((async () => {
1044
- try {
1045
- async_iter = await async_iter;
1046
- for await (let chunk of async_iter)
1047
- on_mqtt_chunk(chunk);
1048
- this._conn_.reset();}
1049
- catch (err) {
1050
- this._conn_.reset(err);} })());
1051
-
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);} } );
1052
1061
  return this}
1053
1062
 
1054
1063
 
@@ -1067,11 +1076,11 @@ class MQTTCore extends MQTTBase {
1067
1076
  this.with_deno_iter(
1068
1077
  Deno.connectTls(opt)) ) }
1069
1078
 
1070
- with_deno_iter(conn) {
1079
+ with_deno_iter(transport) {
1071
1080
  return this.with_async_iter(
1072
- conn.then(Deno.iter),
1073
- async u8_pkt =>
1074
- (await conn).write(u8_pkt)) }
1081
+ transport.then(Deno.iter),
1082
+ transport.then(write_stream =>
1083
+ u8_pkt => write_stream.write(u8_pkt)) ) }
1075
1084
 
1076
1085
  _conn_opt([a0, a1, a2]) {
1077
1086
  // (port, hostname, options) or (url, options)
@@ -1119,33 +1128,30 @@ class MQTTCore extends MQTTBase {
1119
1128
 
1120
1129
  websock.binaryType = 'arraybuffer';
1121
1130
 
1122
- let ready, {readyState} = websock;
1131
+ let ws_ready, readyState = websock.readyState;
1123
1132
  if (1 !== readyState) {
1124
1133
  if (0 !== readyState) {
1125
- throw new Error('Invalid WebSocket readyState') }
1126
-
1127
- ready = new Promise(fn => websock.onopen = fn); }
1134
+ throw new Error('WS readyState') }
1128
1135
 
1136
+ ws_ready = new Promise(ready => websock.onopen = ready); }
1129
1137
 
1130
- let {_conn_} = this;
1131
- let on_mqtt_chunk = _conn_.set(
1132
- this.mqtt_ctx,
1133
- async u8_pkt =>(
1134
- await ready
1135
- , 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)) );
1136
1143
 
1137
- websock.onmessage = evt =>(on_mqtt_chunk(new Uint8Array(evt.data)));
1138
- websock.onclose = evt => {
1139
- if (! evt.wasClean) {
1140
- var err = new Error('websocket connection close');
1141
- err.code = evt.code;
1142
- 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;}
1143
1149
 
1144
- _conn_.reset(err);};
1150
+ conn.reset(err);}; } );
1145
1151
 
1146
1152
  return this} }
1147
1153
 
1148
- const version = '0.5.3-deno';
1154
+ const version = '0.6.0-deno';
1149
1155
 
1150
1156
  const MQTTClient_v4 = /* #__PURE__ */
1151
1157
  MQTTCore.mqtt_ctx(4, mqtt_opts_v4);