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
@@ -1,71 +1,47 @@
1
1
 
2
- export const _mqtt_cmdid_dispatch = @{}
3
- create(target) ::
4
- return @{} __proto__: this, target, hashbelt: [new Map()]
5
-
6
- bind_pkt_future(_pkt_id=100) ::
7
- let {hashbelt} = this
8
-
9
- let _tmp_ // use _tmp_ to reuse _by_key closure
10
- let _by_key = answer_monad =>
11
- hashbelt[0].set(_tmp_, answer_monad)
12
-
13
- return @\ pkt_or_key ::
14
- if 'string' === typeof pkt_or_key ::
15
- _tmp_ = pkt_or_key
16
- else ::
17
- _pkt_id = (_pkt_id + 1) & 0xffff
18
- _tmp_ = pkt_or_key.pkt_id = _pkt_id
19
-
20
- return new Promise(_by_key)
21
-
22
- answer(key, pkt) ::
23
- for let map of this.hashbelt ::
24
- let answer_monad = map.get(key)
25
- if undefined !== answer_monad ::
26
- map.delete(key)
27
-
28
- answer_monad([pkt, /*err*/]) // option/maybe monad
29
- return true
30
- return false
31
-
32
- rotate_belt(n) ::
33
- let {hashbelt} = this
34
- hashbelt.unshift @ new Map()
35
- for let old of hashbelt.splice(n || 5) ::
36
- for let answer_monad of old.values() ::
37
- answer_monad([/*pkt*/, 'expired']) // option/maybe monad
38
-
39
- cmdids: @!
40
- return @[]
41
- @=>{} // 0x0 reserved
42
- by_evt // 0x1 connect
43
- by_type // 0x2 connack
44
- by_evt // 0x3 publish
45
- by_id // 0x4 puback
46
- by_id // 0x5 pubrec
47
- by_id // 0x6 pubrel
48
- by_id // 0x7 pubcomp
49
- by_evt // 0x8 subscribe
50
- by_id // 0x9 suback
51
- by_evt // 0xa unsubscribe
52
- by_id // 0xb unsuback
53
- by_type // 0xc pingreq
54
- by_type // 0xd pingresp
55
- by_evt // 0xe disconnect
56
- by_type // 0xf auth
57
-
58
-
59
- function by_id(disp, pkt) ::
60
- disp.answer @ pkt.pkt_id, pkt
61
-
62
- function by_type(disp, pkt, ctx) ::
63
- disp.answer @ pkt.type, pkt
64
- by_evt(disp, pkt, ctx)
65
-
66
- async function by_evt({target}, pkt, ctx) ::
67
- let fn = target[`mqtt_${pkt.type}`]
68
- || target.mqtt_pkt
69
-
70
- await fn?.call(target, pkt, ctx)
2
+ async function _mqtt_cmd_evt(target, answer, pkt, ctx) ::
3
+ /* target : on_mqtt_type = {
4
+ mqtt_pkt(pkt, ctx) {}, // generic
5
+
6
+ mqtt_auth(pkt, ctx) {},
7
+ mqtt_connect(pkt, ctx) {},
8
+ mqtt_connack(pkt, ctx) {},
9
+ mqtt_disconnect(pkt, ctx) {},
10
+
11
+ mqtt_publish(pkt, ctx) {},
12
+ mqtt_subscribe(pkt, ctx) {},
13
+ mqtt_unsubscribe(pkt, ctx) {},
14
+
15
+ mqtt_pingreq(pkt, ctx) {},
16
+ mqtt_pingresp(pkt, ctx) {},
17
+ } */
18
+
19
+ let pkt_fn = target[`mqtt_${pkt.type}`] || target.mqtt_pkt
20
+ await pkt_fn?.call(target, pkt, ctx)
21
+
22
+ function _mqtt_cmd_type(target, answer, pkt, ctx) ::
23
+ answer(pkt.type, pkt)
24
+ _mqtt_cmd_evt(target, answer, pkt, ctx)
25
+
26
+ function _mqtt_cmd_id(target, answer, pkt) ::
27
+ answer(pkt.pkt_id, pkt)
28
+
29
+
30
+ export const _mqtt_cmdids = @[]
31
+ _ => {} // 0x0 reserved
32
+ _mqtt_cmd_evt // 0x1 connect
33
+ _mqtt_cmd_type // 0x2 connack
34
+ _mqtt_cmd_evt // 0x3 publish
35
+ _mqtt_cmd_id // 0x4 puback
36
+ _mqtt_cmd_id // 0x5 pubrec
37
+ _mqtt_cmd_id // 0x6 pubrel
38
+ _mqtt_cmd_id // 0x7 pubcomp
39
+ _mqtt_cmd_evt // 0x8 subscribe
40
+ _mqtt_cmd_id // 0x9 suback
41
+ _mqtt_cmd_evt // 0xa unsubscribe
42
+ _mqtt_cmd_id // 0xb unsuback
43
+ _mqtt_cmd_type // 0xc pingreq
44
+ _mqtt_cmd_type // 0xd pingresp
45
+ _mqtt_cmd_evt // 0xe disconnect
46
+ _mqtt_cmd_type // 0xf auth
71
47
 
