thor-io.vnext 2.0.5-beta.3 → 3.1.0-beta.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 (185) hide show
  1. package/.gitattributes +17 -17
  2. package/build/index.d.ts +24 -0
  3. package/build/index.js +47 -0
  4. package/build/src/Connection/ClientInfo.d.ts +27 -0
  5. package/{src/Client → build/src/Connection}/ClientInfo.js +7 -0
  6. package/build/src/Connection/Connection.d.ts +117 -0
  7. package/build/src/Connection/Connection.js +202 -0
  8. package/build/src/Connection/IClientInfo.d.ts +20 -0
  9. package/build/src/Controller/ControllerBase.d.ts +134 -0
  10. package/build/src/Controller/ControllerBase.js +543 -0
  11. package/build/src/Controller/Subscription.d.ts +27 -0
  12. package/build/src/Controller/Subscription.js +22 -0
  13. package/build/src/Controllers/BrokerController/Broker.js +145 -0
  14. package/build/src/Controllers/BrokerController/BrokerController.d.ts +61 -0
  15. package/build/src/Controllers/BrokerController/BrokerController.js +115 -0
  16. package/{src/Controllers/BrokerController/Broker.js → build/src/Controllers/BrokerController/BrokerrController.js} +74 -85
  17. package/build/src/Controllers/BrokerController/Models/PeerConnection.d.ts +7 -0
  18. package/build/src/Controllers/BrokerController/Models/PeerConnection.js +14 -0
  19. package/build/src/Controllers/BrokerController/Models/Signal.js +11 -0
  20. package/build/src/Decorators/CanInvoke.d.ts +10 -0
  21. package/build/src/Decorators/CanInvoke.js +22 -0
  22. package/build/src/Decorators/CanSet.d.ts +10 -0
  23. package/build/src/Decorators/CanSet.js +20 -0
  24. package/build/src/Decorators/ControllerProperties.d.ts +10 -0
  25. package/build/src/Decorators/ControllerProperties.js +20 -0
  26. package/{src/Controllers/BrokerController/Models/InstantMessage.js → build/src/Interfaces/IInterceptor.js} +2 -5
  27. package/build/src/Interfaces/ITransport.d.ts +94 -0
  28. package/build/src/Interfaces/ITransportMessage.d.ts +41 -0
  29. package/build/src/Messages/BufferMessage.d.ts +38 -0
  30. package/{src → build/src}/Messages/BufferMessage.js +32 -2
  31. package/build/src/Messages/ErrorMessage.d.ts +29 -0
  32. package/build/src/Messages/ErrorMessage.js +22 -0
  33. package/build/src/Messages/PipeMessage.d.ts +46 -0
  34. package/build/src/Messages/PipeMessage.js +41 -0
  35. package/build/src/Messages/TextMessage.d.ts +88 -0
  36. package/build/src/Messages/TextMessage.js +94 -0
  37. package/build/src/Messages/WebSocketMessage.d.ts +34 -0
  38. package/build/src/Messages/WebSocketMessage.js +41 -0
  39. package/build/src/Plugin.js +32 -0
  40. package/build/src/Server/Plugin.d.ts +37 -0
  41. package/build/src/Server/Plugin.js +32 -0
  42. package/build/src/Server/ThorIOServer.d.ts +68 -0
  43. package/build/src/Server/ThorIOServer.js +131 -0
  44. package/build/src/Subscription.js +22 -0
  45. package/build/src/ThorIO.js +142 -0
  46. package/build/src/ThorIOServer.d.ts +64 -0
  47. package/build/src/ThorIOServer.js +131 -0
  48. package/build/src/Transports/BufferMessageTransport.d.ts +78 -0
  49. package/build/src/Transports/BufferMessageTransport.js +85 -0
  50. package/build/src/Transports/PipeMessageTransport.d.ts +79 -0
  51. package/build/src/Transports/PipeMessageTransport.js +90 -0
  52. package/build/src/Transports/WebSocketMessageTransport.d.ts +87 -0
  53. package/build/src/Transports/WebSocketMessageTransport.js +93 -0
  54. package/build/src/Utils/BufferUtils.d.ts +32 -0
  55. package/build/src/Utils/BufferUtils.js +57 -0
  56. package/build/src/Utils/StringUtils.d.ts +15 -0
  57. package/build/src/Utils/StringUtils.js +31 -0
  58. package/build/src/test.js +5 -0
  59. package/docs/.nojekyll +1 -0
  60. package/docs/assets/hierarchy.js +1 -0
  61. package/docs/assets/highlight.css +43 -0
  62. package/docs/assets/icons.js +18 -0
  63. package/docs/assets/icons.svg +1 -0
  64. package/docs/assets/main.js +60 -0
  65. package/docs/assets/navigation.js +1 -0
  66. package/docs/assets/search.js +1 -0
  67. package/docs/assets/style.css +1610 -0
  68. package/docs/classes/BrokerController.html +164 -0
  69. package/docs/classes/BufferMessage.html +11 -0
  70. package/docs/classes/BufferMessageTransport.html +31 -0
  71. package/docs/classes/BufferUtils.html +16 -0
  72. package/docs/classes/ClientInfo.html +11 -0
  73. package/docs/classes/Connection.html +42 -0
  74. package/docs/classes/ControllerBase.html +144 -0
  75. package/docs/classes/ErrorMessage.html +13 -0
  76. package/docs/classes/PeerConnection.html +4 -0
  77. package/docs/classes/PipeMessage.html +17 -0
  78. package/docs/classes/PipeMessageTransport.html +33 -0
  79. package/docs/classes/Plugin.html +13 -0
  80. package/docs/classes/Signal.html +5 -0
  81. package/docs/classes/StringUtils.html +9 -0
  82. package/docs/classes/Subscription.html +11 -0
  83. package/docs/classes/TextMessage.html +37 -0
  84. package/docs/classes/ThorIOServer.html +25 -0
  85. package/docs/classes/WebSocketMessage.html +18 -0
  86. package/docs/classes/WebSocketMessageTransport.html +35 -0
  87. package/docs/functions/CanInvoke.html +5 -0
  88. package/docs/functions/CanSet.html +5 -0
  89. package/docs/functions/ControllerProperties.html +5 -0
  90. package/docs/hierarchy.html +1 -0
  91. package/docs/index.html +24 -0
  92. package/docs/interfaces/ITransport.html +46 -0
  93. package/docs/interfaces/ITransportMessage.html +21 -0
  94. package/docs/modules.html +1 -0
  95. package/index.ts +32 -37
  96. package/licence +21 -21
  97. package/package.json +48 -50
  98. package/readme.md +32 -1
  99. package/src/{Client → Connection}/ClientInfo.ts +34 -43
  100. package/src/Connection/Connection.ts +229 -0
  101. package/src/Connection/IClientInfo.ts +22 -0
  102. package/src/Controller/ControllerBase.ts +561 -457
  103. package/src/{Subscription.ts → Controller/Subscription.ts} +32 -34
  104. package/src/Controllers/BrokerController/BrokerController.ts +121 -0
  105. package/src/Controllers/BrokerController/Models/PeerConnection.ts +12 -34
  106. package/src/Controllers/BrokerController/Models/Signal.ts +11 -43
  107. package/src/Decorators/CanInvoke.ts +21 -13
  108. package/src/Decorators/CanSet.ts +19 -12
  109. package/src/Decorators/ControllerProperties.ts +19 -16
  110. package/src/Interfaces/ITransport.ts +107 -23
  111. package/src/Interfaces/ITransportMessage.ts +45 -41
  112. package/src/Messages/BufferMessage.ts +70 -69
  113. package/src/Messages/ErrorMessage.ts +34 -6
  114. package/src/Messages/PipeMessage.ts +56 -62
  115. package/src/Messages/TextMessage.ts +139 -93
  116. package/src/Messages/WebSocketMessage.ts +39 -41
  117. package/src/Server/Plugin.ts +56 -0
  118. package/src/Server/ThorIOServer.ts +121 -0
  119. package/src/ThorIOServer.ts +117 -0
  120. package/src/Transports/BufferMessageTransport.ts +109 -100
  121. package/src/Transports/PipeMessageTransport.ts +112 -104
  122. package/src/Transports/WebSocketMessageTransport.ts +122 -110
  123. package/src/Utils/BufferUtils.ts +55 -61
  124. package/src/Utils/StringUtils.ts +28 -17
  125. package/tsconfig.json +109 -19
  126. package/typedoc.json +6 -0
  127. package/index.d.ts +0 -24
  128. package/index.js +0 -46
  129. package/src/Client/ClientInfo.d.ts +0 -6
  130. package/src/Connection.d.ts +0 -24
  131. package/src/Connection.js +0 -121
  132. package/src/Connection.ts +0 -263
  133. package/src/Controller/ControllerBase.d.ts +0 -43
  134. package/src/Controller/ControllerBase.js +0 -331
  135. package/src/Controllers/BrokerController/Broker.d.ts +0 -21
  136. package/src/Controllers/BrokerController/Broker.ts +0 -153
  137. package/src/Controllers/BrokerController/Models/InstantMessage.d.ts +0 -3
  138. package/src/Controllers/BrokerController/Models/InstantMessage.ts +0 -15
  139. package/src/Controllers/BrokerController/Models/PeerConnection.d.ts +0 -5
  140. package/src/Controllers/BrokerController/Models/PeerConnection.js +0 -9
  141. package/src/Controllers/BrokerController/Models/Signal.js +0 -10
  142. package/src/Decorators/CanInvoke.d.ts +0 -2
  143. package/src/Decorators/CanInvoke.js +0 -9
  144. package/src/Decorators/CanSet.d.ts +0 -1
  145. package/src/Decorators/CanSet.js +0 -8
  146. package/src/Decorators/ControllerProperties.d.ts +0 -1
  147. package/src/Decorators/ControllerProperties.js +0 -10
  148. package/src/Interfaces/IInterceptor.d.ts +0 -2
  149. package/src/Interfaces/IInterceptor.ts +0 -2
  150. package/src/Interfaces/ITransport.d.ts +0 -18
  151. package/src/Interfaces/ITransportMessage.d.ts +0 -8
  152. package/src/Listener.d.ts +0 -5
  153. package/src/Listener.js +0 -9
  154. package/src/Listener.ts +0 -34
  155. package/src/Messages/BufferMessage.d.ts +0 -10
  156. package/src/Messages/ErrorMessage.d.ts +0 -4
  157. package/src/Messages/ErrorMessage.js +0 -8
  158. package/src/Messages/PipeMessage.d.ts +0 -12
  159. package/src/Messages/PipeMessage.js +0 -20
  160. package/src/Messages/TextMessage.d.ts +0 -15
  161. package/src/Messages/TextMessage.js +0 -50
  162. package/src/Messages/WebSocketMessage.d.ts +0 -10
  163. package/src/Messages/WebSocketMessage.js +0 -15
  164. package/src/Plugin.d.ts +0 -6
  165. package/src/Plugin.js +0 -11
  166. package/src/Plugin.ts +0 -37
  167. package/src/Subscription.d.ts +0 -5
  168. package/src/Subscription.js +0 -9
  169. package/src/ThorIO.d.ts +0 -18
  170. package/src/ThorIO.js +0 -65
  171. package/src/ThorIO.ts +0 -148
  172. package/src/Transports/BufferMessageTransport.d.ts +0 -21
  173. package/src/Transports/BufferMessageTransport.js +0 -31
  174. package/src/Transports/PipeMessageTransport.d.ts +0 -20
  175. package/src/Transports/PipeMessageTransport.js +0 -33
  176. package/src/Transports/WebSocketMessageTransport.d.ts +0 -20
  177. package/src/Transports/WebSocketMessageTransport.js +0 -31
  178. package/src/Utils/BufferUtils.d.ts +0 -5
  179. package/src/Utils/BufferUtils.js +0 -29
  180. package/src/Utils/StringUtils.d.ts +0 -4
  181. package/src/Utils/StringUtils.js +0 -13
  182. /package/{src/Interfaces/IInterceptor.js → build/src/Connection/IClientInfo.js} +0 -0
  183. /package/{src → build/src}/Controllers/BrokerController/Models/Signal.d.ts +0 -0
  184. /package/{src → build/src}/Interfaces/ITransport.js +0 -0
  185. /package/{src → build/src}/Interfaces/ITransportMessage.js +0 -0
