u8-mqtt 0.3.2-0 → 0.4.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 (76) hide show
  1. package/README.md +5 -5
  2. package/cjs/basic-v4.cjs +1205 -0
  3. package/cjs/basic-v4.cjs.map +1 -0
  4. package/cjs/basic-v5.cjs +1469 -0
  5. package/cjs/basic-v5.cjs.map +1 -0
  6. package/cjs/index.cjs +308 -267
  7. package/cjs/index.cjs.map +1 -1
  8. package/cjs/v4.cjs +303 -262
  9. package/cjs/v4.cjs.map +1 -1
  10. package/cjs/v5.cjs +305 -263
  11. package/cjs/v5.cjs.map +1 -1
  12. package/code/_cmdid_dispatch.jsy +1 -3
  13. package/code/base.jsy +64 -84
  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} +30 -12
  18. package/code/v4.js +3 -1
  19. package/code/v5.js +5 -2
  20. package/code/with_topic_router.jsy +41 -0
  21. package/esm/deno/basic-v4.js +1193 -0
  22. package/esm/deno/basic-v4.js.map +1 -0
  23. package/esm/deno/basic-v5.js +1455 -0
  24. package/esm/deno/basic-v5.js.map +1 -0
  25. package/esm/deno/index.js +306 -264
  26. package/esm/deno/index.js.map +1 -1
  27. package/esm/deno/v4.js +303 -262
  28. package/esm/deno/v4.js.map +1 -1
  29. package/esm/deno/v5.js +305 -263
  30. package/esm/deno/v5.js.map +1 -1
  31. package/esm/node/basic-v4.js +1196 -0
  32. package/esm/node/basic-v4.js.map +1 -0
  33. package/esm/node/basic-v4.mjs +1196 -0
  34. package/esm/node/basic-v4.mjs.map +1 -0
  35. package/esm/node/basic-v5.js +1458 -0
  36. package/esm/node/basic-v5.js.map +1 -0
  37. package/esm/node/basic-v5.mjs +1458 -0
  38. package/esm/node/basic-v5.mjs.map +1 -0
  39. package/esm/node/index.js +306 -264
  40. package/esm/node/index.js.map +1 -1
  41. package/esm/node/index.mjs +306 -264
  42. package/esm/node/index.mjs.map +1 -1
  43. package/esm/node/v4.js +303 -262
  44. package/esm/node/v4.js.map +1 -1
  45. package/esm/node/v4.mjs +303 -262
  46. package/esm/node/v4.mjs.map +1 -1
  47. package/esm/node/v5.js +305 -263
  48. package/esm/node/v5.js.map +1 -1
  49. package/esm/node/v5.mjs +305 -263
  50. package/esm/node/v5.mjs.map +1 -1
  51. package/esm/web/basic-v4.js +1193 -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 +1455 -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 +305 -263
  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 +303 -262
  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 +304 -262
  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,72 @@ 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) ::
121
+ this.constructor?._once_()
122
+ let router = this.router =
123
+ this._init_router?.(opt, this)
124
+
163
125
  let tgt = @{}
164
126
  __proto__: opt.on_mqtt_type || {}
165
- router: this._init_router(opt, this)
127
+ router
166
128
 
167
- tgt.mqtt_publish ||= tgt.router.invoke
129
+ tgt.mqtt_publish ||= router?.invoke
168
130
  return _mqtt_dispatch(this, tgt)
169
131
 
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
132
+ static _aliases() ::
133
+ return ' pub:publish sub:subscribe unsub:unsubscribe '
134
+
135
+ static _once_(self=this) ::
136
+ self._once_ = _=>0
137
+ self.MQTTError = MQTTError
138
+ let p = self.prototype
139
+ for let alias of self._aliases().split(/\s+/) ::
140
+ alias = alias.split(':')
141
+ let fn = alias[1] && p[alias[1]]
142
+ if fn :: p[alias[0]] = fn
143
+
144
+
145
+ /*
146
+ on_mqtt_type = {
147
+ mqtt_auth(pkt, ctx) ::
148
+ mqtt_connect(pkt, ctx) ::
149
+ mqtt_connack(pkt, ctx) ::
150
+ mqtt_disconnect(pkt, ctx) ::
151
+
152
+ mqtt_publish(pkt, ctx)
153
+ mqtt_subscribe(pkt, ctx) ::
154
+ mqtt_unsubscribe(pkt, ctx) ::
155
+
156
+ mqtt_pingreq(pkt, ctx) ::
157
+ mqtt_pingresp(pkt, ctx) ::
158
+ }
159
+ */
160
+
161
+
162
+ const _prefix_topics = (topic_prefix, iterable) =>
163
+ Array.from @ iterable, value => @
164
+ value.trim // string
165
+ ? _prefix_topics(topic_prefix, value)
166
+ : topic_prefix + value
167
+
168
+ function _as_topics(pkt, ex, topic_prefix) ::
169
+ if ex?.trim :: // string
170
+ topic_prefix = ex
171
+ ex = null
172
+
173
+ pkt = @
174
+ pkt.trim // string
175
+ ? {topics:[pkt], ... ex}
176
+ : pkt[Symbol.iterator]
177
+ ? {topics:[... pkt], ... ex}
178
+ : ex ? {...pkt, ...ex}
179
+ : pkt
180
+
181
+ if topic_prefix ::
182
+ // particularly useful with shared queues, e.g.
183
+ // topic_prefix = '$share/some-queue-name/'
184
+ pkt.topics = _prefix_topics(topic_prefix, pkt.topics)
185
+ return pkt
206
186
 