package/code/_conn.jsy CHANGED
@@ -1,82 +1,106 @@
1
- import { ao_defer_v } from 'roap'
2
- export { ao_defer_v }
1
+ import { _interval } from './_utils.jsy'
2
+
3
+ const _defer_obj = o => @
4
+ o.p = new Promise @ (a,e) => { o.a=a; o.e=e }
5
+ , o
6
+
7
+ function _dfn_reset(client, attr, fn_after) ::
8
+ // a resetable deferred for a function
9
+ let self = {set}, afn = async (...args) => (await self.p)(...args)
10
+ return set()
11
+
12
+ function set() ::
13
+ if afn !== client[attr] ::
14
+ _defer_obj(self).p.then(fn_after, _=>0)
15
+ client[attr] = afn
16
+ return self
17
+
18
+ export function _mqtt_conn(opt, client, [on_mqtt, pkt_future]) ::
19
+ let _abort
20
+ let _dfn_send0 = _dfn_reset @ client, '_send0', // client._send0 getter/setter
21
+ _=> client.conn_emit('on_live', conn.has_connected)
22
+ let _dfn_ready = _dfn_reset @ client, '_send', // client._send getter/setter
23
+ _=> client.conn_emit('on_ready')
24
+ let _keep_alive_ival = _interval @=> client._send0('pingreq') // resettable interval for keep_alive ping
25
+
26
+ let conn = Object.create @:
27
+ ping: (td=conn.keep_alive) => _keep_alive_ival(td)
28
+
29
+ on_conn(pkt, response) ::
30
+ conn.has_connected = true
31
+ conn.keep_alive = opt.keep_alive || response[0].props?.server_keep_alive || pkt.keep_alive
32
+ client.conn_emit('on_conn')
33
+ return opt.use_auth
34
+ ? response // wait on enhanced authentication step
35
+ : conn.on_auth(null, response) // otherwise, connect is also auth
36
+
37
+ on_auth(pkt, response) ::
38
+ _dfn_ready.a(_dfn_send0.p)
39
+ if 0 != opt.keep_alive ::
40
+ conn.ping()
41
+ client.conn_emit('on_auth', !pkt)
42
+ return response
43
+
44
+ on_dis(pkt, response) ::
45
+ conn.reset(false)
46
+ return response
3
47
 
4
- export function _mqtt_conn(client, [on_mqtt, pkt_future]) ::
5
- let _q_init = ao_defer_v(), _q_ready = ao_defer_v()
6
- let _send_ready = async (...args) => (await _q_ready[0])(...args)
7
- let _send_mqtt_pkt, _has_connected
8
- client._send = _send_ready
48
+ reset(err) ::
49
+ if err ::
50
+ _dfn_send0.e(err) // send error to uses of _send0 (connect, auth)
51
+ _abort.e(err) // abort in-progress connections
9
52
 
