u8-mqtt 0.3.2-0 → 0.4.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 (76) hide show
  1. package/README.md +5 -5
  2. package/cjs/basic-v4.cjs +1200 -0
  3. package/cjs/basic-v4.cjs.map +1 -0
  4. package/cjs/basic-v5.cjs +1464 -0
  5. package/cjs/basic-v5.cjs.map +1 -0
  6. package/cjs/index.cjs +312 -269
  7. package/cjs/index.cjs.map +1 -1
  8. package/cjs/v4.cjs +307 -264
  9. package/cjs/v4.cjs.map +1 -1
  10. package/cjs/v5.cjs +309 -265
  11. package/cjs/v5.cjs.map +1 -1
  12. package/code/_cmdid_dispatch.jsy +1 -3
  13. package/code/base.jsy +64 -89
  14. package/code/basic-v4.js +18 -0
  15. package/code/basic-v5.js +26 -0
  16. package/code/index.js +2 -1
  17. package/code/{_router.jsy → router_path.jsy} +36 -12
  18. package/code/v4.js +3 -1
  19. package/code/v5.js +5 -2
  20. package/code/with_topic_router.jsy +42 -0
  21. package/esm/deno/basic-v4.js +1188 -0
  22. package/esm/deno/basic-v4.js.map +1 -0
  23. package/esm/deno/basic-v5.js +1450 -0
  24. package/esm/deno/basic-v5.js.map +1 -0
  25. package/esm/deno/index.js +310 -266
  26. package/esm/deno/index.js.map +1 -1
  27. package/esm/deno/v4.js +307 -264
  28. package/esm/deno/v4.js.map +1 -1
  29. package/esm/deno/v5.js +309 -265
  30. package/esm/deno/v5.js.map +1 -1
  31. package/esm/node/basic-v4.js +1191 -0
  32. package/esm/node/basic-v4.js.map +1 -0
  33. package/esm/node/basic-v4.mjs +1191 -0
  34. package/esm/node/basic-v4.mjs.map +1 -0
  35. package/esm/node/basic-v5.js +1453 -0
  36. package/esm/node/basic-v5.js.map +1 -0
  37. package/esm/node/basic-v5.mjs +1453 -0
  38. package/esm/node/basic-v5.mjs.map +1 -0
  39. package/esm/node/index.js +310 -266
  40. package/esm/node/index.js.map +1 -1
  41. package/esm/node/index.mjs +310 -266
  42. package/esm/node/index.mjs.map +1 -1
  43. package/esm/node/v4.js +307 -264
  44. package/esm/node/v4.js.map +1 -1
  45. package/esm/node/v4.mjs +307 -264
  46. package/esm/node/v4.mjs.map +1 -1
  47. package/esm/node/v5.js +309 -265
  48. package/esm/node/v5.js.map +1 -1
  49. package/esm/node/v5.mjs +309 -265
  50. package/esm/node/v5.mjs.map +1 -1
  51. package/esm/web/basic-v4.js +1188 -0
  52. package/esm/web/basic-v4.js.map +1 -0
  53. package/esm/web/basic-v4.min.js +1 -0
  54. package/esm/web/basic-v4.min.js.br +0 -0
  55. package/esm/web/basic-v4.min.js.gz +0 -0
  56. package/esm/web/basic-v5.js +1450 -0
  57. package/esm/web/basic-v5.js.map +1 -0
  58. package/esm/web/basic-v5.min.js +1 -0
  59. package/esm/web/basic-v5.min.js.br +0 -0
  60. package/esm/web/basic-v5.min.js.gz +0 -0
  61. package/esm/web/index.js +309 -265
  62. package/esm/web/index.js.map +1 -1
  63. package/esm/web/index.min.js +1 -1
  64. package/esm/web/index.min.js.br +0 -0
  65. package/esm/web/index.min.js.gz +0 -0
  66. package/esm/web/v4.js +307 -264
  67. package/esm/web/v4.js.map +1 -1
  68. package/esm/web/v4.min.js +1 -1
  69. package/esm/web/v4.min.js.br +0 -0
  70. package/esm/web/v4.min.js.gz +0 -0
  71. package/esm/web/v5.js +308 -264
  72. package/esm/web/v5.js.map +1 -1
  73. package/esm/web/v5.min.js +1 -1
  74. package/esm/web/v5.min.js.br +0 -0
  75. package/esm/web/v5.min.js.gz +0 -0
  76. package/package.json +5 -5