207
187
 
208
188
  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,34 @@
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
+ export const as_topic_path = topic_route => @
17
+ topic_route
18
+ .replace(/#$/, '*') // replace MQTT # wildcard at end
19
+ .split(/([^\/]*[+][^\/]*)/) // split on MQTT + match tokens
20
+ .reduce @\ sz, v, idx => sz + @
21
+ idx & 1 // even entires are body, odd are MQTT + tokens
22
+ ? `:$${1 + idx>>1}` // replace with `:$#` sequential ids, using ? for partial entries
23
+ : v // pass through body
5
24
 
6
25
  function _ignore(pkt, params, ctx) :: ctx.done = true
7
26
 
8
- export function _mqtt_topic_router() ::
27
+ function mqtt_topic_path_router() ::
9
28
  let pri_lsts = [[],[]], rm = Symbol()
10
- let find = topic => _mqtt_routes_iter(pri_lsts, topic)
11
-
12
- return @{} find,
29
+ let find = topic => _routes_iter(pri_lsts, topic)
13
30
 
31
+ // return duck-type compatible with AbstractTopicRouter in ./with_topic_router
32
+ return @{} find, mqtt_topic,
14
33
  add(topic_route, ...args) ::
15
34
  let fn = args.pop()
16
35
  let priority = args.pop()
@@ -20,8 +39,7 @@ export function _mqtt_topic_router() ::
20
39
  fn = _ignore
21
40
  else throw new TypeError()
22
41
 
23
- let rte = _rxp_parse @
24
- topic_route.replace(/[+#]$/, '*')
42
+ let rte = _rxp_parse @ as_topic_path @ topic_route
25
43
 
26
44
  rte.key = topic_route
27
45
  rte.tgt = fn
@@ -30,7 +48,7 @@ export function _mqtt_topic_router() ::
30
48
 
31
49
  remove(topic_route, priority) ::
32
50
  let lst = pri_lsts[priority ? 0 : 1]
33
- return _mqtt_route_remove([lst], topic_route)
51
+ return _route_remove([lst], topic_route)
34
52
 
35
53
  clear(priority) ::
36
54
  pri_lsts[priority ? 0 : 1] = []
@@ -45,7 +63,7 @@ export function _mqtt_topic_router() ::
45
63
  let res = await fn(pkt, params, ctx)
46
64
 
47
65
  if rm === res ::
48
- _mqtt_route_remove(pri_lsts, fn)
66
+ _route_remove(pri_lsts, fn)
49
67
 
50
68
  if ctx.done ::
51
69
  break
@@ -56,15 +74,15 @@ export function _mqtt_topic_router() ::
56
74
  await ctx.mqtt._send('puback', {pkt_id})
57
75
 
58
76
 
59
- export function * _mqtt_routes_iter(all_route_lists, topic) ::
77
+ function * _routes_iter(all_route_lists, topic) ::
60
78
  for let route_list of all_route_lists ::
61
79
  for let route of route_list ::
62
- let res = _mqtt_route_match_one(topic, route)
80
+ let res = _route_match_one(topic, route)
63
81
  if undefined !== res ::
64
82
  yield res
65
83
 
66
84
 
67
- export function _mqtt_route_match_one(topic, {keys, pattern, tgt}) ::
85
+ function _route_match_one(topic, {keys, pattern, tgt}) ::
68
86
  let match = '/' !== topic[0]
69
87
  ? pattern.exec('/'+topic)
70
88
  : pattern.exec(topic)
@@ -92,7 +110,7 @@ export function _mqtt_route_match_one(topic, {keys, pattern, tgt}) ::
92
110
  return [tgt, params]
93
111
 
94
112
 
95
- export function _mqtt_route_remove(all_route_lists, query) ::
113
+ function _route_remove(all_route_lists, query) ::
96
114
  let match = route => route===query || route.tgt===query || route.key===query
97
115
  for let lst of all_route_lists ::
98
116
  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,41 @@
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) ::
18
+ return mqtt_topic_router(opt, this)
19
+
20
+ get on_topic() :: return this.router.add
21
+
22
+ _sub_chain(topic, ex, topic_prefix) ::
23
+ let res = this.subscribe @ [[ topic ]], ex, topic_prefix
24
+ let subs = this.subs || @ this.subs = new Map()
25
+ subs.set @ (res.topic = topic), (subs.last = res)
26
+ return this // fluent api -- return this and track side effects
27
+
28
+ // alias: sub_topic
29
+ subscribe_topic(topic_route, ...args) ::
30
+ let router = this.router
31
+ router.add @ topic_route, true, args.pop() // handler
32
+ let topic = router.mqtt_topic(topic_route)
33
+ return this._sub_chain @ topic, ...args // ex, topic_prefix
34
+
35
+ // alias: unsub_topic
36
+ unsubscribe_topic(topic_route, ...args) ::
37
+ let router = this.router
38
+ router.remove @ topic_route, true
39
+ let topic = router.mqtt_topic(topic_route)
40
+ return this.unsubscribe @ [[ topic ]], ...args // topic_prefix
41
+