10
- return @{}
11
- async when_ready() :: await _q_ready[0]
53
+ delete conn.is_set
54
+ conn.ready = handshake()
55
+ client.conn_emit('on_disconnect', false===err, err)
12
56
 
13
- ping: _ping_interval @=> _send_mqtt_pkt?.('pingreq')
57
+ abort() ::
58
+ _dfn_ready.e(err) // abort all messages awaiting ready state
59
+ return conn.reset(err)
14
60
 
15
- reset(err) ::
16
- if ! _send_mqtt_pkt :: return
61
+ async setup(gate, send_u8_pkt, init_msg_loop) ::
62
+ if conn.is_set ::
63
+ throw new Error() // already in-progress
17
64
 
18
- if err ::
19
- _q_init[2](err)
65
+ conn.is_set = true
66
+ await gate
20
67
 
21
- _send_mqtt_pkt = null
22
- _q_init = ao_defer_v()
23
- client._send = _send_ready
68
+ // setup send/recv MQTT parsing context
69
+ let mqtt_ctx = client.mqtt_ctx.mqtt_stream()
24
70
 
25
- // call client.on_conn_reset in next promise microtask
26
- client.conn_emit('on_disconnect', false===err, err)
71
+ :: // setup inbound message loop
72
+ let sess_ctx = {mqtt: client} // mutable session context
73
+ let on_mqtt_chunk = u8 => on_mqtt(mqtt_ctx.decode(u8), sess_ctx)
74
+ init_msg_loop(on_mqtt_chunk, conn)
75
+
76
+ // setup outbound message path and transport connection
77
+ send_u8_pkt = await send_u8_pkt
78
+ _dfn_send0.a @
79
+ async (type, pkt, key) => ::
80
+ let res = undefined !== key
81
+ ? pkt_future(key) : true
82
+
83
+ await send_u8_pkt @
84
+ mqtt_ctx.encode_pkt(type, pkt)
85
+ return res
86
+
87
+ conn.ready = handshake()
88
+ return conn
89
+
90
+ async function handshake() ::
91
+ _abort = _defer_obj({})
92
+
93
+ _keep_alive_ival(0) // clearInterval on keep alive ping
94
+ _dfn_send0.set() // reset client._send0 if necessary
95
+ _dfn_ready.set() // reset client._send if necessary
96
+
97
+ try ::
98
+ // set client._send0 as passtrhough after transport connection
99
+ client._send0 = await Promise.race @# _dfn_send0.p, _abort.p
27
100
 
28
- async send_connect(... args) ::
29
- if ! _send_mqtt_pkt ::
30
- await _q_init[0] // _send_mqtt_pkt is set before fulfilled
31
-
32
- // await connack response
33
- let res = await _send_mqtt_pkt(...args)
34
- if 0 == res[0].reason ::
35
- _has_connected = true
36
- // resolve _q_ready[0] with _send_mqtt_pkt closure
37
- _q_ready[1](client._send = _send_mqtt_pkt)
38
- _q_ready = ao_defer_v()
39
- client.conn_emit('on_ready')
40
-
41
- return res
42
-
43
- is_set: @=> !! _send_mqtt_pkt
44
- set(mqtt_ctx, send_u8_pkt) ::
45
- if _send_mqtt_pkt ::
46
- throw new Error('Already connected')
47
-
48
- mqtt_ctx = mqtt_ctx.mqtt_stream()
49
- let sess_ctx = {mqtt: client}
50
- let on_mqtt_chunk = u8_buf =>
51
- on_mqtt(mqtt_ctx.decode(u8_buf), sess_ctx)
52
-
53
- _send_mqtt_pkt = async (type, pkt, key) => ::
54
- let res = undefined !== key
55
- ? pkt_future(key) : true
56
-
57
- await send_u8_pkt @
58
- mqtt_ctx.encode_pkt(type, pkt)
59
-
60
- return res
61
-
62
- _q_init[1](_send_mqtt_pkt) // resolve _q_init with _send_mqtt_pkt closure
63
-
64
- // call client.on_live in next promise microtask
65
- client.conn_emit('on_live', _has_connected)
66
- return on_mqtt_chunk
67
-
68
-
69
- function _ping_interval(send_ping) ::
70
- let tid
71
- return @\ td ::
72
- tid = clearInterval(tid)
73
- if td ::
74
- tid = setInterval(send_ping, 1000 * td)
75
- #IF PLAT_DENO
76
- // ensure the interval allows the Deno event loop to exit
77
- Deno.unrefTimer(tid)
78
- #ELSE
79
- // ensure the interval allows the NodeJS event loop to exit
80
- tid.unref?.()
101
+ // set client._send as passtrhough after ready
102
+ client._send = await Promise.race @# _dfn_ready.p, _abort.p
81
103
  return true