package/code/base.jsy CHANGED
@@ -1,5 +1,4 @@
1
1
  import {_mqtt_conn} from './_conn.jsy'
2
- import {_mqtt_topic_router} from './_router.jsy'
3
2
  import {_mqtt_dispatch} from './_dispatch.jsy'
4
3
 
5
4
  export class MQTTError extends Error ::
@@ -60,53 +59,15 @@ export class MQTTBase ::
60
59
 
61
60
 
62
61
  // alias: sub
63
- subscribe(pkt, ex) ::
64
- pkt = _as_topics(pkt, ex)
62
+ subscribe(pkt, ex, topic_prefix) ::
63
+ pkt = _as_topics(pkt, ex, topic_prefix)
65
64
  return this._send('subscribe', pkt, pkt)
66
- _sub_chain(topic, ex) ::
67
- let res = this.subscribe @ [[ topic ]], ex
68
- let subs = this.subs || @ this.subs = new Map()
69
- subs.set @ (res.topic = topic), (subs.last = res)
70
- return this // fluent api -- return this and track side effects
71
65
 
72
66
  // alias: unsub
73
- unsubscribe(pkt, ex) ::
74
- pkt = _as_topics(pkt, ex)
67
+ unsubscribe(pkt, ex, topic_prefix) ::
68
+ pkt = _as_topics(pkt, ex, topic_prefix)
75
69
  return this._send('unsubscribe', pkt, pkt)
76
70
 
77
- get on_topic() :: return this.router.add
78
-
79
- // alias: sub_topic
80
- subscribe_topic(topic_route, ...args) ::
81
- this.router.add @ topic_route, true, args.pop() // handler
82
- let topic = this.topic_for(topic_route)
83
- return this._sub_chain @ topic, args.pop() // ex
84
-
85
- // alias: unsub_topic
86
- unsubscribe_topic(topic_route) ::
87
- this.router.remove @ topic_route, true
88
- let topic = this.topic_for(topic_route)
89
- return this.unsubscribe @ [[ topic ]]
90
-
91
- // alias: shared_sub
92
- shared_subscribe(group, topic_route, ...args) ::
93
- this.router.add @ topic_route, true, args.pop() // handler
94
- let topic = this.topic_for(topic_route)
95
- if null != group ::
96
- topic = `$share/${group}/${topic}`
97
- return this._sub_chain @ topic, args.pop() // ex
98
-
99
- // alias: shared_unsub
100
- shared_unsubscribe(group, topic_route) ::
101
- this.router.remove @ topic_route, true
102
- let topic = this.topic_for(topic_route)
103
- if null != group ::
104
- topic = `$share/${group}/${topic}`
105
- return this.unsubscribe @ [[ topic ]]
106
-
107
- topic_for(topic_route) ::
108
- return topic_route.replace(/[:*].*$/, '#')
109
-
110
71
 
111
72
  // alias: pub
112
73
  publish(pkt, pub_opt) :: return _pub(this, pkt, pub_opt)
@@ -156,53 +117,67 @@ export class MQTTBase ::
156
117
 
157
118
  /* async _send(type, pkt) -- provided by _conn_ and transport */
158
119
 
159
- _init_router(opt) ::
160
- return this.router = _mqtt_topic_router(this)
161
-
162
120
  _init_dispatch(opt) ::
