mqtt-plus 1.4.0 → 1.4.2

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 (73) hide show
  1. package/AGENTS.md +55 -44
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +4 -3
  4. package/doc/mqtt-plus-api.md +693 -680
  5. package/doc/mqtt-plus-architecture.d2 +139 -0
  6. package/doc/mqtt-plus-architecture.md +10 -0
  7. package/doc/mqtt-plus-architecture.svg +95 -0
  8. package/doc/mqtt-plus-broker-setup.md +9 -3
  9. package/doc/mqtt-plus-comm.md +73 -0
  10. package/doc/mqtt-plus-internals.md +3 -3
  11. package/dst-stage1/mqtt-plus-base.d.ts +3 -2
  12. package/dst-stage1/mqtt-plus-base.js +53 -22
  13. package/dst-stage1/mqtt-plus-event.d.ts +0 -2
  14. package/dst-stage1/mqtt-plus-event.js +6 -26
  15. package/dst-stage1/mqtt-plus-meta.d.ts +2 -2
  16. package/dst-stage1/mqtt-plus-meta.js +2 -2
  17. package/dst-stage1/mqtt-plus-msg.d.ts +2 -0
  18. package/dst-stage1/mqtt-plus-msg.js +17 -0
  19. package/dst-stage1/mqtt-plus-service.d.ts +0 -5
  20. package/dst-stage1/mqtt-plus-service.js +12 -48
  21. package/dst-stage1/mqtt-plus-sink.d.ts +0 -10
  22. package/dst-stage1/mqtt-plus-sink.js +25 -92
  23. package/dst-stage1/mqtt-plus-source.d.ts +0 -10
  24. package/dst-stage1/mqtt-plus-source.js +23 -88
  25. package/dst-stage1/mqtt-plus-subscription.d.ts +20 -0
  26. package/dst-stage1/mqtt-plus-subscription.js +126 -0
  27. package/dst-stage1/mqtt-plus-timer.d.ts +8 -0
  28. package/dst-stage1/mqtt-plus-timer.js +57 -0
  29. package/dst-stage1/mqtt-plus-topic.d.ts +20 -0
  30. package/dst-stage1/mqtt-plus-topic.js +112 -0
  31. package/dst-stage1/mqtt-plus-trace.js +2 -0
  32. package/dst-stage1/mqtt-plus-util.d.ts +0 -13
  33. package/dst-stage1/mqtt-plus-util.js +1 -77
  34. package/dst-stage1/mqtt-plus-version.d.ts +0 -1
  35. package/dst-stage1/mqtt-plus-version.js +0 -6
  36. package/dst-stage1/tsc.tsbuildinfo +1 -1
  37. package/dst-stage2/mqtt-plus.cjs.js +242 -292
  38. package/dst-stage2/mqtt-plus.esm.js +240 -290
  39. package/dst-stage2/mqtt-plus.umd.js +12 -12
  40. package/etc/knip.jsonc +1 -1
  41. package/etc/stx.conf +6 -4
  42. package/package.json +1 -1
  43. package/src/mqtt-plus-base.ts +56 -26
  44. package/src/mqtt-plus-event.ts +8 -24
  45. package/src/mqtt-plus-meta.ts +3 -3
  46. package/src/mqtt-plus-msg.ts +28 -0
  47. package/src/mqtt-plus-service.ts +12 -50
  48. package/src/mqtt-plus-sink.ts +32 -105
  49. package/src/mqtt-plus-source.ts +29 -99
  50. package/src/mqtt-plus-subscription.ts +141 -0
  51. package/src/mqtt-plus-timer.ts +61 -0
  52. package/src/mqtt-plus-trace.ts +4 -0
  53. package/src/mqtt-plus-util.ts +1 -81
  54. package/src/mqtt-plus-version.ts +0 -7
  55. package/tst/mqtt-plus-0-fixture.ts +2 -2
  56. package/tst/mqtt-plus-0-mosquitto.ts +5 -0
  57. package/tst/mqtt-plus-1-api.spec.ts +1 -1
  58. package/tst/mqtt-plus-2-event.spec.ts +0 -6
  59. package/tst/mqtt-plus-3-service.spec.ts +3 -7
  60. package/tst/mqtt-plus-4-sink.spec.ts +14 -9
  61. package/tst/mqtt-plus-5-source.spec.ts +11 -5
  62. package/tst/mqtt-plus-6-misc.spec.ts +23 -23
  63. package/tst/tsc.json +1 -1
  64. package/doc/mqtt-plus-communication.md +0 -68
  65. /package/doc/{mqtt-plus-1-event-emission.d2 → mqtt-plus-comm-event-emission.d2} +0 -0
  66. /package/doc/{mqtt-plus-1-event-emission.svg → mqtt-plus-comm-event-emission.svg} +0 -0
  67. /package/doc/{mqtt-plus-2-service-call.d2 → mqtt-plus-comm-service-call.d2} +0 -0
  68. /package/doc/{mqtt-plus-2-service-call.svg → mqtt-plus-comm-service-call.svg} +0 -0
  69. /package/doc/{mqtt-plus-3-sink-push.d2 → mqtt-plus-comm-sink-push.d2} +0 -0
  70. /package/doc/{mqtt-plus-3-sink-push.svg → mqtt-plus-comm-sink-push.svg} +0 -0
  71. /package/doc/{mqtt-plus-4-source-fetch.d2 → mqtt-plus-comm-source-fetch.d2} +0 -0
  72. /package/doc/{mqtt-plus-4-source-fetch.svg → mqtt-plus-comm-source-fetch.svg} +0 -0
  73. /package/{doc/theme.d2 → etc/d2.theme.d2} +0 -0