104
+ catch err ::
105
+ return false
82
106
 
@@ -1,39 +1,47 @@
1
- import {_mqtt_cmdid_dispatch} from './_cmdid_dispatch.jsy'
1
+ import { _isstr } from './_utils.jsy'
2
+ import {_mqtt_cmdids} from './_cmdid_dispatch.jsy'
2
3
 
3
- /*
4
- on_mqtt_type = {
5
- mqtt_auth(pkt, ctx) ::
6
- mqtt_connect(pkt, ctx) ::
7
- mqtt_connack(pkt, ctx) ::
8
- mqtt_disconnect(pkt, ctx) ::
4
+ export function _mqtt_dispatch(opt, target) ::
5
+ let hashbelt=[], rotate_ts=0
6
+ // default rotate at 1s across 5 buckets
7
+ let { td: rotate_td=1000, n: rotate_n=5 } = opt?.rotate || {}
9
8
 
10
- mqtt_publish(pkt, ctx)
11
- mqtt_subscribe(pkt, ctx) ::
12
- mqtt_unsubscribe(pkt, ctx) ::
9
+ // Promise / future scaffolding
10
+ let _pkt_id=100, _ftr_key // use _ftr_key to reuse _by_key closure
11
+ let _ftr_by_key = fn_answer => hashbelt[0].set(_ftr_key, fn_answer)
13
12
 
14
- mqtt_pingreq(pkt, ctx) ::
15
- mqtt_pingresp(pkt, ctx) ::
16
- }
17
- */
13
+ on_mqtt([]) // init hashbelt and rotate_ts
14
+ return [on_mqtt, pkt_future]
18
15
 
19
- export function _mqtt_dispatch(opt, target) ::
20
- let _disp_ = _mqtt_cmdid_dispatch.create(target)
21
- let { cmdids } = _disp_
22
16
 
23
- // default rotate at 1s across 5 buckets
24
- let { td: rotate_td=1000, n: rotate_n=5 } =
25
- opt && opt.rotate || {}
17
+ function pkt_future(pkt_or_key) ::
18
+ if ! _isstr(pkt_or_key) ::
19
+ _pkt_id = (_pkt_id + 1) & 0xffff // 16-bit unsigned short
20
+ _ftr_key = pkt_or_key.pkt_id = _pkt_id
21
+ else _ftr_key = pkt_or_key
22
+
23
+ return new Promise(_ftr_by_key)
26
24
 
27
- let rotate_ts = rotate_td + Date.now()
25
+ function answer(key, pkt) ::
26
+ for let map of hashbelt ::
27
+ let fn_answer = map.get(key)
28
+ if fn_answer ::
29
+ map.delete(key)
28
30
 
29
- return @[] on_mqtt,
30
- _disp_.bind_pkt_future()
31
+ fn_answer([pkt, /*err*/]) // option/maybe monad
32
+ return true
33
+ return false
31
34
 
32
35
  function on_mqtt(pkt_list, ctx) ::
33
36
  for let pkt of pkt_list ::
34
- cmdids[pkt.id] @ _disp_, pkt, ctx
35
-
36
- if Date.now() > rotate_ts ::
37
- _disp_.rotate_belt(rotate_n)
38
- rotate_ts = rotate_td + Date.now()
37
+ _mqtt_cmdids[pkt.id](target, answer, pkt, ctx)
38
+
39
+ // rotate after rotate_ts
40
+ let now = Date.now()
41
+ if now > rotate_ts ::
42
+ rotate_ts = rotate_td + now
43
+ hashbelt.unshift(new Map())
44
+ while hashbelt.length > rotate_n ::
45
+ for let fn_answer of hashbelt.pop().values() ::
46
+ fn_answer([/*pkt*/, 'expired']) // option/maybe monad
39
47
 
