thor-io.vnext 2.0.6 → 3.1.0-beta.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 (178) hide show
  1. package/.gitattributes +17 -17
  2. package/{index.d.ts → build/index.d.ts} +11 -8
  3. package/build/index.js +47 -0
  4. package/build/src/Connection/ClientInfo.d.ts +27 -0
  5. package/{src → 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/build/src/Interfaces/IInterceptor.js +2 -0
  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 -35
  96. package/licence +21 -21
  97. package/package.json +48 -49
  98. package/readme.md +32 -71
  99. package/src/Connection/ClientInfo.ts +34 -37
  100. package/src/Connection/Connection.ts +229 -278
  101. package/src/Connection/IClientInfo.ts +22 -0
  102. package/src/Controller/ControllerBase.ts +561 -458
  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 -18
  126. package/typedoc.json +6 -0
  127. package/index.js +0 -40
  128. package/src/Connection/ClientInfo.d.ts +0 -6
  129. package/src/Connection/Connection.d.ts +0 -24
  130. package/src/Connection/Connection.js +0 -129
  131. package/src/Controller/ControllerBase.d.ts +0 -43
  132. package/src/Controller/ControllerBase.js +0 -331
  133. package/src/Controllers/BrokerController/Broker.d.ts +0 -21
  134. package/src/Controllers/BrokerController/Broker.ts +0 -153
  135. package/src/Controllers/BrokerController/Models/PeerConnection.d.ts +0 -5
  136. package/src/Controllers/BrokerController/Models/PeerConnection.js +0 -9
  137. package/src/Controllers/BrokerController/Models/Signal.js +0 -10
  138. package/src/Decorators/CanInvoke.d.ts +0 -2
  139. package/src/Decorators/CanInvoke.js +0 -9
  140. package/src/Decorators/CanSet.d.ts +0 -1
  141. package/src/Decorators/CanSet.js +0 -8
  142. package/src/Decorators/ControllerProperties.d.ts +0 -1
  143. package/src/Decorators/ControllerProperties.js +0 -10
  144. package/src/Interfaces/IInterceptor.d.ts +0 -2
  145. package/src/Interfaces/IInterceptor.ts +0 -2
  146. package/src/Interfaces/ITransport.d.ts +0 -18
  147. package/src/Interfaces/ITransportMessage.d.ts +0 -8
  148. package/src/Messages/BufferMessage.d.ts +0 -10
  149. package/src/Messages/ErrorMessage.d.ts +0 -4
  150. package/src/Messages/ErrorMessage.js +0 -8
  151. package/src/Messages/PipeMessage.d.ts +0 -12
  152. package/src/Messages/PipeMessage.js +0 -20
  153. package/src/Messages/TextMessage.d.ts +0 -15
  154. package/src/Messages/TextMessage.js +0 -50
  155. package/src/Messages/WebSocketMessage.d.ts +0 -10
  156. package/src/Messages/WebSocketMessage.js +0 -15
  157. package/src/Plugin.d.ts +0 -6
  158. package/src/Plugin.js +0 -11
  159. package/src/Plugin.ts +0 -37
  160. package/src/Subscription.d.ts +0 -5
  161. package/src/Subscription.js +0 -9
  162. package/src/ThorIO.d.ts +0 -19
  163. package/src/ThorIO.js +0 -67
  164. package/src/ThorIO.ts +0 -153
  165. package/src/Transports/BufferMessageTransport.d.ts +0 -21
  166. package/src/Transports/BufferMessageTransport.js +0 -31
  167. package/src/Transports/PipeMessageTransport.d.ts +0 -20
  168. package/src/Transports/PipeMessageTransport.js +0 -33
  169. package/src/Transports/WebSocketMessageTransport.d.ts +0 -20
  170. package/src/Transports/WebSocketMessageTransport.js +0 -31
  171. package/src/Utils/BufferUtils.d.ts +0 -5
  172. package/src/Utils/BufferUtils.js +0 -29
  173. package/src/Utils/StringUtils.d.ts +0 -4
  174. package/src/Utils/StringUtils.js +0 -13
  175. /package/{src/Interfaces/IInterceptor.js → build/src/Connection/IClientInfo.js} +0 -0
  176. /package/{src → build/src}/Controllers/BrokerController/Models/Signal.d.ts +0 -0
  177. /package/{src → build/src}/Interfaces/ITransport.js +0 -0
  178. /package/{src → build/src}/Interfaces/ITransportMessage.js +0 -0
@@ -1,458 +1,561 @@
1
- import { CanInvoke } from '../Decorators/CanInvoke';
2
- import { CanSet } from '../Decorators/CanSet';
3
- import { TextMessage } from '../Messages/TextMessage';
4
-
5
- import { Subscription } from '../Subscription';
6
- import { ErrorMessage } from '../Messages/ErrorMessage';
7
- import { URLSearchParams } from 'url';
8
- import { Connection } from '../Connection/Connection';
9
-
10
- export interface ControllerBase {
11
- new(connection: Connection): ControllerBase;
12
- }
13
- export class ControllerBase {
14
- /**
15
- *
16
- *
17
- * @type {string}
18
- * @memberOf Controller
19
- */
20
- @CanSet(false)
21
- public alias: string;
22
- /**
23
- *
24
- *
25
- * @type {Array<Subscription>}
26
- * @memberOf Controller
27
- */
28
- @CanSet(false)
29
- public subscriptions: Array<Subscription>;
30
- /**
31
- *
32
- *
33
- * @type {Connection}
34
- * @memberOf Controller
35
- */
36
- @CanSet(false)
37
- public connection: Connection;
38
- /**
39
- *
40
- *
41
- * @private
42
- * @type {Date}
43
- * @memberOf Controller
44
- */
45
- @CanSet(false)
46
- private lastPong: Date;
47
- /**
48
- *
49
- *
50
- * @private
51
- * @type {Date}
52
- * @memberOf Controller
53
- */
54
- @CanSet(false)
55
- private lastPing: Date;
56
- /**
57
- *
58
- *
59
- * @private
60
- * @type {number}
61
- * @memberOf Controller
62
- */
63
- @CanSet(false)
64
- private heartbeatInterval: number;
65
- private interval: NodeJS.Timeout;
66
- /**
67
- * Creates an instance of Controller.
68
- *
69
- * @param {Connection} connection
70
- *
71
- * @memberOf Controller
72
- */
73
- constructor(connection: Connection) {
74
- this.connection = connection;
75
- this.subscriptions = [];
76
- this.alias = Reflect.getMetadata("alias", this.constructor);
77
- this.heartbeatInterval = Reflect.getMetadata("heartbeatInterval", this.constructor);
78
- if (this.heartbeatInterval >= 1000)
79
- this.enableHeartbeat();
80
- }
81
- /**
82
- *
83
- *
84
- * @private
85
- *
86
- * @memberOf Controller
87
- */
88
- @CanInvoke(false)
89
- private enableHeartbeat() {
90
- this.connection.transport.addEventListener("pong", () => {
91
- this.lastPong = new Date();
92
- });
93
- this.interval = setInterval(() => {
94
- this.lastPing = new Date();
95
- if (this.connection.transport.readyState === 1)
96
- this.connection.transport.ping();
97
- }, this.heartbeatInterval);
98
- }
99
- @CanInvoke(false)
100
- public disbaleHeartbeat(): void {
101
- clearInterval(this.interval);
102
- }
103
- /**
104
- *
105
- *
106
- * @param {string} method
107
- * @returns {boolean}
108
- *
109
- * @memberOf Controller
110
- */
111
- @CanInvoke(false)
112
- public canInvokeMethod(method: string): boolean {
113
- return Reflect.getMetadata("canInvokeOrSet", this, method);
114
- }
115
- /**
116
- *
117
- *
118
- * @template T
119
- * @param {string} alias
120
- * @param {(item: any) => boolean} predicate
121
- * @returns {Array<any>}
122
- *
123
- * @memberOf Controller
124
- */
125
- @CanInvoke(false)
126
- findOn<T>(alias: string, predicate: (item: any) => boolean): Array<ControllerBase> {
127
- /**
128
- *
129
- *
130
- * @param {Connection} p
131
- * @returns
132
- */
133
- let connections = this.getConnections(alias).map((p: Connection) => {
134
- return p.getController(alias);
135
- });
136
- return connections.filter(predicate);
137
- }
138
- /**
139
- *
140
- *
141
- * @param {string} [alias]
142
- * @returns {Array<Connection>}
143
- *
144
- * @memberOf Controller
145
- */
146
- @CanInvoke(false)
147
- getConnections(alias?: string): Array<Connection> {
148
- if (!alias) {
149
- return Array.from(this.connection.connections.values());
150
- }
151
- else {
152
- return Array.from(this.connection.connections.values()).map((conn: Connection) => {
153
- if (conn.hasController(this.alias))
154
- return conn;
155
- });
156
- }
157
- }
158
- /**
159
- *
160
- *
161
- *
162
- * @memberOf Controller
163
- */
164
- @CanInvoke(false)
165
- onopen() { }
166
- /**
167
- *
168
- *
169
- *
170
- * @memberOf Controller
171
- */
172
- @CanInvoke(false)
173
- onclose() { }
174
- /**
175
- *
176
- *
177
- * @template T
178
- * @template U
179
- * @param {T[]} array
180
- * @param {(item: any) => boolean} predicate
181
- * @param {(item: T) => U} [selector=(x: T) => <U><any>x]
182
- * @returns {U[]}
183
- *
184
- * @memberOf Controller
185
- */
186
- @CanInvoke(false)
187
- find<T, U>(array: T[], predicate: (item: any) => boolean, selector: (item: T) => U = (x: T) => <U><any>x): U[] {
188
- return array.filter(predicate).map(selector);
189
- }
190
- /**
191
- *
192
- *
193
- * @param {*} error
194
- *
195
- * @memberOf Controller
196
- */
197
- @CanInvoke(false)
198
- invokeError(ex: any) {
199
- let errorMessage = new ErrorMessage(ex.message);
200
- this.invoke(errorMessage, "___error", this.alias);
201
- }
202
- /**
203
- *
204
- *
205
- * @param {*} data
206
- * @param {string} topic
207
- * @param {string} [controller]
208
- * @param {*} [buffer]
209
- * @returns {ControllerBase}
210
- *
211
- * @memberOf Controller
212
- */
213
- @CanInvoke(false)
214
- invokeToOthers(data: any, topic: string, controller?: string, buffer?: any) {
215
- this.getConnections().filter((pre: Connection) => {
216
- return pre.id !== this.connection.id;
217
- })
218
- .forEach((connection: Connection) => {
219
- connection.getController(controller || this.alias).invoke(data, topic, controller || this.alias, buffer);
220
- });
221
-
222
- }
223
- /*
224
- *
225
- *
226
- * @param {*} data
227
- * @param {string} topic
228
- * @param {string} [controller]
229
- * @param {*} [buffer]
230
- * @returns {ControllerBase}
231
- *
232
- * @memberOf Controller
233
- */
234
- @CanInvoke(false)
235
- invokeToAll(data: any, topic: string, controller?: string, buffer?: any) {
236
- this.getConnections().forEach((connection: Connection) => {
237
- connection.getController(controller || this.alias).invoke(data, topic, controller || this.alias, buffer);
238
- });
239
-
240
- }
241
- /**
242
- *
243
- *
244
- * @param {(item: ControllerBase) => boolean} predicate
245
- * @param {*} data
246
- * @param {string} topic
247
- * @param {string} [controller]
248
- * @param {*} [buffer]
249
- * @returns {ControllerBase}
250
- *
251
- * @memberOf Controller
252
- */
253
- @CanInvoke(false)
254
- invokeTo(predicate: (item: ControllerBase) => boolean, data: any, topic: string, controller?: string, buffer?: any) {
255
- let connections = this.findOn<this>(controller || this.alias, predicate);
256
- connections.forEach((ctrl: ControllerBase) => {
257
- ctrl.invoke(data, topic, controller || this.alias, buffer);
258
- });
259
- }
260
- /**
261
- *
262
- *
263
- * @param {*} data
264
- * @param {string} topic
265
- * @param {string} [controller]
266
- * @param {*} [buffer]
267
- * @returns {ControllerBase}
268
- *
269
- * @memberOf Controller
270
- */
271
- @CanInvoke(false)
272
- invoke(data: any, topic: string, controller?: string, buffer?: any): ControllerBase {
273
- let msg = new TextMessage(topic, data, controller || this.alias, buffer);
274
- if (this.connection.transport)
275
- this.connection.transport.send(!msg.isBinary ? msg.toString() : msg.toArrayBuffer());
276
- return this;
277
- }
278
- /**
279
- *
280
- *
281
- * @param {*} data
282
- * @param {string} topic
283
- * @param {string} [controller]
284
- * @returns {ControllerBase}
285
- *
286
- * @memberOf Controller
287
- */
288
- @CanInvoke(false)
289
- publish(data: any, topic: string, controller?: string): ControllerBase {
290
- if (!this.hasSubscription(topic))
291
- return;
292
- return this.invoke(data, topic, controller || this.alias);
293
- }
294
- /**
295
- *
296
- *
297
- * @param {*} data
298
- * @param {string} topic
299
- * @param {string} [controller]
300
- * @returns {ControllerBase}
301
- *
302
- * @memberOf Controller
303
- */
304
- @CanInvoke(false)
305
- publishToAll(data: any, topic: string, controller?: string) {
306
- let msg = new TextMessage(topic, data, this.alias);
307
- this.getConnections().forEach((connection: Connection) => {
308
- let ctrl = connection.getController(controller || this.alias);
309
- if (ctrl.getSubscription(topic)) {
310
- connection.transport.send(msg.toString());
311
- }
312
- });
313
-
314
- }
315
- /**
316
- *
317
- *
318
- * @param {string} topic
319
- * @returns {boolean}
320
- *
321
- * @memberOf Controller
322
- */
323
- @CanInvoke(false)
324
- hasSubscription(topic: string): boolean {
325
- /**
326
- *
327
- *
328
- * @param {Subscription} pre
329
- * @returns
330
- */
331
- let p = this.subscriptions.filter((pre: Subscription) => {
332
- return pre.topic === topic;
333
- });
334
- return !(p.length === 0);
335
- }
336
- /**
337
- *
338
- *
339
- * @param {string} topic
340
- * @returns {Subscription}
341
- *
342
- * @memberOf Controller
343
- */
344
- @CanInvoke(false)
345
- addSubscription(topic: string): Subscription {
346
- let subscription = new Subscription(topic, this.alias);
347
- return this.___subscribe(subscription, topic, this.alias);
348
- }
349
- /**
350
- *
351
- *
352
- * @param {string} topic
353
- * @returns
354
- *
355
- * @memberOf Controller
356
- */
357
- @CanInvoke(false)
358
- removeSubscription(topic: string) {
359
- return this.___unsubscribe(this.getSubscription(topic));
360
- }
361
- /**
362
- *
363
- *
364
- * @param {string} topic
365
- * @returns {Subscription}
366
- *
367
- * @memberOf Controller
368
- */
369
- @CanInvoke(false)
370
- getSubscription(topic: string): Subscription {
371
- /**
372
- *
373
- *
374
- * @param {Subscription} pre
375
- * @returns
376
- */
377
- let subscription = this.subscriptions.find((pre: Subscription) => {
378
- return pre.topic === topic;
379
- });
380
- return subscription;
381
- }
382
- /**
383
- *
384
- *
385
- *
386
- * @memberOf Controller
387
- */
388
- @CanInvoke(true)
389
- ___connect() {
390
- // todo: remove this method
391
- }
392
- /**
393
- *
394
- *
395
- *
396
- * @memberOf Controller
397
- */
398
- @CanInvoke(true)
399
- ___close() {
400
- this.connection.removeController(this.alias);
401
- this.invoke({}, " ___close", this.alias);
402
- }
403
- /**
404
- *
405
- *
406
- * @param {Subscription} subscription
407
- * @param {string} topic
408
- * @param {string} controller
409
- * @returns {Subscription}
410
- *
411
- * @memberOf Controller
412
- */
413
- @CanInvoke(true)
414
- ___subscribe(subscription: Subscription, topic: string, controller: string): Subscription {
415
- if (this.hasSubscription(subscription.topic)) {
416
- return;
417
- }
418
- this.subscriptions.push(subscription);
419
- return subscription;
420
- }
421
-
422
- /**
423
- *
424
- *
425
- * @param {Subscription} subscription
426
- * @returns {boolean}
427
- *
428
- * @memberOf Controller
429
- */
430
- @CanInvoke(true)
431
- ___unsubscribe(subscription: Subscription): boolean {
432
- let index = this.subscriptions.indexOf(this.getSubscription(subscription.topic));
433
- if (index >= 0) {
434
- let result = this.subscriptions.splice(index, 1);
435
- return true;
436
- }
437
- else
438
- return false;
439
- }
440
- get queryParameters(): URLSearchParams {
441
- return new URLSearchParams(this.request.url.replace("/?",""));
442
- }
443
- get headers(): Map<string, string> {
444
- let headers = new Map<string, any>();
445
- try {
446
- Object.keys(this.connection.transport.request["headers"]).forEach(k => {
447
- headers.set(k, this.connection.transport.request["headers"][k]);
448
- });
449
-
450
- } catch{
451
- return headers;
452
- }
453
- return headers;
454
- }
455
- get request(): any {
456
- return this.connection.transport.request;
457
- }
458
- }
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
+ }