163
- let tgt = @{}
164
- __proto__: opt.on_mqtt_type || {}
165
- router: this._init_router(opt, this)
166
-
167
- tgt.mqtt_publish ||= tgt.router.invoke
168
- return _mqtt_dispatch(this, tgt)
169
-
170
-
171
- ::
172
- let p = MQTTBase.prototype
173
- Object.assign @ p, @{}
174
- MQTTError
175
- pub: p.publish
176
- sub: p.subscribe
177
- unsub: p.unsubscribe
178
- sub_topic: p.subscribe_topic
179
- unsub_topic: p.unsubscribe_topic
180
- shared_sub: p.shared_subscribe
181
- shared_unsub: p.shared_unsubscribe
182
-
183
- /*
184
- p.on_mqtt_type = {
185
- mqtt_auth(pkt, ctx) ::
186
- mqtt_connect(pkt, ctx) ::
187
- mqtt_connack(pkt, ctx) ::
188
- mqtt_disconnect(pkt, ctx) ::
189
-
190
- mqtt_publish(pkt, ctx)
191
- mqtt_subscribe(pkt, ctx) ::
192
- mqtt_unsubscribe(pkt, ctx) ::
193
-
194
- mqtt_pingreq(pkt, ctx) ::
195
- mqtt_pingresp(pkt, ctx) ::
196
- }
197
- */
198
-
199
-
200
- function _as_topics(pkt, ex) ::
201
- if 'string' === typeof pkt ::
202
- return {topics:[pkt], ... ex}
203
- if pkt[Symbol.iterator] ::
204
- return {topics:[... pkt], ... ex}
205
- return ex ? {...pkt, ...ex} : pkt
121
+ this.constructor?._once_()
122
+ let target = @{} __proto__: opt.on_mqtt_type
123
+ target.mqtt_publish ||=
124
+ this._init_router?.(opt, this, target)
125
+ return _mqtt_dispatch(this, target)
126
+
127
+ static _aliases() ::
128
+ return ' pub:publish sub:subscribe unsub:unsubscribe '
129
+
130
+ static _once_(self=this) ::
131
+ self._once_ = _=>0
132
+ self.MQTTError = MQTTError
133
+ let p = self.prototype
134
+ for let alias of self._aliases().split(/\s+/) ::
135
+ alias = alias.split(':')
136
+ let fn = alias[1] && p[alias[1]]
137
+ if fn :: p[alias[0]] = fn
138
+
139
+
140
+ /*
141
+ on_mqtt_type = {
142
+ mqtt_auth(pkt, ctx) ::
143
+ mqtt_connect(pkt, ctx) ::
144
+ mqtt_connack(pkt, ctx) ::
145
+ mqtt_disconnect(pkt, ctx) ::
146
+
147
+ mqtt_publish(pkt, ctx)
148
+ mqtt_subscribe(pkt, ctx) ::
149
+ mqtt_unsubscribe(pkt, ctx) ::
150
+
151
+ mqtt_pingreq(pkt, ctx) ::
152
+ mqtt_pingresp(pkt, ctx) ::
153
+ }
154
+ */
155
+
156
+
157
+ const _prefix_topics = (topic_prefix, iterable) =>
158
+ Array.from @ iterable, value => @
159
+ value.trim // string
160
+ ? _prefix_topics(topic_prefix, value)
161
+ : topic_prefix + value
162
+
163
+ function _as_topics(pkt, ex, topic_prefix) ::
164
+ if ex?.trim :: // string
165
+ topic_prefix = ex
166
+ ex = null
167
+
168
+ pkt = @
169
+ pkt.trim // string
170
+ ? {topics:[pkt], ... ex}
171
+ : pkt[Symbol.iterator]
172
+ ? {topics:[... pkt], ... ex}
173
+ : ex ? {...pkt, ...ex}
174
+ : pkt
175
+
176
+ if topic_prefix ::
177
+ // particularly useful with shared queues, e.g.
178
+ // topic_prefix = '$share/some-queue-name/'
179
+ pkt.topics = _prefix_topics(topic_prefix, pkt.topics)
180
+ return pkt
206
181
 
207
182
 
208
183
  async function _pub(self, pkt, pub_opt) ::