@@ -0,0 +1,17 @@
1
+ export const _isfn = v => typeof v === 'function'
2
+ export const _isstr = v => typeof v === 'string'
3
+
4
+ export function _interval(fn_callback) ::
5
+ let tid
6
+ return @\ td ::
7
+ tid = clearInterval(tid)
8
+ if td ::
9
+ tid = setInterval(fn_callback, 1000 * td)
10
+ #IF PLAT_DENO
11
+ // ensure the interval allows the Deno event loop to exit
12
+ Deno.unrefTimer(tid)
13
+ #ELSE
14
+ // ensure the interval allows the NodeJS event loop to exit
15
+ tid.unref?.()
16
+ return true
17
+
package/code/base.jsy CHANGED
@@ -1,41 +1,18 @@
1
- import {_mqtt_conn} from './_conn.jsy'
2
- import {_mqtt_dispatch} from './_dispatch.jsy'
1
+ import { _isfn, _isstr } from './_utils.jsy'
2
+ import { _mqtt_dispatch } from './_dispatch.jsy'
3
3
 
4
4
  export class MQTTError extends Error ::
5
5
  constructor(mqtt_pkt, reason=mqtt_pkt.reason) ::
6
+ // use hex-encoded reasons to match MQTT spec documentation
6
7
  super(`[0x${reason.toString(16)}] ${reason.reason}`)
7
8
  this.mqtt_pkt = mqtt_pkt
8
9
  this.reason = reason
9
10
 
10
11
  export class MQTTBase ::
11
- constructor(opt={}) ::
12
- this.with(opt)
13
- this._conn_ = _mqtt_conn @ this,
14
- this._init_dispatch(opt, this)
15
-
16
- with(fns_ns) ::
17
- for let [k,v] of Object.entries(fns_ns) ::
18
- if 'function' === typeof v :: this[k] = v
19
- return this
20
-
21
- async conn_emit(evt, arg, err_arg) ::
22
- this.log_conn?.(evt, arg, err_arg)
23
- try ::
24
- let fn_evt = this[await evt] // microtask break using `await evt`
25
- if fn_evt ::
26
- await fn_evt.call(this, this, arg, err_arg)
27
- else if err_arg :: throw err_arg
28
- catch err ::
29
- this.on_error(err, evt)
30
-
31
- on_error(err, evt) ::
32
- console.warn @ '[[u8-mqtt error: %s]]', evt, err
33
-
34
12
  // Handshaking Packets
35
-
36
13
  async connect(pkt={}) ::
37
14
  let cid = pkt.client_id
38
- if 'string' !== typeof cid ::
15
+ if ! _isstr(cid) ::
39
16
  // see init_client_id implementation in core.jsy
40
17
  pkt.client_id = cid = this.client_id || this.init_client_id(cid)
41
18
  this.client_id = cid
@@ -43,23 +20,20 @@ export class MQTTBase ::
43
20
  if null == pkt.keep_alive ::
44
21
  pkt.keep_alive = 60
45
22
 
46
- let res = await this._conn_
47
- .send_connect('connect', pkt, 'connack')
48
-
49
- if 0 != res[0].reason ::
50
- throw new this.MQTTError(res[0])
51
-
52
- // TODO: merge with server's keep_alive frequency
53
- this._conn_.ping(pkt.keep_alive)
54
- return res
23
+ let response = await this._send0('connect', pkt, 'connack')
24
+ if 0 != response[0].reason :: // compare to 0 to coerce to number
25
+ throw new this.MQTTError(response[0])
26
+ return this.conn.on_conn(pkt, response)
55
27
 
56
28
  async disconnect(pkt={}) ::