package/etc/knip.jsonc CHANGED
@@ -28,7 +28,7 @@
28
28
  "src/mqtt-plus.ts",
29
29
  "etc/eslint.mts",
30
30
  "tst/mqtt-plus-0-mosquitto.ts",
31
- "tst/mqtt-plus-0-fixtures.ts",
31
+ "tst/mqtt-plus-0-fixture.ts",
32
32
  "tst/mqtt-plus-1-api.spec.ts",
33
33
  "tst/mqtt-plus-2-event.spec.ts",
34
34
  "tst/mqtt-plus-3-service.spec.ts",
package/etc/stx.conf CHANGED
@@ -35,10 +35,11 @@ build : lint
35
35
 
36
36
  # documentation compilation
37
37
  build-doc
38
- node etc/d2.mts doc/theme.d2 doc/mqtt-plus-1-event-emission.d2 doc/mqtt-plus-1-event-emission.svg
39
- node etc/d2.mts doc/theme.d2 doc/mqtt-plus-2-service-call.d2 doc/mqtt-plus-2-service-call.svg
40
- node etc/d2.mts doc/theme.d2 doc/mqtt-plus-3-sink-push.d2 doc/mqtt-plus-3-sink-push.svg
41
- node etc/d2.mts doc/theme.d2 doc/mqtt-plus-4-source-fetch.d2 doc/mqtt-plus-4-source-fetch.svg
38
+ node etc/d2.mts etc/d2.theme.d2 doc/mqtt-plus-comm-event-emission.d2 doc/mqtt-plus-comm-event-emission.svg
39
+ node etc/d2.mts etc/d2.theme.d2 doc/mqtt-plus-comm-service-call.d2 doc/mqtt-plus-comm-service-call.svg
40
+ node etc/d2.mts etc/d2.theme.d2 doc/mqtt-plus-comm-sink-push.d2 doc/mqtt-plus-comm-sink-push.svg
41
+ node etc/d2.mts etc/d2.theme.d2 doc/mqtt-plus-comm-source-fetch.d2 doc/mqtt-plus-comm-source-fetch.svg
42
+ node etc/d2.mts etc/d2.theme.d2 doc/mqtt-plus-architecture.d2 doc/mqtt-plus-architecture.svg
42
43
 
43
44
  # development loop
44
45
  dev
@@ -50,6 +51,7 @@ dev
50
51
 
51
52
  # run test suite
52
53
  test
54
+ tsc --project tst/tsc.json --noEmit && \
53
55
  eslint --config etc/eslint.mts tst/mqtt-plus-0-fixture.ts tst/mqtt-plus-0-mosquitto.ts tst/*.spec.ts && \
54
56
  NODE_OPTIONS="--import=tsx --trace-warnings" mocha --require tst/mqtt-plus-0-fixture.ts tst/*.spec.ts
55
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mqtt-plus",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "MQTT Communication Patterns",
5
5
  "keywords": [ "mqtt",
6
6
  "event", "emit",
@@ -34,12 +34,17 @@ import { MqttClient,
34
34
  import type { APISchema } from "./mqtt-plus-api"
35
35
  import type { APIOptions } from "./mqtt-plus-options"
36
36
  import { TraceTrait } from "./mqtt-plus-trace"
37
+ import { ensureError } from "./mqtt-plus-error"
37
38
 
38
39
  /* MQTTp Base class with shared infrastructure */
