@itee/client 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +251 -0
  2. package/LICENSE.md +23 -0
  3. package/README.md +76 -0
  4. package/builds/itee-client.cjs.js +6517 -0
  5. package/builds/itee-client.cjs.js.map +1 -0
  6. package/builds/itee-client.cjs.min.js +125 -0
  7. package/builds/itee-client.esm.js +6468 -0
  8. package/builds/itee-client.esm.js.map +1 -0
  9. package/builds/itee-client.esm.min.js +124 -0
  10. package/builds/itee-client.iife.js +6524 -0
  11. package/builds/itee-client.iife.js.map +1 -0
  12. package/builds/itee-client.iife.min.js +125 -0
  13. package/package.json +87 -0
  14. package/sources/client.js +14 -0
  15. package/sources/cores/TAbstractFactory.js +42 -0
  16. package/sources/cores/TCloningFactory.js +39 -0
  17. package/sources/cores/TConstants.js +433 -0
  18. package/sources/cores/TInstancingFactory.js +41 -0
  19. package/sources/cores/TStore.js +303 -0
  20. package/sources/cores/_cores.js +13 -0
  21. package/sources/input_devices/TKeyboardController.js +158 -0
  22. package/sources/input_devices/TMouseController.js +31 -0
  23. package/sources/input_devices/_inputDevices.js +11 -0
  24. package/sources/loaders/TBinaryConverter.js +35 -0
  25. package/sources/loaders/TBinaryReader.js +1029 -0
  26. package/sources/loaders/TBinarySerializer.js +258 -0
  27. package/sources/loaders/TBinaryWriter.js +429 -0
  28. package/sources/loaders/_loaders.js +21 -0
  29. package/sources/loaders/converters/ArrayBinaryConverter.js +33 -0
  30. package/sources/loaders/converters/BooleanBinaryConverter.js +24 -0
  31. package/sources/loaders/converters/DateBinaryConverter.js +21 -0
  32. package/sources/loaders/converters/NullBinaryConverter.js +13 -0
  33. package/sources/loaders/converters/NumberBinaryConverter.js +15 -0
  34. package/sources/loaders/converters/ObjectBinaryConverter.js +101 -0
  35. package/sources/loaders/converters/RegExBinaryConverter.js +11 -0
  36. package/sources/loaders/converters/StringBinaryConverter.js +26 -0
  37. package/sources/loaders/converters/UndefinedBinaryConverter.js +13 -0
  38. package/sources/managers/TDataBaseManager.js +1649 -0
  39. package/sources/managers/_managers.js +10 -0
  40. package/sources/utils/TIdFactory.js +84 -0
  41. package/sources/utils/_utils.js +9 -0
  42. package/sources/webapis/WebAPI.js +773 -0
  43. package/sources/webapis/WebAPIOrigin.js +141 -0
  44. package/sources/webapis/_webapis.js +10 -0
  45. package/sources/webapis/messages/WebAPIMessage.js +75 -0
  46. package/sources/webapis/messages/WebAPIMessageData.js +51 -0
  47. package/sources/webapis/messages/WebAPIMessageError.js +79 -0
  48. package/sources/webapis/messages/WebAPIMessageEvent.js +58 -0
  49. package/sources/webapis/messages/WebAPIMessageProgress.js +91 -0
  50. package/sources/webapis/messages/WebAPIMessageReady.js +66 -0
  51. package/sources/webapis/messages/WebAPIMessageRequest.js +94 -0
  52. package/sources/webapis/messages/WebAPIMessageResponse.js +80 -0
  53. package/sources/webapis/messages/_messages.js +16 -0
  54. package/sources/workers/AbstractWorker.js +149 -0
  55. package/sources/workers/_workers.js +10 -0
  56. package/sources/workers/messages/WorkerMessage.js +33 -0
  57. package/sources/workers/messages/WorkerMessageData.js +30 -0
  58. package/sources/workers/messages/WorkerMessageError.js +32 -0
  59. package/sources/workers/messages/WorkerMessageMethodCall.js +60 -0
  60. package/sources/workers/messages/WorkerMessageProgress.js +67 -0
  61. package/sources/workers/messages/_messages.js +14 -0