@@ -0,0 +1,18 @@
1
+ import mqtt_opts_v4 from 'u8-mqtt-packet/esm/codec_v4_client.js'
2
+ import MQTTCore from './core.jsy'
3
+ export * from './version.js'
4
+
5
+ const MQTTClient_v4 = /* #__PURE__ */
6
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v4)
7
+
8
+ const mqtt_v4 = opt =>
9
+ new MQTTClient_v4(opt)
10
+
11
+ export {
12
+ MQTTClient_v4,
13
+ MQTTClient_v4 as MQTTClient,
14
+
15
+ mqtt_v4,
16
+ mqtt_v4 as mqtt,
17
+ mqtt_v4 as default,
18
+ }
@@ -0,0 +1,26 @@
1
+ import mqtt_opts_v5 from 'u8-mqtt-packet/esm/codec_v5_client.js'
2
+ import MQTTCore from './core.jsy'
3
+ export * from './version.js'
4
+
5
+ const MQTTClient_v4 = /* #__PURE__ */
6
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v5)
7
+
8
+ const MQTTClient_v5 = /* #__PURE__ */
9
+ MQTTCore.mqtt_ctx(5, mqtt_opts_v5)
10
+
11
+ const mqtt_v4 = opt =>
12
+ new MQTTClient_v4(opt)
13
+
14
+ const mqtt_v5 = opt =>
15
+ new MQTTClient_v5(opt)
16
+
17
+ export {
18
+ MQTTClient_v4,
19
+ MQTTClient_v5,
20
+ MQTTClient_v5 as MQTTClient,
21
+
22
+ mqtt_v4,
23
+ mqtt_v5,
24
+ mqtt_v5 as mqtt,
25
+ mqtt_v5 as default,
26
+ }
package/code/index.js CHANGED
@@ -7,7 +7,8 @@ export {
7
7
  export * from './core.jsy'
8
8
  export * from './base.jsy'
9
9
  export * from './_conn.jsy'
10
- export * from './_router.jsy'
11
10
  export * from './_dispatch.jsy'
12
11
  export * from './_cmdid_dispatch.jsy'
12
+ export * from './with_topic_router.jsy'
13
+ export * from './router_path.jsy'
13
14
 
@@ -2,15 +2,40 @@
2
2
  // [regexparam]: https://github.com/lukeed/regexparam
3
3
 
4
4
  import {parse as _rxp_parse} from 'regexparam'
5
+ import {with_topic_router} from './with_topic_router.jsy'
6
+
7
+ export const with_topic_path_router = /* #__PURE__ */
8
+ with_topic_router(mqtt_topic_path_router)
9
+
10
+
11
+ const mqtt_topic = topic_route =>
12
+ topic_route
13
+ .replace @ /[*].*$/, '#'
14
+ .replace @ /:\w+\??/g, '+'
15
+
16
+ /* From the [MQTT v5 Spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Topic_Names_and)
17
+ 4.7.1.2 Multi-level wildcard -- (‘#’ U+0023)
18
+ ... MUST be specified either on its own or following a topic level separator.
19
+ In either case it MUST be the last character specified in the Topic Filter
20
+
21
+ 4.7.1.3 Single-level wildcard -- (‘+’ U+002B)
22
+ ...it MUST occupy an entire level of the filter.
23
+ */
24
+
25
+ export const as_topic_path = (topic_route, id) => @
26
+ id=1,
27
+ topic_route
28
+ .replace @ /#$/, '*' // replace MQTT '#' multi-level wildcard at end
29
+ .replace @ /\+/g, () => `:$${id++}` // replace MQTT '+' single-level wildcards
5
30
 
6
31
  function _ignore(pkt, params, ctx) :: ctx.done = true
7
32
 
8
- export function _mqtt_topic_router() ::
33
+ function mqtt_topic_path_router() ::
9
34
  let pri_lsts = [[],[]], rm = Symbol()
10
- let find = topic => _mqtt_routes_iter(pri_lsts, topic)
11
-
12
- return @{} find,
35
+ let find = topic => _routes_iter(pri_lsts, topic)
13
36
 
37
+ // return duck-type compatible with AbstractTopicRouter in ./with_topic_router
38
+ return @{} find, mqtt_topic,
14
39
  add(topic_route, ...args) ::
15
40
  let fn = args.pop()
16
41
  let priority = args.pop()
@@ -20,8 +45,7 @@ export function _mqtt_topic_router() ::
20
45
  fn = _ignore
21
46
  else throw new TypeError()
22
47
 
23
- let rte = _rxp_parse @
24
- topic_route.replace(/[+#]$/, '*')
48
+ let rte = _rxp_parse @ as_topic_path @ topic_route
25
49
 
26
50
  rte.key = topic_route
27
51
  rte.tgt = fn
@@ -30,7 +54,7 @@ export function _mqtt_topic_router() ::
30
54
 
31
55
  remove(topic_route, priority) ::
32
56
  let lst = pri_lsts[priority ? 0 : 1]
33
- return _mqtt_route_remove([lst], topic_route)
57
+ return _route_remove([lst], topic_route)
34
58
 
35
59
  clear(priority) ::
36
60
  pri_lsts[priority ? 0 : 1] = []
@@ -45,7 +69,7 @@ export function _mqtt_topic_router() ::
45
69
  let res = await fn(pkt, params, ctx)
46
70
 
47
71
  if rm === res ::
48
- _mqtt_route_remove(pri_lsts, fn)
72
+ _route_remove(pri_lsts, fn)
49
73
 
50
74
  if ctx.done ::
51
75
  break
@@ -56,15 +80,15 @@ export function _mqtt_topic_router() ::
56
80
  await ctx.mqtt._send('puback', {pkt_id})
57
81
 
58
82
 
59
- export function * _mqtt_routes_iter(all_route_lists, topic) ::
83
+ function * _routes_iter(all_route_lists, topic) ::
60
84
  for let route_list of all_route_lists ::
61
85
  for let route of route_list ::
62
- let res = _mqtt_route_match_one(topic, route)
86
+ let res = _route_match_one(topic, route)
63
87
  if undefined !== res ::
64
88
  yield res
65
89
 
66
90
 
67
- export function _mqtt_route_match_one(topic, {keys, pattern, tgt}) ::
91
+ function _route_match_one(topic, {keys, pattern, tgt}) ::
68
92
  let match = '/' !== topic[0]
69
93
  ? pattern.exec('/'+topic)
70
94
  : pattern.exec(topic)
@@ -92,7 +116,7 @@ export function _mqtt_route_match_one(topic, {keys, pattern, tgt}) ::
92
116
  return [tgt, params]
93
117
 
94
118
 
95
- export function _mqtt_route_remove(all_route_lists, query) ::
119
+ function _route_remove(all_route_lists, query) ::
96
120
  let match = route => route===query || route.tgt===query || route.key===query
97
121
  for let lst of all_route_lists ::
98
122
  let i = lst.findIndex(match)
package/code/v4.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import mqtt_opts_v4 from 'u8-mqtt-packet/esm/codec_v4_client.js'
2
+ import {with_topic_path_router} from './router_path.jsy'
2
3
  import MQTTCore from './core.jsy'
3
4
  export * from './version.js'
4
5
 
5
6
  const MQTTClient_v4 = /* #__PURE__ */
6
- MQTTCore.mqtt_ctx(4, mqtt_opts_v4)
7
+ with_topic_path_router(
8
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v4) )
7
9
 
8
10
  const mqtt_v4 = opt =>
9
11
  new MQTTClient_v4(opt)
package/code/v5.js CHANGED
@@ -1,12 +1,15 @@
1
1
  import mqtt_opts_v5 from 'u8-mqtt-packet/esm/codec_v5_client.js'
2
+ import {with_topic_path_router} from './router_path.jsy'
2
3
  import MQTTCore from './core.jsy'
3
4
  export * from './version.js'
4
5
 
5
6
  const MQTTClient_v4 = /* #__PURE__ */
6
- MQTTCore.mqtt_ctx(4, mqtt_opts_v5)
7
+ with_topic_path_router(
8
+ MQTTCore.mqtt_ctx(4, mqtt_opts_v5) )
7
9
 
8
10
  const MQTTClient_v5 = /* #__PURE__ */
9
- MQTTCore.mqtt_ctx(5, mqtt_opts_v5)
11
+ with_topic_path_router(
12
+ MQTTCore.mqtt_ctx(5, mqtt_opts_v5) )
10
13
 
11
14
  const mqtt_v4 = opt =>
12
15
  new MQTTClient_v4(opt)
@@ -0,0 +1,42 @@
1
+ /*
2
+ class AbstractTopicRouter ::
3
+ async invoke(pkt, ctx) ::
4
+ add(topic_route, ...args) ::
5
+ remove(topic_route, priority) ::
6
+ clear(priority) ::
7
+ find(topic) :: // optional
8
+ mqtt_topic(topic_route)
9
+ */
10
+
11
+ export const with_topic_router = mqtt_topic_router =>
12
+ MQTTKlass => class extends MQTTKlass ::
13
+ static _aliases() ::
14
+ return super._aliases() +
15
+ ' sub_topic:subscribe_topic unsub_topic:unsubscribe_topic'
16
+
17
+ _init_router(opt, client, target) ::
18
+ let router = this.router = target.router =
19
+ mqtt_topic_router(opt, this)
20
+ return router?.invoke
21
+ get on_topic() :: return this.router.add
22
+
23
+ _sub_chain(topic, ex, topic_prefix) ::
24
+ let res = this.subscribe @ [[ topic ]], ex, topic_prefix
25
+ let subs = this.subs || @ this.subs = new Map()
26
+ subs.set @ (res.topic = topic), (subs.last = res)
27
+ return this // fluent api -- return this and track side effects
28
+
29
+ // alias: sub_topic
30
+ subscribe_topic(topic_route, ...args) ::
31
+ let router = this.router
32
+ router.add @ topic_route, true, args.pop() // handler
33
+ let topic = router.mqtt_topic(topic_route)
34
+ return this._sub_chain @ topic, ...args // ex, topic_prefix
35
+
36
+ // alias: unsub_topic
37
+ unsubscribe_topic(topic_route, ...args) ::
38
+ let router = this.router
39
+ router.remove @ topic_route, true
40
+ let topic = router.mqtt_topic(topic_route)
41
+ return this.unsubscribe @ [[ topic ]], ...args // topic_prefix
42
+