39
40
  export class BaseTrait<T extends APISchema = APISchema> extends TraceTrait<T> {
40
41
  protected mqtt: MqttClient
41
42
  private _messageHandler: OnMessageCallback
42
43
 
44
+ /* central message callback registries */
45
+ protected onRequest = new Map<string, (message: any, topicName: string) => void>()
46
+ protected onResponse = new Map<string, (message: any, topicName: string) => void>()
47
+
43
48
  /* construct API class */
44
49
  constructor (
45
50
  mqtt: MqttClient | null,
@@ -92,7 +97,7 @@ export class BaseTrait<T extends APISchema = APISchema> extends TraceTrait<T> {
92
97
  }
93
98
 
94
99
  /* destroy API class */
95
- destroy () {
100
+ async destroy () {
96
101
  this.log("info", "un-hooking from MQTT client")
97
102
  this.mqtt.off("message", this._messageHandler)
98
103
  }
@@ -171,36 +176,61 @@ export class BaseTrait<T extends APISchema = APISchema> extends TraceTrait<T> {
171
176
  }
172
177
 
173
178
  /* handle incoming MQTT message */
174
- private _onMessage (topic: string, message: string | Uint8Array, packet: IPublishPacket): void {
175
- /* try to parse message as payload */
176
- if (typeof message === "string")
177
- this.log("info", `received from MQTT topic "${topic}" (type: string, length: ${message.length} chars)`)
179
+ private _onMessage (topic: string, data: string | Uint8Array, packet: IPublishPacket): void {
180
+ /* parse MQTT topic */
181
+ const topicMatch = this.options.topicMatch(topic)
182
+ if (topicMatch === null)
183
+ return
184
+
185
+ /* parse MQTT data into payload object */
186
+ if (typeof data === "string")
187
+ this.log("info", `received from MQTT topic "${topic}" (type: string, length: ${data.length} chars)`)
178
188
  else
179
- this.log("info", `received from MQTT topic "${topic}" (type: buffer, length: ${message.byteLength} bytes)`)
180
- let parsed: any
189
+ this.log("info", `received from MQTT topic "${topic}" (type: buffer, length: ${data.byteLength} bytes)`)
190
+ let payload: any
181
191
  try {
182
- const payload = this.codec.decode(message)
183
- parsed = this.msg.parse(payload)
192
+ payload = this.codec.decode(data)
184
193
  }
185
- catch (_err: unknown) {
186
- const err = _err instanceof Error
187
- ? new Error(`failed to parse message: ${_err.message}`, { cause: _err })
188
- : new Error("failed to parse message")
189
- this.error(err)
194
+ catch (err: unknown) {
195
+ this.error(ensureError(err, "failed to parse message into object"))
190
196
  return
191
197
  }
192
- this.log("debug", `received from MQTT topic "${topic}"`, { message: parsed })
193
198
 
194
- /* dispatch to trait handlers */
195
- this._dispatchMessage(topic, parsed).catch((err: Error) => {
196
- this.error(err, `dispatching message from MQTT topic "${topic}" failed`)
197
- })
199
+ /* parse payload object into typed MQTT+ message */
200
+ let message: any
201
+ try {
202
+ message = this.msg.parse(payload)
203
+ }
204
+ catch (err: unknown) {
205
+ this.error(ensureError(err, "failed to parse object into typed message object"))
206
+ return
207
+ }
208
+ this.log("debug", `received from MQTT topic "${topic}"`, { message })
209
+
210
+ /* dispatch MQTT+ message */
211
+ if (this.msg.isRequest(message)) {
212
+ /* dispatch request message */
213
+ const handler = this.onRequest.get(`${topicMatch.operation}:${message.name}`)
214
+ if (handler !== undefined) {
215
+ try {
216
+ handler(message, topicMatch.name)
217
+ }
218
+ catch (err: unknown) {
219
+ this.error(ensureError(err, `dispatching request message from MQTT topic "${topic}" failed`))
220
+ }
221
+ }
222
+ }
223
+ else if (this.msg.isResponse(message)) {
224
+ /* dispatch response message */
225
+ const handler = this.onResponse.get(`${topicMatch.operation}:${message.id}`)
226
+ if (handler !== undefined) {
227
+ try {
228
+ handler(message, topicMatch.name)
229
+ }
230
+ catch (err: unknown) {
231
+ this.error(ensureError(err, `dispatching response message from MQTT topic "${topic}" failed`))
232
+ }
233
+ }
234
+ }
198
235
  }
199
-
200
- /* dispatch parsed message to appropriate handler
201
- (base implementation, to be overridden in sub-traits) */
202
- protected async _dispatchMessage (
203
- _topic: string,
204
- _parsed: any
205
- ): Promise<void> {}
206
236
  }
@@ -37,9 +37,6 @@ import { run, Spool, ensureError } from "./mqtt-plus-error"
37
37
 
38
38
  /* Event Emission Trait */
39
39
  export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
40
- /* internal state */
41
- private events = new Map<string, (request: EventEmission, topicName: string) => void>()
42
-
43
40
  /* register an event handler */
44
41
  async event<K extends EventKeys<T> & string> (
45
42
  name: K,
@@ -88,7 +85,7 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
88
85
  const spool = new Spool()
89
86
 
90
87
  /* sanity check situation */
91
- if (this.events.has(name))
88
+ if (this.onRequest.has(`event-emission:${name}`))
92
89
  throw new Error(`event: event "${name}" already registered`)
93
90
 
94
91
  /* generate the corresponding MQTT topics for broadcast and direct use */
@@ -97,7 +94,7 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
97
94
  const topicD = this.options.topicMake(name, "event-emission", this.options.id)
98
95
 
99
96
  /* remember the registration */
100
- this.events.set(name, (request: EventEmission, topicName: string) => {
97
+ this.onRequest.set(`event-emission:${name}`, (request: EventEmission, topicName: string) => {
101
98
  /* determine event information */
102
99
  const senderId = request.sender
103
100
  const params = request.params ?? []
@@ -123,7 +120,7 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
123
120
  this.error(error, `handler for event "${name}" failed`)
124
121
  })
125
122
  })
126
- spool.roll(() => { this.events.delete(name) })
123
+ spool.roll(() => { this.onRequest.delete(`event-emission:${name}`) })
127
124
 
128
125
  /* subscribe to MQTT topics */
129
126
  await run(`subscribe to MQTT topic "${topicB}"`, spool, () =>
@@ -136,7 +133,7 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
136
133
  /* provide a registration for subsequent destruction */
137
134
  return {
138
135
  destroy: async (): Promise<void> => {
139
- if (!this.events.has(name))
136
+ if (!this.onRequest.has(`event-emission:${name}`))
140
137
  throw new Error(`destroy: event "${name}" not registered`)
141
138
  await spool.unroll(false)?.catch((err: Error) => {
142
139
  this.error(err, `destroy: failed to cleanup: ${err.message}`)
@@ -185,7 +182,7 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
185
182
  let params: Parameters<T[K]>
186
183
  let receiver: string | undefined
187
184
  let options: IClientPublishOptions = {}
188
- let meta: Record<string, any> = {}
185
+ let meta: Record<string, any> | undefined
189
186
  let dry: boolean | undefined
190
187
  if (typeof eventOrConfig === "object" && eventOrConfig !== null) {
191
188
  /* object-based API */
@@ -193,7 +190,7 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
193
190
  params = eventOrConfig.params
194
191
  receiver = eventOrConfig.receiver
195
192
  options = eventOrConfig.options ?? {}
196
- meta = eventOrConfig.meta ?? {}
193
+ meta = eventOrConfig.meta
197
194
  dry = eventOrConfig.dry
198
195
  }
199
196
  else {
@@ -208,7 +205,8 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
208
205
  /* generate encoded message */
209
206
  const auth = this.authenticate()
210
207
  const metaStore = this.metaStore(meta)
211
- const request = this.msg.makeEventEmission(requestId, event, params, this.options.id, receiver, auth, metaStore)
208
+ const request = this.msg.makeEventEmission(requestId, event, params,
209
+ this.options.id, receiver, auth, metaStore)
212
210
  const message = this.codec.encode(request)
213
211
 
214
212
  /* generate corresponding MQTT topic */
@@ -225,18 +223,4 @@ export class EventTrait<T extends APISchema = APISchema> extends AuthTrait<T> {
225
223
  })
226
224
  }
227
225
 
228
- /* dispatch message (Event pattern handling) */
229
- protected override async _dispatchMessage (topic: string, message: any) {
230
- await super._dispatchMessage(topic, message)
231
- const topicMatch = this.options.topicMatch(topic)
232
-
233
- /* on server-side handle event emission request */
234
- if (topicMatch !== null
235
- && topicMatch.operation === "event-emission"
236
- && message instanceof EventEmission) {
237
- const handler = this.events.get(message.name)
238
- if (handler !== undefined)
239
- handler(message, topicMatch.name)
240
- }
241
- }
242
226
  }
@@ -23,11 +23,11 @@
23
23
  */
24
24
 
25
25
  /* internal requirements */
26
- import type { APISchema } from "./mqtt-plus-api"
27
- import { BaseTrait } from "./mqtt-plus-base"
26
+ import type { APISchema } from "./mqtt-plus-api"
27
+ import { TimerTrait } from "./mqtt-plus-timer"
28
28
 
29
29
  /* Meta trait with meta information management */
30
- export class MetaTrait<T extends APISchema = APISchema> extends BaseTrait<T> {
30
+ export class MetaTrait<T extends APISchema = APISchema> extends TimerTrait<T> {
31
31
  /* internal state */
32
32
  private _meta: Map<string, any> = new Map()
33
33
 
@@ -509,6 +509,34 @@ class Msg {
509
509
  else
510
510
  throw new Error("invalid object: not of any known type")
511
511
  }
512
+
513
+ /* guard for request messages */
514
+ isRequest (msg: any): msg is (
515
+ EventEmission | ServiceCallRequest | SourceFetchRequest | SinkPushRequest
516
+ ) {
517
+ return (
518
+ msg instanceof EventEmission
519
+ || msg instanceof ServiceCallRequest
520
+ || msg instanceof SourceFetchRequest
521
+ || msg instanceof SinkPushRequest
522
+ )
523
+ }
524
+
525
+ /* guard for response messages */
526
+ isResponse (msg: any): msg is (
527
+ ServiceCallResponse | SinkPushResponse | SinkPushChunk | SinkPushCredit |
528
+ SourceFetchResponse | SourceFetchChunk | SourceFetchCredit
529
+ ) {
530
+ return (
531
+ msg instanceof ServiceCallResponse
532
+ || msg instanceof SinkPushResponse
533
+ || msg instanceof SinkPushChunk
534
+ || msg instanceof SinkPushCredit
535
+ || msg instanceof SourceFetchResponse
536
+ || msg instanceof SourceFetchChunk
537
+ || msg instanceof SourceFetchCredit
538
+ )
539
+ }
512
540
  }
513
541
 
514
542
  /* message trait */
@@ -28,7 +28,6 @@ import type { IClientPublishOptions,
28
28
  import { nanoid } from "nanoid"
29
29
 
30
30
  /* internal requirements */
31
- import { RefCountedSubscription } from "./mqtt-plus-util"
32
31
  import { run, Spool, ensureError } from "./mqtt-plus-error"
33
32
  import { ServiceCallRequest,
34
33
  ServiceCallResponse } from "./mqtt-plus-msg"
@@ -40,19 +39,6 @@ import type { AuthOption } from "./mqtt-plus-auth"
40
39
 
41
40
  /* Service Call Trait */
42
41
  export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T> {
43
- /* internal state */
44
- private services = new Map<string, (request: ServiceCallRequest, topicName: string) => void>()
45
- private callCallbacks = new Map<string, (response: ServiceCallResponse) => void>()
46
- private callSubscriptions = new RefCountedSubscription(
47
- (topic, options) => this._subscribeTopic(topic, options),
48
- (topic) => this._unsubscribeTopic(topic)
49
- )
50
-
51
- /* destroy service trait */
52
- override destroy () {
53
- super.destroy()
54
- this.callSubscriptions.flush()
55
- }
56
42
 
57
43
  /* register a service call handler */
58
44
  async service<K extends ServiceKeys<T> & string> (
@@ -102,8 +88,8 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
102
88
  const spool = new Spool()
103
89
 
104
90
  /* sanity check situation */
105
- if (this.services.has(name))
106
- throw new Error(`register: service "${name}" already registered`)
91
+ if (this.onRequest.has(`service-call-request:${name}`))
92
+ throw new Error(`service: service "${name}" already registered`)
107
93
 
108
94
  /* generate the corresponding MQTT topics for broadcast and direct use */
109
95
  const topicS = `$share/${share}/${name}`
@@ -111,7 +97,7 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
111
97
  const topicD = this.options.topicMake(name, "service-call-request", this.options.id)
112
98
 
113
99
  /* remember the registration */
114
- this.services.set(name, (request: ServiceCallRequest, topicName: string) => {
100
+ this.onRequest.set(`service-call-request:${name}`, (request: ServiceCallRequest, topicName: string) => {
115
101
  /* determine request information */
116
102
  const requestId = request.id
117
103
  const senderId = request.sender
@@ -154,7 +140,7 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
154
140
  this.error(err, `handler for service "${name}" failed`)
155
141
  })
156
142
  })
157
- spool.roll(() => { this.services.delete(name) })
143
+ spool.roll(() => { this.onRequest.delete(`service-call-request:${name}`) })
158
144
 
159
145
  /* subscribe to MQTT topics */
160
146
  await run(`subscribe to MQTT topic "${topicB}"`, spool, () =>
@@ -167,8 +153,8 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
167
153
  /* provide a registration for subsequent destruction */
168
154
  return {
169
155
  destroy: async (): Promise<void> => {
170
- if (!this.services.has(name))
171
- throw new Error(`destroy: service "${name}" no longer registered`)
156
+ if (!this.onRequest.has(`service-call-request:${name}`))
157
+ throw new Error(`destroy: service "${name}" not registered`)
172
158
  await spool.unroll(false)?.catch((err: Error) => {
173
159
  this.error(err, `destroy: failed to cleanup: ${err.message}`)
174
160
  })
@@ -205,14 +191,14 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
205
191
  let params: Parameters<T[K]>
206
192
  let receiver: string | undefined
207
193
  let options: IClientPublishOptions = {}
208
- let meta: Record<string, any> = {}
194
+ let meta: Record<string, any> | undefined
209
195
  if (typeof nameOrConfig === "object" && nameOrConfig !== null) {
210
196
  /* object-based API */
211
197
  name = nameOrConfig.name
212
198
  params = nameOrConfig.params
213
199
  receiver = nameOrConfig.receiver
214
200
  options = nameOrConfig.options ?? {}
215
- meta = nameOrConfig.meta ?? {}
201
+ meta = nameOrConfig.meta
216
202
  }
217
203
  else {
218
204
  /* positional API */
@@ -229,8 +215,8 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
229
215
  /* subscribe to MQTT response topic */
230
216
  const responseTopic = this.options.topicMake(name, "service-call-response", this.options.id)
231
217
  await run(`subscribe to MQTT topic "${responseTopic}"`, spool, () =>
232
- this.callSubscriptions.subscribe(responseTopic, { qos: options.qos ?? 2 }))
233
- spool.roll(() => this.callSubscriptions.unsubscribe(responseTopic))
218
+ this.subscriptions.subscribe(responseTopic, { qos: options.qos ?? 2 }))
219
+ spool.roll(() => this.subscriptions.unsubscribe(responseTopic))
234
220
 
235
221
  /* create promise for MQTT response handling */
236
222
  const promise: Promise<ReturnType<T[K]>> = new Promise((resolve, reject) => {
@@ -245,14 +231,14 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
245
231
  timer = null
246
232
  }
247
233
  })
248
- this.callCallbacks.set(requestId, async (response: ServiceCallResponse) => {
234
+ this.onResponse.set(`service-call-response:${requestId}`, async (response: ServiceCallResponse) => {
249
235
  await spool.unroll()
250
236
  if (response.error !== undefined)
251
237
  reject(new Error(response.error))
252
238
  else
253
239
  resolve(response.result)
254
240
  })
255
- spool.roll(() => { this.callCallbacks.delete(requestId) })
241
+ spool.roll(() => { this.onResponse.delete(`service-call-response:${requestId}`) })
256
242
  })
257
243
 
258
244
  /* generate encoded message */
@@ -272,28 +258,4 @@ export class ServiceTrait<T extends APISchema = APISchema> extends EventTrait<T>
272
258
  return promise
273
259
  }
274
260
 
275
- /* dispatch message (Service pattern handling) */
276
- protected override async _dispatchMessage (topic: string, message: any) {
277
- await super._dispatchMessage(topic, message)
278
- const topicMatch = this.options.topicMatch(topic)
279
-
280
- /* on server-side handle service call request */
281
- if (topicMatch !== null
282
- && topicMatch.operation === "service-call-request"
283
- && message instanceof ServiceCallRequest) {
284
- const handler = this.services.get(message.name)
285
- if (handler !== undefined)
286
- handler(message, topicMatch.name)
287
- }
288
-
289
- /* on client-side handle service call response */
290
- else if (topicMatch !== null
291
- && topicMatch.operation === "service-call-response"
292
- && topicMatch.peerId === this.options.id
293
- && message instanceof ServiceCallResponse) {
294
- const handler = this.callCallbacks.get(message.id)
295
- if (handler !== undefined)
296
- handler(message)
297
- }
298
- }
299
261
  }