@@ -1,457 +1,561 @@
1
- import { CanInvoke } from '../Decorators/CanInvoke';
2
- import { CanSet } from '../Decorators/CanSet';
3
- import { TextMessage } from '../Messages/TextMessage';
4
- import { Connection } from '../Connection';
5
- import { Subscription } from '../Subscription';
6
- import { ErrorMessage } from '../Messages/ErrorMessage';
7
- import { URLSearchParams } from 'url';
8
-
9
- export interface ControllerBase {
10
- new(connection: Connection): ControllerBase;
11
- }
12
- export class ControllerBase {
13
- /**
14
- *
15
- *
16
- * @type {string}
17
- * @memberOf Controller
18
- */
19
- @CanSet(false)
20
- public alias: string;
21
- /**
22
- *
23
- *
24
- * @type {Array<Subscription>}
25
- * @memberOf Controller
26
- */
27
- @CanSet(false)
28
- public subscriptions: Array<Subscription>;
29
- /**
30
- *
31
- *
32
- * @type {Connection}
33
- * @memberOf Controller
34
- */
35
- @CanSet(false)
36
- public connection: Connection;
37
- /**
38
- *
39
- *
40
- * @private
41
- * @type {Date}
42
- * @memberOf Controller
43
- */
44
- @CanSet(false)
45
- private lastPong: Date;
46
- /**
47
- *
48
- *
49
- * @private
50
- * @type {Date}
51
- * @memberOf Controller
52
- */
53
- @CanSet(false)
54
- private lastPing: Date;
55
- /**
56
- *
57
- *
58
- * @private
59
- * @type {number}
60
- * @memberOf Controller
61
- */
62
- @CanSet(false)
63
- private heartbeatInterval: number;
64
- private interval: NodeJS.Timeout;
65
- /**
66
- * Creates an instance of Controller.
67
- *
68
- * @param {Connection} connection
69
- *
70
- * @memberOf Controller
71
- */
72
- constructor(connection: Connection) {
73
- this.connection = connection;
74
- this.subscriptions = [];
75
- this.alias = Reflect.getMetadata("alias", this.constructor);
76
- this.heartbeatInterval = Reflect.getMetadata("heartbeatInterval", this.constructor);
77
- if (this.heartbeatInterval >= 1000)
78
- this.enableHeartbeat();
79
- }
80
- /**
81
- *
82
- *
83
- * @private
84
- *
85
- * @memberOf Controller
86
- */
87
- @CanInvoke(false)
88
- private enableHeartbeat() {
89
- this.connection.transport.addEventListener("pong", () => {
90
- this.lastPong = new Date();
91
- });
92
- this.interval = setInterval(() => {
93
- this.lastPing = new Date();
94
- if (this.connection.transport.readyState === 1)
95
- this.connection.transport.ping();
96
- }, this.heartbeatInterval);
97
- }
98
- @CanInvoke(false)
99
- public disbaleHeartbeat(): void {
100
- clearInterval(this.interval);
101
- }
102
- /**
103
- *
104
- *
105
- * @param {string} method
106
- * @returns {boolean}
107
- *
108
- * @memberOf Controller
109
- */
110
- @CanInvoke(false)
111
- public canInvokeMethod(method: string): boolean {
112
- return Reflect.getMetadata("canInvokeOrSet", this, method);
113
- }
114
- /**
115
- *
116
- *
117
- * @template T
118
- * @param {string} alias
119
- * @param {(item: any) => boolean} predicate
120
- * @returns {Array<any>}
121
- *
122
- * @memberOf Controller
123
- */
124
- @CanInvoke(false)
125
- findOn<T>(alias: string, predicate: (item: any) => boolean): Array<ControllerBase> {
126
- /**
127
- *
128
- *
129
- * @param {Connection} p
130
- * @returns
131
- */
132
- let connections = this.getConnections(alias).map((p: Connection) => {
133
- return p.getController(alias);
134
- });
135
- return connections.filter(predicate);
136
- }
137
- /**
138
- *
139
- *
140
- * @param {string} [alias]
141
- * @returns {Array<Connection>}
142
- *
143
- * @memberOf Controller
144
- */
145
- @CanInvoke(false)
146
- getConnections(alias?: string): Array<Connection> {
147
- if (!alias) {
148
- return Array.from(this.connection.connections.values());
149
- }
150
- else {
151
- return Array.from(this.connection.connections.values()).map((conn: Connection) => {
152
- if (conn.hasController(this.alias))
153
- return conn;
154
- });
155
- }
156
- }
157
- /**
158
- *
159
- *
160
- *
161
- * @memberOf Controller
162
- */
163
- @CanInvoke(false)
164
- onopen() { }
165
- /**
166
- *
167
- *
168
- *
169
- * @memberOf Controller
170
- */
171
- @CanInvoke(false)
172
- onclose() { }
173
- /**
174
- *
175
- *
176
- * @template T
177
- * @template U
178
- * @param {T[]} array
179
- * @param {(item: any) => boolean} predicate
180
- * @param {(item: T) => U} [selector=(x: T) => <U><any>x]
181
- * @returns {U[]}
182
- *
183
- * @memberOf Controller
184
- */
185
- @CanInvoke(false)
186
- find<T, U>(array: T[], predicate: (item: any) => boolean, selector: (item: T) => U = (x: T) => <U><any>x): U[] {
187
- return array.filter(predicate).map(selector);
188
- }
189
- /**
190
- *
191
- *
192
- * @param {*} error
193
- *
194
- * @memberOf Controller
195
- */
196
- @CanInvoke(false)
197
- invokeError(ex: any) {
198
- let errorMessage = new ErrorMessage(ex.message);
199
- this.invoke(errorMessage, "___error", this.alias);
200
- }
201
- /**
202
- *
203
- *
204
- * @param {*} data
205
- * @param {string} topic
206
- * @param {string} [controller]
207
- * @param {*} [buffer]
208
- * @returns {ControllerBase}
209
- *
210
- * @memberOf Controller
211
- */
212
- @CanInvoke(false)
213
- invokeToOthers(data: any, topic: string, controller?: string, buffer?: any) {
214
- this.getConnections().filter((pre: Connection) => {
215
- return pre.id !== this.connection.id;
216
- })
217
- .forEach((connection: Connection) => {
218
- connection.getController(controller || this.alias).invoke(data, topic, controller || this.alias, buffer);
219
- });
220
-
221
- }
222
- /*
223
- *
224
- *
225
- * @param {*} data
226
- * @param {string} topic
227
- * @param {string} [controller]
228
- * @param {*} [buffer]
229
- * @returns {ControllerBase}
230
- *
231
- * @memberOf Controller
232
- */
233
- @CanInvoke(false)
234
- invokeToAll(data: any, topic: string, controller?: string, buffer?: any) {
235
- this.getConnections().forEach((connection: Connection) => {
236
- connection.getController(controller || this.alias).invoke(data, topic, controller || this.alias, buffer);
237
- });
238
-
239
- }
240
- /**
241
- *
242
- *
243
- * @param {(item: ControllerBase) => boolean} predicate
244
- * @param {*} data
245
- * @param {string} topic
246
- * @param {string} [controller]
247
- * @param {*} [buffer]
248
- * @returns {ControllerBase}
249
- *
250
- * @memberOf Controller
251
- */
252
- @CanInvoke(false)
253
- invokeTo(predicate: (item: ControllerBase) => boolean, data: any, topic: string, controller?: string, buffer?: any) {
254
- let connections = this.findOn<this>(controller || this.alias, predicate);
255
- connections.forEach((ctrl: ControllerBase) => {
256
- ctrl.invoke(data, topic, controller || this.alias, buffer);
257
- });
258
- }
259
- /**
260
- *
261
- *
262
- * @param {*} data
263
- * @param {string} topic
264
- * @param {string} [controller]
265
- * @param {*} [buffer]
266
- * @returns {ControllerBase}
267
- *
268
- * @memberOf Controller
269
- */
270
- @CanInvoke(false)
271
- invoke(data: any, topic: string, controller?: string, buffer?: any): ControllerBase {
272
- let msg = new TextMessage(topic, data, controller || this.alias, buffer);
273
- if (this.connection.transport)
274
- this.connection.transport.send(!msg.isBinary ? msg.toString() : msg.toArrayBuffer());
275
- return this;
276
- }
277
- /**
278
- *
279
- *
280
- * @param {*} data
281
- * @param {string} topic
282
- * @param {string} [controller]
283
- * @returns {ControllerBase}
284
- *
285
- * @memberOf Controller
286
- */
287
- @CanInvoke(false)
288
- publish(data: any, topic: string, controller?: string): ControllerBase {
289
- if (!this.hasSubscription(topic))
290
- return;
291
- return this.invoke(data, topic, controller || this.alias);
292
- }
293
- /**
294
- *
295
- *
296
- * @param {*} data
297
- * @param {string} topic
298
- * @param {string} [controller]
299
- * @returns {ControllerBase}
300
- *
301
- * @memberOf Controller
302
- */
303
- @CanInvoke(false)
304
- publishToAll(data: any, topic: string, controller?: string) {
305
- let msg = new TextMessage(topic, data, this.alias);
306
- this.getConnections().forEach((connection: Connection) => {
307
- let ctrl = connection.getController(controller || this.alias);
308
- if (ctrl.getSubscription(topic)) {
309
- connection.transport.send(msg.toString());
310
- }
311
- });
312
-
313
- }
314
- /**
315
- *
316
- *
317
- * @param {string} topic
318
- * @returns {boolean}
319
- *
320
- * @memberOf Controller
321
- */
322
- @CanInvoke(false)
323
- hasSubscription(topic: string): boolean {
324
- /**
325
- *
326
- *
327
- * @param {Subscription} pre
328
- * @returns
329
- */
330
- let p = this.subscriptions.filter((pre: Subscription) => {
331
- return pre.topic === topic;
332
- });
333
- return !(p.length === 0);
334
- }
335
- /**
336
- *
337
- *
338
- * @param {string} topic
339
- * @returns {Subscription}
340
- *
341
- * @memberOf Controller
342
- */
343
- @CanInvoke(false)
344
- addSubscription(topic: string): Subscription {
345
- let subscription = new Subscription(topic, this.alias);
346
- return this.___subscribe(subscription, topic, this.alias);
347
- }
348
- /**
349
- *
350
- *
351
- * @param {string} topic
352
- * @returns
353
- *
354
- * @memberOf Controller
355
- */
356
- @CanInvoke(false)
357
- removeSubscription(topic: string) {
358
- return this.___unsubscribe(this.getSubscription(topic));
359
- }
360
- /**
361
- *
362
- *
363
- * @param {string} topic
364
- * @returns {Subscription}
365
- *
366
- * @memberOf Controller
367
- */
368
- @CanInvoke(false)
369
- getSubscription(topic: string): Subscription {
370
- /**
371
- *
372
- *
373
- * @param {Subscription} pre
374
- * @returns
375
- */
376
- let subscription = this.subscriptions.find((pre: Subscription) => {
377
- return pre.topic === topic;
378
- });
379
- return subscription;
380
- }
381
- /**
382
- *
383
- *
384
- *
385
- * @memberOf Controller
386
- */
387
- @CanInvoke(true)
388
- ___connect() {
389
- // todo: remove this method
390
- }
391
- /**
392
- *
393
- *
394
- *
395
- * @memberOf Controller
396
- */
397
- @CanInvoke(true)
398
- ___close() {
399
- this.connection.removeController(this.alias);
400
- this.invoke({}, " ___close", this.alias);
401
- }
402
- /**
403
- *
404
- *
405
- * @param {Subscription} subscription
406
- * @param {string} topic
407
- * @param {string} controller
408
- * @returns {Subscription}
409
- *
410
- * @memberOf Controller
411
- */
412
- @CanInvoke(true)
413
- ___subscribe(subscription: Subscription, topic: string, controller: string): Subscription {
414
- if (this.hasSubscription(subscription.topic)) {
415
- return;
416
- }
417
- this.subscriptions.push(subscription);
418
- return subscription;
419
- }
420
-
421
- /**
422
- *
423
- *
424
- * @param {Subscription} subscription
425
- * @returns {boolean}
426
- *
427
- * @memberOf Controller
428
- */
429
- @CanInvoke(true)
430
- ___unsubscribe(subscription: Subscription): boolean {
431
- let index = this.subscriptions.indexOf(this.getSubscription(subscription.topic));
432
- if (index >= 0) {
433
- let result = this.subscriptions.splice(index, 1);
434
- return true;
435
- }
436
- else
437
- return false;
438
- }
439
- get queryParameters(): URLSearchParams {
440
- return new URLSearchParams(this.request.url.replace("/?",""));
441
- }
442
- get headers(): Map<string, string> {
443
- let headers = new Map<string, any>();
444
- try {
445
- Object.keys(this.connection.transport.request["headers"]).forEach(k => {
446
- headers.set(k, this.connection.transport.request["headers"][k]);
447
- });
448
-
449
- } catch{
450
- return headers;
451
- }
452
- return headers;
453
- }
454
- get request(): any {
455
- return this.connection.transport.request;
456
- }
457
- }
1
+ import { URLSearchParams } from 'url';
2
+
3
+ import { Connection } from '../Connection/Connection';
4
+ import { CanInvoke } from '../Decorators/CanInvoke';
5
+ import { CanSetGet } from '../Decorators/CanSet';
6
+ import { ErrorMessage } from '../Messages/ErrorMessage';
7
+ import { TextMessage } from '../Messages/TextMessage';
8
+ import { Subscription } from './Subscription';
9
+
10
+ export interface ControllerBase {
11
+
12
+ subscriptions: Array<Subscription>;
13
+ connection: Connection;
14
+ disbaleHeartbeat(): void;
15
+ canInvokeMethod(method: string): boolean;
16
+ canSetProperty(property: string): boolean;
17
+ canGetProperty(property: string): boolean;
18
+ getProperty(propertyName:string,topic:string):any
19
+ setProperty(propertyName: string, propertyValue: any): void;
20
+ invokeError(ex: any): void;
21
+ invokeMethod(method: string, data: any, buffer?: Buffer): void;
22
+ findOn<T>(alias: string, predicate: (item: any) => boolean): ControllerBase[] | undefined;
23
+ getConnections(alias?: string): Connection[];
24
+ onopen(): void;
25
+ onclose(): void;
26
+ find<T, U>(array: T[], predicate: (item: any) => boolean, selector?: (item: T) => U): U[];
27
+ invokeToOthers(data: any, topic: string, controller?: string, buffer?: Buffer): void;
28
+ invokeToAll(data: any, topic: string, controller?: string, buffer?: Buffer): void;
29
+ invokeTo<T>(predicate: (item: T) => boolean, data: any, topic: string, controller?: string, buffer?: Buffer): void;
30
+ invoke(data: any, topic: string, controller?: string, buffer?: Buffer): ControllerBase;
31
+ publish(data: any, topic: string, controller?: string): ControllerBase;
32
+ publishToAll(data: any, topic: string, controller?: string): void;
33
+ hasSubscription(topic: string): boolean;
34
+ addSubscription(topic: string): Subscription;
35
+ removeSubscription(topic: string): void;
36
+ getSubscription(topic: string): Subscription | undefined;
37
+ instance(connection:Connection):ControllerBase
38
+ new(connection: Connection): ControllerBase;
39
+ }
40
+
41
+
42
+ /**
43
+ * ControllerBase
44
+ *
45
+ * Base class for all controllers.
46
+ */
47
+ export class ControllerBase implements ControllerBase {
48
+
49
+ /**
50
+ * Invokes a method on the controller.
51
+ * @param {string} method The name of the method to invoke.
52
+ * @param {any} data The data to pass to the method.
53
+ * @param {Buffer} [buffer] Optional buffer data.
54
+ */
55
+ @CanInvoke(false)
56
+ invokeMethod(method:string,data:any,buffer?:Buffer):void{
57
+ const controller = this as any;
58
+ const json = JSON.parse(data);
59
+ if (typeof controller[method] === "function") {
60
+ controller[method].apply(controller, [
61
+ json,
62
+ method,
63
+ controller.alias,
64
+ buffer,
65
+ ]);
66
+ }
67
+ }
68
+
69
+
70
+ /**
71
+ * Sets a property on the controller.
72
+ * @param {string} propertyName The name of the property to set.
73
+ * @param {any} propertyValue The value to set the property to.
74
+ */
75
+ @CanInvoke(false)
76
+ setProperty(proprtyName:string,propertyValue:any):void{
77
+ const controller = this as any;
78
+ if (typeof controller[proprtyName] === typeof propertyValue)
79
+ controller[proprtyName] = propertyValue;
80
+ }
81
+
82
+ /**
83
+ * Gets a property from the controller.
84
+ * @param {string} propertyName The name of the property to get.
85
+ * @param {string} topic The topic to use for the response.
86
+ */
87
+ @CanInvoke(false)
88
+ getProperty(proprtyName:string,topic:string):void{
89
+ const propertyValue = Reflect.getOwnMetadata(proprtyName, this)
90
+
91
+ this.invoke(propertyValue,topic);
92
+
93
+ }
94
+
95
+
96
+ /**
97
+ * Gets the name of the controller.
98
+ * @returns {string} The alias of the controller.
99
+ */
100
+ @CanInvoke(false)
101
+ public getName(){
102
+ return this.alias;
103
+ }
104
+ /**
105
+ * The alias of the controller.
106
+ * @type {string}
107
+ */
108
+ @CanSetGet(false)
109
+ public alias: string;
110
+ /**
111
+ * An array of subscriptions for the controller.
112
+ * @type {Array<Subscription>}
113
+ */
114
+ @CanSetGet(false)
115
+ public subscriptions: Array<Subscription>;
116
+ /**
117
+ * The connection associated with the controller.
118
+ * @type {Connection}
119
+ */
120
+ @CanSetGet(false)
121
+ public connection: Connection;
122
+ /**
123
+ * Timestamp of the last pong received.
124
+ * @type {Date | undefined}
125
+ */
126
+ @CanSetGet(false)
127
+ private lastPong: Date | undefined;
128
+
129
+ @CanSetGet(false)
130
+ /**
131
+ * Timestamp of the last ping sent.
132
+ * @type {Date | undefined}
133
+ */
134
+ private lastPing: Date | undefined;
135
+ /**
136
+ * Interval for sending heartbeats.
137
+ * @type {number}
138
+ */
139
+ @CanSetGet(false)
140
+ private heartbeatInterval: number;
141
+
142
+ /**
143
+ * NodeJS.Timeout object for the heartbeat interval.
144
+ * @type {NodeJS.Timeout | undefined}
145
+ */
146
+ private interval: NodeJS.Timeout | undefined;
147
+
148
+ /**
149
+ * Creates a new instance of ControllerBase.
150
+ *
151
+ * @param {Connection} connection The connection associated with the controller.
152
+ */
153
+ constructor(connection: Connection) {
154
+ this.connection = connection;
155
+ this.subscriptions = [];
156
+ this.alias = Reflect.getMetadata("alias", this.constructor);
157
+ this.heartbeatInterval = Reflect.getMetadata("heartbeatInterval", this.constructor);
158
+ if (this.heartbeatInterval >= 1000)
159
+ this.enableHeartbeat();
160
+ }
161
+ /**
162
+ * Enables the heartbeat mechanism.
163
+ */
164
+ @CanInvoke(false)
165
+ private enableHeartbeat() {
166
+ this.connection.transport.addEventListener("pong", () => {
167
+ this.lastPong = new Date();
168
+ });
169
+ this.interval = setInterval(() => {
170
+ this.lastPing = new Date();
171
+ if (this.connection.transport.readyState === 1)
172
+ this.connection.transport.ping();
173
+ }, this.heartbeatInterval);
174
+ }
175
+ /**
176
+ * Disables the heartbeat mechanism.
177
+ */
178
+ @CanInvoke(false)
179
+ public disbaleHeartbeat(): void {
180
+ clearInterval(this.interval!);
181
+ }
182
+
183
+ /**
184
+ * Checks if a specific method can be invoked on the controller.
185
+ *
186
+ * @param {string} method The name of the method.
187
+ * @returns {boolean} True if the method can be invoked, false otherwise.
188
+ */
189
+ @CanInvoke(false)
190
+ public canInvokeMethod(method: string): boolean {
191
+ return Reflect.getMetadata("canInvoke", this, method);
192
+ }
193
+
194
+ /**
195
+ * Checks if a specific property can be set on the controller.
196
+ *
197
+ * @param {string} property The name of the property.
198
+ * @returns {boolean} True if the property can be set, false otherwise.
199
+ */
200
+ @CanInvoke(false)
201
+ public canSetProperty(property: string): boolean {
202
+ return Reflect.getMetadata("canSet", this, property);
203
+ }
204
+ /**
205
+ * Checks if a specific property can be gotten from the controller.
206
+ *
207
+ * @param {string} property The name of the property.
208
+ * @returns {boolean} True if the property can be gotten, false otherwise.
209
+ */
210
+ @CanInvoke(false)
211
+ public canGetProperty(property: string): boolean {
212
+ return Reflect.getMetadata("canGet", this, property);
213
+ }
214
+
215
+ /**
216
+ * Finds controllers on other connections that match the given predicate.
217
+ *
218
+ * @template T
219
+ * @param {string} alias The alias of the controller to find.
220
+ * @param {Function} predicate The predicate function to filter controllers.
221
+ * @returns {ControllerBase[] | undefined} An array of controllers that match the predicate, or undefined if no controllers were found.
222
+ */
223
+ @CanInvoke(false)
224
+ findOn<T>(alias: string, predicate: (item: any) => boolean): ControllerBase[] | undefined {
225
+ let connections = this.getConnections(alias).map((p: Connection) => {
226
+ return p.tryGetController(alias);
227
+ });
228
+ const result = connections.filter(predicate).filter((c): c is ControllerBase => c !== undefined);
229
+ return result.length > 0 ? result : undefined;
230
+ }
231
+ /**
232
+ * Gets a list of connections.
233
+ *
234
+ * @param {string} alias Optional alias to filter connections by.
235
+ * @returns {Connection[]} An array of connections.
236
+ */
237
+ @CanInvoke(false)
238
+ getConnections(alias?: string): Connection[] {
239
+ if (!alias) {
240
+ return Array.from(this.connection.connections.values());
241
+ } else {
242
+ return Array.from(this.connection.connections.values())
243
+ .map((conn: Connection) => {
244
+ if (conn.hasController(this.alias)) {
245
+ return conn;
246
+ }
247
+ })
248
+ .filter((conn): conn is Connection => conn !== undefined);
249
+ }
250
+ }
251
+ /**
252
+ * Called when the connection is opened.
253
+ */
254
+ @CanInvoke(false)
255
+ onopen() { }
256
+ /**
257
+ * Called when the connection is closed.
258
+ */
259
+ @CanInvoke(false)
260
+ onclose() { }
261
+ /**
262
+ * Finds elements in an array that match a predicate and applies a selector function.
263
+ *
264
+ * @template T
265
+ * @template U
266
+ * @param {T[]} array The array to search.
267
+ * @param {Function} predicate The predicate function to filter elements.
268
+ * @param {Function} selector The selector function to apply to the filtered elements.
269
+ * @returns {U[]} An array of selected elements.
270
+ */
271
+ @CanInvoke(false)
272
+ find<T, U>(array: T[], predicate: (item: any) => boolean, selector: (item: T) => U = (x: T) => <U><any>x): U[] {
273
+ return array.filter(predicate).map(selector);
274
+ }
275
+ /**
276
+ * Invokes an error message.
277
+ *
278
+ * @param {any} ex The error object.
279
+ */
280
+ @CanInvoke(false)
281
+ invokeError(ex: any) {
282
+ let errorMessage = new ErrorMessage(ex.message);
283
+
284
+ this.invoke(errorMessage, "___error", this.alias);
285
+ }
286
+ /**
287
+ * Invokes a method on controllers on other connections.
288
+ *
289
+ * @param {any} data The data to send.
290
+ * @param {string} topic The topic of the message.
291
+ * @param {string} [controller] The optional controller alias.
292
+ * @param {any} [buffer] Optional buffer data.
293
+ */
294
+ @CanInvoke(false)
295
+ invokeToOthers(data: any, topic: string, controller?: string, buffer?: any) {
296
+ this.getConnections().filter((pre: Connection) => pre.id !== this.connection.id)
297
+ .forEach((connection: Connection) => {
298
+ const targetController = connection.tryGetController(controller || this.alias);
299
+ if (targetController) {
300
+ targetController.invoke(data, topic, controller || this.alias, buffer);
301
+ } else {
302
+ // Handle the case where the controller is not found for this connection
303
+ console.warn(`Controller '${controller || this.alias}' not found on connection '${connection.id}'`);
304
+ }
305
+ });
306
+ }
307
+
308
+ /**
309
+ * Invokes a method on controllers on all connections.
310
+ *
311
+ * @param {any} data The data to send.
312
+ * @param {string} topic The topic of the message.
313
+ * @param {string} [controller] The optional controller alias.
314
+ * @param {any} [buffer] Optional buffer data.
315
+ */
316
+ @CanInvoke(false)
317
+ invokeToAll(data: any, topic: string, controller?: string, buffer?: any) {
318
+ this.getConnections().forEach((connection: Connection) => {
319
+ const targetController = connection.tryGetController(controller || this.alias);
320
+ if (targetController) {
321
+ targetController.invoke(data, topic, controller || this.alias, buffer);
322
+ }
323
+ });
324
+ }
325
+
326
+ /**
327
+ * Invokes a method on controllers that match the given predicate.
328
+ *
329
+ * @param {Function} predicate The predicate function to filter controllers.
330
+ * @param {any} data The data to send.
331
+ * @param {string} topic The topic of the message.
332
+ * @param {string} [controller] The optional controller alias.
333
+ * @param {any} [buffer] Optional buffer data.
334
+ */
335
+ @CanInvoke(false)
336
+ invokeTo<T>(predicate: (item: T) => boolean, data: any, topic: string, controller?: string, buffer?: Buffer) {
337
+ const connections = this.findOn<ControllerBase>(controller || this.alias, predicate);
338
+ if (connections) {
339
+ connections.forEach((ctrl: ControllerBase) => {
340
+ ctrl.invoke(data, topic, controller || this.alias, buffer);
341
+ });
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Invokes a method on the current connection.
347
+ *
348
+ * @param {any} data The data to send.
349
+ * @param {string} topic The topic of the message.
350
+ * @param {string} [controller] The optional controller alias.
351
+ * @param {Buffer} [buffer] Optional buffer data.
352
+ * @returns {ControllerBase} The current controller instance.
353
+ */
354
+ @CanInvoke(false)
355
+ invoke(data: any, topic: string, controller?: string, buffer?: Buffer): ControllerBase {
356
+ let msg = new TextMessage(topic, data, controller || this.alias, buffer);
357
+ if (this.connection.transport)
358
+ this.connection.transport.send(!msg.isBinary ? msg.toString() : msg.toArrayBuffer());
359
+ return this;
360
+ }
361
+
362
+ /**
363
+ * Publishes a message to subscribers.
364
+ *
365
+ * @param {any} data The data to send.
366
+ * @param {string} topic The topic of the message.
367
+ * @param {string} [controller] The optional controller alias.
368
+ * @returns {ControllerBase} The current controller instance.
369
+ */
370
+ @CanInvoke(false)
371
+ publish(data: any, topic: string, controller?: string): ControllerBase {
372
+ if (!this.hasSubscription(topic))
373
+ return this;
374
+ return this.invoke(data, topic, controller || this.alias);
375
+ }
376
+
377
+ /**
378
+ * Publishes a message to all connections.
379
+ *
380
+ * @param {any} data The data to send.
381
+ * @param {string} topic The topic of the message.
382
+ * @param {string} [controller] The optional controller alias.
383
+ */
384
+ @CanInvoke(false)
385
+ publishToAll(data: any, topic: string, controller?: string) {
386
+ let msg = new TextMessage(topic, data, this.alias);
387
+ this.getConnections().forEach((connection: Connection) => {
388
+ let ctrl = connection.tryGetController(controller || this.alias);
389
+ if (ctrl) {
390
+ if (ctrl.getSubscription(topic)) {
391
+ connection.transport.send(msg.toString());
392
+ }
393
+ } else {
394
+ // Handle the case where the controller is not found for this connection
395
+ console.warn(`Controller '${controller || this.alias}' not found on connection '${connection.id}'`);
396
+ }
397
+ });
398
+ }
399
+
400
+ /**
401
+ * Checks if the controller has a subscription for the given topic.
402
+ *
403
+ * @param {string} topic The topic to check.
404
+ * @returns {boolean} True if the controller has a subscription for the topic, false otherwise.
405
+ */
406
+ @CanInvoke(false)
407
+ hasSubscription(topic: string): boolean {
408
+ /**
409
+ *
410
+ *
411
+ * @param {Subscription} pre
412
+ * @returns
413
+ */
414
+ let p = this.subscriptions.filter((pre: Subscription) => {
415
+ return pre.topic === topic;
416
+ });
417
+ return !(p.length === 0);
418
+ }
419
+
420
+ /**
421
+ * Adds a subscription for the given topic.
422
+ *
423
+ * @param {string} topic The topic to subscribe to.
424
+ * @returns {Subscription} The created subscription.
425
+ */
426
+ @CanInvoke(false)
427
+ addSubscription(topic: string): Subscription {
428
+ let subscription = new Subscription(topic, this.alias);
429
+ return this.___subscribe(subscription, topic, this.alias);
430
+ }
431
+
432
+ /**
433
+ * Removes a subscription for the given topic.
434
+ *
435
+ * @param {string} topic The topic to unsubscribe from.
436
+ */
437
+ @CanInvoke(false)
438
+ removeSubscription(topic: string) {
439
+
440
+ const subscription = this.getSubscription(topic);
441
+ if (!subscription) return;
442
+ return this.___unsubscribe(subscription);
443
+ }
444
+
445
+ /**
446
+ * Gets the subscription for the given topic.
447
+ *
448
+ * @param {string} topic The topic to find the subscription for.
449
+ * @returns {Subscription | undefined} The subscription for the given topic, or undefined if no subscription is found.
450
+ */
451
+ @CanInvoke(false)
452
+ getSubscription(topic: string): Subscription | undefined {
453
+ let subscription = this.subscriptions.find((pre: Subscription) => {
454
+ return pre.topic === topic;
455
+ });
456
+ return subscription;
457
+ }
458
+
459
+ /**
460
+ * Connects the controller.
461
+ *
462
+ * **Note:** This method is marked as @CanInvoke(true), but its purpose is unclear.
463
+ * Consider reviewing and potentially removing this method.
464
+ */
465
+ @CanInvoke(true)
466
+ ___connect() {
467
+ // todo: remove this method
468
+ }
469
+
470
+ /**
471
+ * Closes the connection associated with the controller.
472
+ */
473
+ @CanInvoke(true)
474
+ ___close() {
475
+ this.connection.tryRemoveControllerInstance(this.alias);
476
+ this.invoke({}, " ___close", this.alias);
477
+ }
478
+
479
+ /**
480
+ * Subscribes the controller to a specific topic.
481
+ *
482
+ * @param {Subscription} subscription The subscription object.
483
+ * @param {string} topic The topic to subscribe to.
484
+ * @param {string} controller The controller alias.
485
+ * @returns {Subscription} The created or existing subscription.
486
+ */
487
+
488
+ @CanInvoke(true)
489
+ ___subscribe(subscription: Subscription, topic: string, controller: string): Subscription {
490
+ if (this.hasSubscription(subscription.topic)) {
491
+ return this.getSubscription(topic)!;
492
+ }
493
+ this.subscriptions.push(subscription);
494
+ return subscription;
495
+ }
496
+
497
+ /**
498
+ * Unsubscribes the controller from a specific topic.
499
+ *
500
+ * @param {Subscription} subscription The subscription to unsubscribe.
501
+ * @returns {boolean} True if the subscription was successfully unsubscribed, false otherwise.
502
+ */
503
+ @CanInvoke(true)
504
+ ___unsubscribe(subscription: Subscription): boolean {
505
+ let index = this.subscriptions.indexOf(subscription);
506
+ if (index >= 0) {
507
+ let result = this.subscriptions.splice(index, 1);
508
+ return true;
509
+ }
510
+ else
511
+ return false;
512
+ }
513
+
514
+ /**
515
+ * Gets the query parameters from the request.
516
+ *
517
+ * @returns {URLSearchParams} The URLSearchParams object containing the query parameters.
518
+ */
519
+ get queryParameters(): URLSearchParams {
520
+ return new URLSearchParams(this.request.url.replace("/?", ""));
521
+ }
522
+ /**
523
+ * Gets the headers from the request.
524
+ *
525
+ * @returns {Map<string, string>} A Map containing the request headers.
526
+ */
527
+ get headers(): Map<string, string> {
528
+ let headers = new Map<string, any>();
529
+ try {
530
+ Object.keys(this.connection.transport.request["headers"]).forEach(k => {
531
+ headers.set(k, this.connection.transport.request["headers"][k]);
532
+ });
533
+
534
+ } catch {
535
+ return headers;
536
+ }
537
+ return headers;
538
+ }
539
+
540
+ /**
541
+ * Gets the underlying request object.
542
+ *
543
+ * @returns {any} The request object.
544
+ */
545
+ get request(): any {
546
+ return this.connection.transport.request;
547
+ }
548
+
549
+ /**
550
+ * Creates a new instance of the controller.
551
+ * @param {Connection} connection The connection associated with the controller.
552
+ * @returns {ControllerBase} The new controller instance.
553
+ */
554
+ instance(connection:Connection): ControllerBase{
555
+ console.log(`Create a new Instance of ${this.alias!} for ${connection.id}`);
556
+ return new ControllerBase(connection);
557
+ }
558
+ // new(connection: Connection): ControllerBase{
559
+ // return new ControllerBase(connection)
560
+ // }
561
+ }