57
- let res = await this._send('disconnect', pkt)
58
- this._conn_.reset(false)
59
- return res
29
+ let response = await this._send0('disconnect', pkt)
30
+ return this.conn.on_dis(pkt, response)
60
31
 
61
- auth(pkt={}) ::
62
- return this._send('auth', pkt, 'auth')
32
+ async auth(pkt={}) ::
33
+ let response = await this._send0('auth', pkt, 'auth')
34
+ if response[0].reason ::
35
+ throw new this.MQTTError(response[0])
36
+ return this.conn.on_auth(pkt, response)
63
37
 
64
38
  ping() :: return this._send('pingreq', null, 'pingresp')
65
39
  puback({pkt_id}) :: return this._send('puback', {pkt_id})
@@ -96,20 +70,18 @@ export class MQTTBase ::
96
70
  // alias: publish -- because 'pub' is shorter for semantic aliases above
97
71
  async pub(pkt, pub_opt) ::
98
72
  if undefined === pkt.payload ::
99
- if 'function' === typeof pub_opt ::
73
+ if _isfn(pub_opt) ::
74
+ // pub_opt as a function is fn_encode value
100
75
  pub_opt = {fn_encode: pub_opt}
101
76
 
102
- let {msg} = pkt
103
- switch typeof msg ::
104
- case 'function':
105
- pub_opt = {...pub_opt, fn_encode: msg}
106
- // flow into 'undefined' case
107
- case 'undefined':
108
- // return a single-value closure to publish packets
109
- return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)
77
+ let msg = pkt.msg, fn_encode = pub_opt?.fn_encode
78
+ if null == msg || _isfn(msg) ::
79
+ // when msg is a function, return closure using fn_encode
80
+ if msg :: pub_opt = {...pub_opt, fn_encode: msg}
81
+ // return a single-value closure to publish packets
82
+ return v => this.pub({...pkt, [pkt.arg || 'payload']: v}, pub_opt)
110
83
 
111
84
  // Encode payload from msg; fn_encode allows alternative to JSON.stringify
112
- let {fn_encode} = pub_opt || {}
113
85
  pkt.payload = fn_encode
114
86
  ? await fn_encode(msg)
115
87
  : JSON.stringify(msg)
@@ -121,31 +93,31 @@ export class MQTTBase ::
121
93
  pkt = pub_opt.xform(pkt) || pkt
122
94
 
123
95
  return this._send @ 'publish', pkt,
124
- pkt.qos ? pkt : void 0 // key
96
+ pkt.qos ? pkt : null // key
125
97
 
126
98
 
127
99
  // Internal API
128
100
 
129
- /* async _send(type, pkt) -- provided by _conn_ and transport */
101
+ /* async _send0(type, pkt) -- provided by conn and transport */
102
+ /* async _send(type, pkt) -- provided by conn and transport */
130
103
 
131
104
  _init_dispatch(opt) ::
132
105
  this.constructor?._once_()
133
106
  let target = @{} __proto__: opt.on_mqtt_type
134
107
  target.mqtt_publish ||=
135
108
  this._init_router?.(opt, this, target)
136
- return _mqtt_dispatch(this, target)
109
+ return _mqtt_dispatch(opt, target)
137
110
 
138
111
  static _aliases() ::
139
112
  return ' publish:pub sub:subscribe unsub:unsubscribe json_post:obj_post json_send:obj_send json_store:obj_store'
140
113
 
141
- static _once_(self=this) ::
142
- self._once_ = _=>0
143
- let p = self.prototype
114
+ static _once_(klass=this) ::
115
+ klass._once_ = _=>0
116
+ var alias, name, p = klass.prototype
144
117
  p.MQTTError = MQTTError
145
- for let alias of self._aliases().split(/\s+/) ::
146
- alias = alias.split(':')
147
- let fn = alias[1] && p[alias[1]]
148
- if fn :: p[alias[0]] = fn
118
+ for alias of klass._aliases().split(/\s+/) ::
119
+ [alias, name] = alias.split(':')
120
+ p[alias] = p[name]
149
121
 
150
122
 
151
123
  function _as_topics(pkt, ex, topic_prefix) ::