@@ -0,0 +1,773 @@
1
+ /**
2
+ * @author [Tristan Valcke]{@link https://github.com/Itee}
3
+ */
4
+
5
+ import { DefaultLogger } from '@itee/core'
6
+ import { toArray } from '@itee/utils'
7
+ import {
8
+ isDefined,
9
+ isEmptyArray,
10
+ isNotDefined,
11
+ isNotNumber,
12
+ isNull,
13
+ isNumberNegative,
14
+ isObject,
15
+ isString,
16
+ isUndefined,
17
+ isZero
18
+ } from '@itee/validators'
19
+ import { WebAPIMessageData } from './messages/WebAPIMessageData.js'
20
+ import { WebAPIMessageError } from './messages/WebAPIMessageError.js'
21
+ import { WebAPIMessageEvent } from './messages/WebAPIMessageEvent.js'
22
+ import { WebAPIMessageReady } from './messages/WebAPIMessageReady.js'
23
+ import { WebAPIMessageRequest } from './messages/WebAPIMessageRequest.js'
24
+ import { WebAPIMessageResponse } from './messages/WebAPIMessageResponse.js'
25
+ import { WebAPIOrigin } from './WebAPIOrigin.js'
26
+
27
+ /**
28
+ * A POJO object containg datas about a distant source to allow
29
+ * @typedef {Object} AllowedOrigin
30
+ * @property {string} id - The id to reference this origin as a human readable string
31
+ * @property {string} uri - The uri of the origin to allow
32
+ * @property {Array<String>} methods - An array of methods names that are allowed for this origins. To allow all methods use '*', in case no methods string were provide the origin won't be able to do
33
+ * anything.
34
+ */
35
+
36
+ /**
37
+ * @class
38
+ * @classdesc The abstract class to use standardized webapi.
39
+ * @abstract
40
+ */
41
+ class WebAPI {
42
+
43
+ /**
44
+ * @constructor
45
+ * @param {Object} parameters - An object containing all parameters to pass through the inheritance chain to initialize this instance
46
+ * @param {Boolean} [parameters.allowAnyOrigins=false] - A boolean to allow or not any origins calls
47
+ * @param {Array<AllowedOrigin>} [parameters.allowedOrigins=[]] - An array containing configured allowed origins
48
+ * @param {Number} [parameters.requestTimeout=2000] - The request timeout before throw an error
49
+ */
50
+ constructor( parameters = {} ) {
51
+
52
+ const _parameters = {
53
+ ...{
54
+ logger: DefaultLogger,
55
+ allowedOrigins: [],
56
+ requestTimeout: 2000,
57
+ methods: this,
58
+ broadcastReadyOnInit: true
59
+ },
60
+ ...parameters
61
+ }
62
+
63
+ // Private stuff
64
+ this._localOriginUri = window.location.origin
65
+ this._awaitingRequest = new Map()
66
+ this._eventListeners = {} //"eventName" : [ callback1, ... ]
67
+
68
+ // Listen message from Window
69
+ window.addEventListener( 'message', this._onMessage.bind( this ), false )
70
+
71
+ // Public stuff
72
+ this.logger = _parameters.logger
73
+ this.allowedOrigins = _parameters.allowedOrigins
74
+ this.requestTimeout = _parameters.requestTimeout
75
+ this.methods = _parameters.methods
76
+
77
+ // Initiate connection to all origins
78
+ if ( _parameters.broadcastReadyOnInit ) {
79
+ this._broadcastReadyMessage()
80
+ }
81
+ }
82
+
83
+ /**
84
+ *
85
+ * @returns {TLogger}
86
+ */
87
+ get logger() {
88
+ return this._logger
89
+ }
90
+ /**
91
+ *
92
+ * @param value {TLogger}
93
+ */
94
+ set logger( value ) {
95
+ if ( isNull( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The logger cannot be null, expect a TLogger.` )}
96
+ if ( isUndefined( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The logger cannot be undefined, expect a TLogger.` )}
97
+ if ( !value.isLogger ) { throw new ReferenceError( `[${ this._localOriginUri }]: The logger cannot be undefined, expect a TLogger.` )}
98
+
99
+ this._logger = value
100
+ }
101
+ /**
102
+ *
103
+ * @returns {Array<WebAPIOrigin>}
104
+ */
105
+ get allowedOrigins() {
106
+ return this._allowedOrigins
107
+ }
108
+ /**
109
+ *
110
+ * @param value {Array<WebAPIOrigin>}
111
+ */
112
+ set allowedOrigins( value ) {
113
+
114
+ this._allowedOrigins = []
115
+ const _allowedOrigins = toArray( value )
116
+
117
+ // Special case for any origin
118
+ // Todo: should log error in production and cancel '*'
119
+ if ( _allowedOrigins.includes( '*' ) ) {
120
+ this.logger.warn( `[${ this._localOriginUri }]: This webApi is allowed for all origin and could lead to security concerne !` )
121
+ this._allowedOrigins.push( '*' )
122
+ return
123
+ }
124
+
125
+ // Create WebApiOrigin based on provided settings
126
+ for ( let allowedOrigin of _allowedOrigins ) {
127
+
128
+ const origin = new WebAPIOrigin( {
129
+ id: allowedOrigin.id,
130
+ uri: allowedOrigin.uri,
131
+ methods: allowedOrigin.methods,
132
+ window: this._getOriginWindow( allowedOrigin.uri )
133
+ } )
134
+ this._allowedOrigins.push( origin )
135
+
136
+ }
137
+
138
+ }
139
+ /**
140
+ *
141
+ * @returns {Number}
142
+ */
143
+ get requestTimeout() {
144
+ return this._requestTimeout
145
+ }
146
+ /**
147
+ *
148
+ * @param value {Number}
149
+ */
150
+ set requestTimeout( value ) {
151
+ if ( isNull( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The request timeout cannot be null, expect to be 0 or a positive number.` )}
152
+ if ( isUndefined( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The request timeout cannot be undefined, expect to be 0 or a positive number.` )}
153
+ if ( isNotNumber( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The request timeout expect to be 0 or a positive number.` )}
154
+ if ( isNumberNegative( value ) && !isZero( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The request timeout expect to be 0 or a positive number.` )}
155
+
156
+ this._requestTimeout = value
157
+ }
158
+ /**
159
+ *
160
+ * @returns {Array<Function>}
161
+ */
162
+ get methods() {
163
+ return this._methods
164
+ }
165
+ /**
166
+ *
167
+ * @param value Array<Function>
168
+ */
169
+ set methods( value ) {
170
+ if ( isNull( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The methods cannot be null, expect any keyed collection of function.` )}
171
+ if ( isUndefined( value ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: The methods cannot be undefined, expect any keyed collection of function.` )}
172
+ // Todo: isNotObject && isNotMap && isNotSet && isNotApi
173
+
174
+ this._methods = value
175
+ }
176
+ /**
177
+ *
178
+ * @param value {TLogger}
179
+ * @returns {AbstractWebAPI}
180
+ */
181
+ setLogger( value ) {
182
+ this.logger = value
183
+ return this
184
+ }
185
+ /**
186
+ *
187
+ * @param value {Array<WebAPIOrigin>}
188
+ * @returns {AbstractWebAPI}
189
+ */
190
+ setAllowedOrigins( value ) {
191
+ this.allowedOrigins = value
192
+ return this
193
+ }
194
+ /**
195
+ *
196
+ * @param value {Number}
197
+ * @returns {AbstractWebAPI}
198
+ */
199
+ setRequestTimeout( value ) {
200
+ this.requestTimeout = value
201
+ return this
202
+ }
203
+ /**
204
+ *
205
+ * @param value Array<Function>
206
+ * @returns {AbstractWebAPI}
207
+ */
208
+ setMethods( value ) {
209
+ this.methods = value
210
+ return this
211
+ }
212
+
213
+ addEventListener( eventName, listener ) {
214
+ if ( isNotDefined( this._eventListeners[ eventName ] ) ) {
215
+ this._eventListeners[ eventName ] = []
216
+ }
217
+
218
+ this._eventListeners[ eventName ].push( listener )
219
+ }
220
+ removeListener( eventName, listener ) {
221
+ if ( isNotDefined( this._eventListeners[ eventName ] ) ) {
222
+ return
223
+ }
224
+
225
+ const index = this._eventListeners[ eventName ].indexOf( listener )
226
+ if ( index > -1 ) {
227
+ this._eventListeners[ eventName ].splice( index, 1 )
228
+ }
229
+ }
230
+ // Validators
231
+
232
+ /**
233
+ *
234
+ * @returns {boolean}
235
+ * @private
236
+ */
237
+ _isInIframe() {
238
+
239
+ try {
240
+ return window.self !== window.top
241
+ } catch ( error ) {
242
+ return true
243
+ }
244
+
245
+ }
246
+
247
+ /**
248
+ *
249
+ * @returns {boolean}
250
+ * @private
251
+ */
252
+ _isNotAllowedForAllOrigins() {
253
+
254
+ return !this._allowedOrigins.includes( '*' )
255
+ // return !this.allowAnyOrigins
256
+ }
257
+
258
+ /**
259
+ *
260
+ * @param originURI
261
+ * @returns {boolean}
262
+ * @private
263
+ */
264
+ _isNotAllowedOrigin( originURI ) {
265
+
266
+ return !this._allowedOrigins
267
+ .filter( origin => origin !== '*' )
268
+ .map( origin => origin.uri )
269
+ .includes( originURI )
270
+
271
+ }
272
+
273
+ /**
274
+ *
275
+ * @param originURI
276
+ * @returns {boolean}
277
+ * @private
278
+ */
279
+ _isSameOrigin( originURI ) {
280
+ return this._localOriginUri === originURI
281
+ }
282
+
283
+ /**
284
+ *
285
+ * @param origin {WebAPIOrigin}
286
+ * @returns {boolean}
287
+ * @private
288
+ */
289
+ _isNotAllowedForAllMethods( origin ) {
290
+ return ( origin.allowedMethods.indexOf( '*' ) === -1 )
291
+ }
292
+
293
+ /**
294
+ *
295
+ * @param origin {WebAPIOrigin}
296
+ * @param methodName {string}
297
+ * @returns {boolean}
298
+ * @private
299
+ */
300
+ _isNotAllowedMethod( origin, methodName ) {
301
+ return ( origin.allowedMethods.indexOf( methodName ) === -1 )
302
+ }
303
+
304
+ /**
305
+ *
306
+ * @param methodName
307
+ * @returns {boolean}
308
+ * @private
309
+ */
310
+ _methodNotExist( methodName ) {
311
+ return isNotDefined( this.methods[ methodName ] )
312
+ }
313
+
314
+ // Utils
315
+
316
+ /**
317
+ *
318
+ * @param propertyName
319
+ * @param value
320
+ * @returns {WebAPIOrigin}
321
+ * @private
322
+ */
323
+ _getAllowedOriginBy( propertyName, value ) {
324
+ return this.allowedOrigins.find( origin => origin[ propertyName ] === value )
325
+ }
326
+
327
+ /**
328
+ *
329
+ * @param originURI
330
+ * @returns {Window}
331
+ * @private
332
+ */
333
+ _getOriginWindow( originURI ) {
334
+
335
+ let originWindow
336
+
337
+ if ( this._isInIframe() ) {
338
+
339
+ originWindow = window.parent
340
+
341
+ } else {
342
+
343
+ const frames = document.getElementsByTagName( 'iframe' )
344
+ const frame = Array.from( frames ).find( iframe => iframe.src.includes( originURI ) )
345
+ if ( isNotDefined( frame ) ) {
346
+ this.logger.warn( `[${ this._localOriginUri }]: Unable to find iframe element for [${ originURI }] URI !` )
347
+ originWindow = null
348
+ } else {
349
+ originWindow = frame.contentWindow
350
+ }
351
+
352
+ }
353
+
354
+ return originWindow
355
+
356
+ }
357
+
358
+ /**
359
+ *
360
+ * @param origin {WebAPIOrigin}
361
+ * @private
362
+ */
363
+ _processMessageQueueOf( origin ) {
364
+
365
+ const messageQueue = origin.messageQueue
366
+ for ( let messageIndex = messageQueue.length - 1 ; messageIndex >= 0 ; messageIndex-- ) {
367
+ this.postMessageTo( origin.id, messageQueue.shift() )
368
+ }
369
+
370
+ }
371
+
372
+ /**
373
+ *
374
+ * @private
375
+ */
376
+ _broadcastReadyMessage() {
377
+
378
+ const ready = new WebAPIMessageReady()
379
+ let checkInterval = 250
380
+
381
+ const broadcast = () => {
382
+
383
+ const unreadyOrigins = this.allowedOrigins.filter( origin => !origin.isReady && origin.isReachable )
384
+ if ( isEmptyArray( unreadyOrigins ) ) {
385
+ return
386
+ }
387
+
388
+ for ( let unreadyOrigin of unreadyOrigins ) {
389
+ this.postReadyTo( unreadyOrigin.id, ready )
390
+ }
391
+
392
+ checkInterval += checkInterval
393
+ setTimeout( broadcast, checkInterval )
394
+
395
+ }
396
+ broadcast()
397
+
398
+ }
399
+
400
+ // Messaging
401
+
402
+ /**
403
+ *
404
+ * @param event
405
+ * @returns {Promise<void>}
406
+ * @private
407
+ */
408
+ async _onMessage( event ) {
409
+
410
+ // Is allowed origin
411
+ if ( this._isNotAllowedForAllOrigins() && this._isNotAllowedOrigin( event.origin ) ) {
412
+ this.logger.warn( `[${ this._localOriginUri }]: An unallowed origin [${ event.origin }] try to access the web api.` )
413
+ return
414
+ }
415
+
416
+ // Is self ?
417
+ if ( this._isSameOrigin( event.origin ) ) {
418
+ this.logger.warn( `[${ this._localOriginUri }]: A local origin try to access the web api...
419
+ or... Am i talking to myself ?
420
+ Said i (${ isString( event.data ) ? event.data : JSON.stringify( event.data ) }) ?
421
+ Hummm... Ehhooo ! Who's there ?
422
+ ` )
423
+ return
424
+ }
425
+
426
+ // In case we are not in embbeded iframe or the origin is not an iframe set the origin window as the source event
427
+ let origin = this._getAllowedOriginBy( 'uri', event.origin )
428
+ if ( isNotDefined( origin ) ) {
429
+
430
+ // If we are here, we are called by an unknown origin but we are allowed for all. So create a new one
431
+ origin = new WebAPIOrigin( {
432
+ uri: event.origin,
433
+ window: event.source
434
+ } )
435
+ this.allowedOrigins.push( origin )
436
+
437
+ } else if ( isNull( origin.window ) ) {
438
+
439
+ origin.window = event.source
440
+
441
+ }
442
+
443
+ const eventData = event.data
444
+ const message = isObject( eventData ) ? eventData : JSON.parse( eventData )
445
+ if ( isNotDefined( message ) ) {
446
+ this.logger.error( `[${ this._localOriginUri }]: Recieve null or undefined message from [${ origin.uri }] ! Expect a json object.` )
447
+ return
448
+ }
449
+
450
+ await this._dispatchMessageFrom( origin, message )
451
+
452
+ }
453
+
454
+ /**
455
+ *
456
+ * @param origin
457
+ * @param message
458
+ * @private
459
+ */
460
+ async _dispatchMessageFrom( origin, message ) {
461
+
462
+ this.logger.log( `[${ this._localOriginUri }]: Recieve message of type '${ message.type }' from [${ origin.uri }].` )
463
+
464
+ switch ( message.type ) {
465
+
466
+ case '_ready':
467
+ this._onReadyFrom( origin, message )
468
+ break
469
+
470
+ case '_request':
471
+ await this._onRequestFrom( origin, message )
472
+ break
473
+
474
+ case '_response':
475
+ this._onResponseFrom( origin, message )
476
+ break
477
+
478
+ case '_data':
479
+ this.onDataFrom( origin, message )
480
+ break
481
+
482
+ case '_event':
483
+ this.onEventFrom( origin, message )
484
+ break
485
+
486
+ case '_error':
487
+ this.onErrorFrom( origin, message )
488
+ break
489
+
490
+ default:
491
+ this.onMessageFrom( origin, message )
492
+
493
+ }
494
+
495
+ }
496
+
497
+ /**
498
+ *
499
+ * @param origin
500
+ * @param message
501
+ */
502
+ _onReadyFrom( origin, message ) {
503
+
504
+ if ( !origin.isReady ) {
505
+ origin.isReady = true
506
+
507
+ // Avoid some ping-pong ready message
508
+ if ( !message.isBind ) {
509
+ const ready = new WebAPIMessageReady( { isBind: true } )
510
+ this.postMessageTo( origin.id, ready, true )
511
+ }
512
+ }
513
+
514
+ this._processMessageQueueOf( origin )
515
+
516
+ }
517
+
518
+ /**
519
+ *
520
+ * @param origin
521
+ * @param request
522
+ */
523
+ async _onRequestFrom( origin, request ) {
524
+
525
+ let message
526
+ const methodName = request.method
527
+ const parameters = request.parameters
528
+
529
+ if ( this._isNotAllowedForAllMethods( origin ) && this._isNotAllowedMethod( origin, methodName ) ) {
530
+
531
+ this.logger.error( `[${ this._localOriginUri }]: Origin [${ origin.uri }] try to access an unallowed method named '${ methodName }'.` )
532
+ message = new WebAPIMessageError( new RangeError( `Trying to access an unallowed method named '${ methodName }'.` ) )
533
+
534
+ } else if ( this._methodNotExist( methodName ) ) {
535
+
536
+ this.logger.error( `[${ this._localOriginUri }]: Origin [${ origin.uri }] try to access an unexisting method named '${ methodName }'.` )
537
+ message = new WebAPIMessageError( new RangeError( `Trying to access an unexisting method named '${ methodName }'.` ) )
538
+
539
+ } else {
540
+
541
+ try {
542
+ const result = await this.methods[ methodName ]( ...parameters )
543
+ message = new WebAPIMessageData( result )
544
+ } catch ( error ) {
545
+ message = new WebAPIMessageError( error )
546
+ }
547
+
548
+ }
549
+
550
+ // To avoid unnecessary client timeout we need to respond with error or data in any case
551
+ this.postResponseTo( origin.id, request, message )
552
+
553
+ }
554
+
555
+ /**
556
+ *
557
+ * @param origin
558
+ * @param response
559
+ */
560
+ _onResponseFrom( origin, response ) {
561
+
562
+ const requestId = response.request.id
563
+ if ( !this._awaitingRequest.has( requestId ) ) { return }
564
+
565
+ const request = this._awaitingRequest.get( requestId )
566
+ this._awaitingRequest.delete( requestId )
567
+
568
+ clearTimeout( request.timeoutId )
569
+
570
+ const result = response.result
571
+ if ( isDefined( result ) ) {
572
+
573
+ if ( result.type === '_error' ) {
574
+ request.reject( result.error )
575
+ } else if ( result.type === '_data' ) {
576
+ request.resolve( result.data )
577
+ } else {
578
+ request.resolve( result )
579
+ }
580
+
581
+ } else {
582
+ request.resolve()
583
+ }
584
+
585
+ }
586
+
587
+ /**
588
+ *
589
+ * @param origin
590
+ * @param message
591
+ * @private
592
+ */
593
+
594
+ onErrorFrom( origin, message ) {
595
+ // Need to be reimplemented if needed
596
+ this.logger.error( `[${ this._localOriginUri }]: the origin [${ origin.uri }] send error => ${ JSON.stringify( message.error, null, 4 ) }. Need you to reimplement this method ?` )
597
+ }
598
+
599
+ /**
600
+ *
601
+ * @param origin
602
+ * @param message
603
+ */
604
+
605
+ onDataFrom( origin, message ) {
606
+ // Need to be reimplemented if needed
607
+ this.logger.log( `[${ this._localOriginUri }]: the origin [${ origin.uri }] send data => ${ JSON.stringify( message.data, null, 4 ) }. Need you to reimplement this method ?` )
608
+ }
609
+
610
+ /**
611
+ *
612
+ * @param origin
613
+ * @param message
614
+ */
615
+
616
+ onMessageFrom( origin, message ) {
617
+ // Need to be reimplemented if needed
618
+ this.logger.log( `[${ this._localOriginUri }]: the origin [${ origin.uri }] send custom message => ${ JSON.stringify( message, null, 4 ) }. Need you to reimplement this method ?` )
619
+ }
620
+
621
+ onEventFrom( origin, event ) {
622
+ const listeners = this._eventListeners[ event.name ]
623
+ for ( const listener of listeners ) {
624
+ listener( event.data )
625
+ }
626
+ }
627
+ // Send
628
+
629
+ /**
630
+ *
631
+ * @param originId
632
+ * @param ready
633
+ */
634
+ postReadyTo( originId, ready ) {
635
+
636
+ const _ready = ( ready && ready.constructor.isWebAPIMessageReady ) ? ready : new WebAPIMessageReady()
637
+ this.postMessageTo( originId, _ready, true )
638
+
639
+ }
640
+
641
+ /**
642
+ *
643
+ * @param originId
644
+ * @param request
645
+ * @param params
646
+ * @returns {Promise<unknown>}
647
+ */
648
+ postRequestTo( originId, request, ...params ) {
649
+
650
+ const _request = ( request && request.constructor.isWebAPIMessageRequest ) ? request : new WebAPIMessageRequest( request, params )
651
+
652
+ return new Promise( ( resolve, reject ) => {
653
+
654
+ try {
655
+
656
+ this._awaitingRequest.set( _request.id, {
657
+ request: _request,
658
+ resolve: resolve,
659
+ reject: reject,
660
+ timeoutId: setTimeout( () => {
661
+ this._awaitingRequest.delete( _request.id )
662
+ reject( new Error( `Request timeout for ${ JSON.stringify( _request, null, 4 ) }` ) )
663
+ //Todo send abort to avoid future return that won't be processed
664
+ }, this.requestTimeout )
665
+ } )
666
+
667
+ this.postMessageTo( originId, _request )
668
+
669
+ } catch ( error ) {
670
+
671
+ reject( error )
672
+
673
+ }
674
+
675
+ } )
676
+
677
+ }
678
+
679
+ /**
680
+ *
681
+ * @param originId
682
+ * @param request
683
+ * @param reponse
684
+ */
685
+ postResponseTo( originId, request, reponse ) {
686
+
687
+ const _response = ( reponse && reponse.constructor.isWebAPIMessageResponse ) ? reponse : new WebAPIMessageResponse( request, reponse )
688
+ this.postMessageTo( originId, _response )
689
+
690
+ }
691
+
692
+ /**
693
+ *
694
+ * @param originId
695
+ * @param error {WebAPIMessageError|String}
696
+ */
697
+ postErrorTo( originId, error ) {
698
+
699
+ const _error = ( error && error.constructor.isWebAPIMessageError ) ? error : new WebAPIMessageError( error )
700
+ this.postMessageTo( originId, _error )
701
+
702
+ }
703
+
704
+ /**
705
+ *
706
+ * @param originId
707
+ * @param data
708
+ */
709
+ postDataTo( originId, data ) {
710
+
711
+ const _data = ( data && data.constructor.isWebAPIMessageData ) ? data : new WebAPIMessageData( data )
712
+ this.postMessageTo( originId, _data )
713
+
714
+ }
715
+
716
+ /**
717
+ *
718
+ * @param originId
719
+ * @param message
720
+ * @param force
721
+ */
722
+ postMessageTo( originId, message, force = false ) {
723
+
724
+ if ( isNotDefined( originId ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: Unable to post message to null or undefined origin id !` ) }
725
+ if ( isNotDefined( message ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: Unable to post null or undefined message !` ) }
726
+
727
+ const origin = this._getAllowedOriginBy( 'id', originId )
728
+ if ( isNotDefined( origin ) ) { throw new ReferenceError( `[${ this._localOriginUri }]: Unable to retrieved origin with id: ${ originId }` ) }
729
+
730
+ try {
731
+
732
+ if ( !force && !origin.isReady ) {
733
+
734
+ this.logger.warn( `[${ this._localOriginUri }]: Origin [${ origin.uri }] is not ready yet !` )
735
+ origin.messageQueue.push( message )
736
+
737
+ } else if ( force && !origin.window ) {
738
+
739
+ this.logger.error( `[${ this._localOriginUri }]: Origin [${ origin.uri }] is unreachable !` )
740
+ // origin.isUnreachable = true
741
+ origin.messageQueue.push( message )
742
+
743
+ } else {
744
+
745
+ this.logger.log( `[${ this._localOriginUri }]: Send message of type '${ message.type }' to [${ origin.uri }]` )
746
+ origin.window.postMessage( JSON.stringify( message ), origin.uri )
747
+
748
+ }
749
+
750
+ } catch ( error ) {
751
+
752
+ this.logger.error( error )
753
+
754
+ }
755
+
756
+ }
757
+
758
+ postEvent( name = 'DefaultEventName', data ) {
759
+
760
+ const _data = ( data && data.constructor.isWebAPIMessageEvent ) ? data : new WebAPIMessageEvent( name, data )
761
+
762
+ // Broadcast to all potential listener
763
+ const allowedOrigins = this._allowedOrigins.filter( origin => origin !== '*' )
764
+ for ( let i = 0 ; i < allowedOrigins.length ; i++ ) {
765
+ const allowedOrigin = allowedOrigins[ i ]
766
+ const originId = allowedOrigin.id
767
+ this.postMessageTo( originId, _data )
768
+ }
769
+
770
+ }
771
+ }
772
+
773
+ export { WebAPI }