anear-js-api 0.4.36 → 0.4.37

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.
@@ -218,6 +218,12 @@ const AnearCoreServiceMachineFunctions = {
218
218
  anearEventMachines: (context, event) => {
219
219
  const eventJSON = JSON.parse(event.data)
220
220
  const anearEvent = new AnearEvent(eventJSON)
221
+
222
+ if (context.anearEventMachines[anearEvent.id]) {
223
+ logger.info(`[ACSM] Event machine for ${anearEvent.id} already exists. Ignoring CREATE_EVENT.`)
224
+ return context.anearEventMachines
225
+ }
226
+
221
227
  const service = AnearEventMachine(anearEvent, context)
222
228
 
223
229
  return {
@@ -57,8 +57,6 @@ const AnearEventMachineContext = (
57
57
  participantMachines: {}
58
58
  })
59
59
 
60
- const MinuteMsecs = minutes => minutes * (60 * 1000)
61
-
62
60
  const DeferredStates = [
63
61
  'PARTICIPANT_ENTER',
64
62
  'PARTICIPANT_LEAVE',
@@ -198,13 +196,21 @@ const ActiveEventStatesConfig = {
198
196
  invoke: {
199
197
  src: 'renderDisplay',
200
198
  onDone: {
201
- target: '#waitingAnnounce',
199
+ target: 'notifyingRenderComplete',
202
200
  internal: true
203
201
  },
204
202
  onError: {
205
203
  target: '#activeEvent.failure'
206
204
  }
207
205
  }
206
+ },
207
+ notifyingRenderComplete: {
208
+ after: {
209
+ timeoutRendered: {
210
+ target: '#waitingAnnounce',
211
+ actions: ['notifyAppMachineRendered']
212
+ }
213
+ }
208
214
  }
209
215
  }
210
216
  },
@@ -282,7 +288,7 @@ const ActiveEventStatesConfig = {
282
288
  invoke: {
283
289
  src: 'renderDisplay',
284
290
  onDone: {
285
- target: '#waitingToStart',
291
+ target: 'notifyingRenderComplete',
286
292
  internal: true
287
293
  },
288
294
  onError: {
@@ -307,6 +313,14 @@ const ActiveEventStatesConfig = {
307
313
  }
308
314
  }
309
315
  },
316
+ notifyingRenderComplete: {
317
+ after: {
318
+ timeoutRendered: {
319
+ target: '#waitingToStart',
320
+ actions: ['notifyAppMachineRendered']
321
+ }
322
+ }
323
+ },
310
324
  waitParticipantReady: {
311
325
  id: 'waitParticipantReady',
312
326
  deferred: DeferredStatesPlus('START'),
@@ -339,7 +353,7 @@ const ActiveEventStatesConfig = {
339
353
  }
340
354
  ],
341
355
  PARTICIPANT_TIMEOUT: {
342
- action: ['processParticipantTimeout']
356
+ actions: ['processParticipantTimeout']
343
357
  },
344
358
  PAUSE: '#activeEvent.paused', // Currently no use-case for these
345
359
  CLOSE: '#activeEvent.closeEvent' // AppM explicitly closed the event
@@ -391,7 +405,7 @@ const ActiveEventStatesConfig = {
391
405
  invoke: {
392
406
  src: 'renderDisplay',
393
407
  onDone: {
394
- target: '#waitingForActions',
408
+ target: 'notifyingRenderComplete',
395
409
  internal: true
396
410
  },
397
411
  onError: {
@@ -399,6 +413,14 @@ const ActiveEventStatesConfig = {
399
413
  }
400
414
  }
401
415
  },
416
+ notifyingRenderComplete: {
417
+ after: {
418
+ timeoutRendered: {
419
+ target: '#waitingForActions',
420
+ actions: ['notifyAppMachineRendered']
421
+ }
422
+ }
423
+ },
402
424
  participantEntering: {
403
425
  // a PARTICIPANT_ENTER received from a new user JOIN click. Unless already exists,
404
426
  // create an AnearParticipantMachine instance.
@@ -455,47 +477,40 @@ const ActiveEventStatesConfig = {
455
477
  },
456
478
  closeEvent: {
457
479
  id: 'closeEvent',
458
- initial: 'eventTransitionClosed',
480
+ initial: 'notifyingParticipants',
459
481
  states: {
460
- eventTransitionClosed: {
461
- invoke: {
462
- src: 'eventTransitionClosed',
463
- onDone: 'waitForParticipantsToExit',
464
- onError: '#activeEvent.failure'
465
- }
482
+ notifyingParticipants: {
483
+ entry: 'sendParticipantExitEvents',
484
+ always: 'waitForParticipantsToExit'
466
485
  },
467
486
  waitForParticipantsToExit: {
468
- on: {
469
- ANNOUNCE: {
470
- actions: () => logger.debug('[AEM] ANNOUNCE received in closeEvent state; too late - already shutting down')
471
- },
472
- START: {
473
- actions: () => logger.debug('[AEM] START received in closeEvent state; too late - already shutting down')
474
- },
475
- CLOSE: {
476
- actions: () => logger.debug('[AEM] CLOSE received in closeEvent state; ignoring redundant event')
477
- },
478
- CANCEL: {
479
- actions: () => logger.debug('[AEM] CANCEL received in closeEvent state; ignoring redundant event')
480
- },
481
- PARTICIPANT_LEAVE: {
482
- actions: ['sendExitToParticipantMachine']
483
- }
484
- },
487
+ entry: context => logger.debug(`[AEM] Entering waitForParticipantsToExit with ${Object.keys(context.participants).length} participants`),
485
488
  always: [
486
489
  {
487
490
  cond: context => Object.keys(context.participants).length === 0,
488
- target: 'detaching'
491
+ target: 'finalizing'
492
+ }
493
+ ],
494
+ on: {
495
+ PARTICIPANT_LEAVE: {
496
+ actions: () => logger.debug('[AEM] Ignoring PARTICIPANT_LEAVE during orchestrated shutdown.')
489
497
  }
490
- ]
498
+ }
499
+ },
500
+ finalizing: {
501
+ deferred: DeferredStates,
502
+ invoke: {
503
+ src: 'eventTransitionClosed',
504
+ onDone: 'detaching',
505
+ onError: '#activeEvent.failure'
506
+ }
491
507
  },
492
508
  detaching: {
493
509
  deferred: DeferredStates,
494
510
  invoke: {
495
511
  src: 'detachChannels',
496
512
  onDone: {
497
- target: '#activeEvent.doneExit',
498
- actions: ['notifyAppMachineShutdown']
513
+ target: '#activeEvent.doneExit'
499
514
  }
500
515
  }
501
516
  }
@@ -503,47 +518,45 @@ const ActiveEventStatesConfig = {
503
518
  },
504
519
  canceled: {
505
520
  id: 'canceled',
506
- initial: 'eventTransitionCanceled',
521
+ initial: 'notifyingParticipants',
522
+ on: {
523
+ CLOSE: {
524
+ actions: () => logger.debug('[AEM] Ignoring CLOSE during cancel.')
525
+ }
526
+ },
507
527
  states: {
508
- eventTransitionCanceled: {
509
- invoke: {
510
- src: 'eventTransitionCanceled',
511
- onDone: 'waitForParticipantsToExit',
512
- onError: '#activeEvent.failure'
513
- }
528
+ notifyingParticipants: {
529
+ entry: 'sendParticipantExitEvents',
530
+ always: 'waitForParticipantsToExit'
514
531
  },
515
532
  waitForParticipantsToExit: {
516
- on: {
517
- ANNOUNCE: {
518
- actions: () => logger.debug('[AEM] ANNOUNCE received in canceled state; too late - already canceled')
519
- },
520
- START: {
521
- actions: () => logger.debug('[AEM] START received in canceled state; too late - already canceled')
522
- },
523
- CLOSE: {
524
- actions: () => logger.debug('[AEM] CLOSE received in canceled state; ignoring redundant event')
525
- },
526
- CANCEL: {
527
- actions: () => logger.debug('[AEM] CANCEL received in canceled state; ignoring redundant event')
528
- },
529
- PARTICIPANT_LEAVE: {
530
- actions: ['sendExitToParticipantMachine']
531
- }
532
- },
533
+ entry: context => logger.debug(`[AEM] Entering waitForParticipantsToExit with ${Object.keys(context.participants).length} participants`),
533
534
  always: [
534
535
  {
535
536
  cond: context => Object.keys(context.participants).length === 0,
536
- target: 'detaching'
537
+ target: 'finalizing'
538
+ }
539
+ ],
540
+ on: {
541
+ PARTICIPANT_LEAVE: {
542
+ actions: () => logger.debug('[AEM] Ignoring PARTICIPANT_LEAVE during orchestrated shutdown.')
537
543
  }
538
- ]
544
+ }
545
+ },
546
+ finalizing: {
547
+ deferred: DeferredStates,
548
+ invoke: {
549
+ src: 'eventTransitionCanceled',
550
+ onDone: 'detaching',
551
+ onError: '#activeEvent.failure'
552
+ }
539
553
  },
540
554
  detaching: {
541
555
  deferred: DeferredStates,
542
556
  invoke: {
543
557
  src: 'detachChannels',
544
558
  onDone: {
545
- target: '#activeEvent.doneExit',
546
- actions: ['notifyAppMachineShutdown']
559
+ target: '#activeEvent.doneExit'
547
560
  },
548
561
  onError: {
549
562
  target: '#activeEvent.failure'
@@ -714,11 +727,10 @@ const AnearEventMachineFunctions = ({
714
727
  return service.start()
715
728
  }
716
729
  }),
717
- notifyAppMachineShutdown: (context, event) => {
718
- // Send TERMINATED to AppM when shutdown is complete
730
+ notifyAppMachineRendered: (context, event) => {
719
731
  if (context.appEventMachine) {
720
- logger.debug('[AEM] Sending TERMINATED to AppM - shutdown complete')
721
- context.appEventMachine.send('TERMINATED')
732
+ logger.debug('[AEM] Sending RENDERED to AppM')
733
+ context.appEventMachine.send('RENDERED')
722
734
  }
723
735
  },
724
736
  createEventChannel: assign({
@@ -827,6 +839,8 @@ const AnearEventMachineFunctions = ({
827
839
  if (participantMachine) {
828
840
  logger.debug("[AEM] sending PARTICIPANT_EXIT to ", participantMachine.id)
829
841
  participantMachine.send('PARTICIPANT_EXIT')
842
+ } else {
843
+ logger.warn(`[AEM] Participant machine not found for id ${event.data.id} during sendExitToParticipantMachine`)
830
844
  }
831
845
  },
832
846
  sendParticipantExitToAppEventMachine: (context, event) => {
@@ -1028,7 +1042,14 @@ const AnearEventMachineFunctions = ({
1028
1042
  // The remote client has left the event. This is a permanent exit
1029
1043
  // from the event
1030
1044
  const type = event.data.type
1031
- return type === 'PARTICIPANT_EXIT' || type === 'EVENT_UNMOUNT'
1045
+ switch (type) {
1046
+ case 'PARTICIPANT_EXIT':
1047
+ case 'EVENT_UNMOUNT':
1048
+ case 'TRANSITION_CLOSED':
1049
+ return true
1050
+ default:
1051
+ return false
1052
+ }
1032
1053
  },
1033
1054
  participantExists: (context, event) => !!context.participants[event.data.id],
1034
1055
  eventCreatorIsHost: (context, event) => context.anearEvent.hosted,
@@ -1037,8 +1058,9 @@ const AnearEventMachineFunctions = ({
1037
1058
  delays: {
1038
1059
  // in the future, these delays should be goverened by the type of App and
1039
1060
  // if there has been activity.
1040
- timeoutEventAnnounce: context => MinuteMsecs(C.TIMEOUT_MINUTES.ANNOUNCE),
1041
- timeoutEventStart: context => MinuteMsecs(C.TIMEOUT_MINUTES.START)
1061
+ timeoutEventAnnounce: context => C.TIMEOUT_MSECS.ANNOUNCE,
1062
+ timeoutEventStart: context => C.TIMEOUT_MSECS.START,
1063
+ timeoutRendered: context => C.TIMEOUT_MSECS.RENDERED_EVENT_DELAY
1042
1064
  }
1043
1065
  })
1044
1066
 
@@ -293,7 +293,7 @@ const AnearParticipantMachineFunctions = {
293
293
  },
294
294
  delays: {
295
295
  actionTimeout: context => context.actionTimeoutMsecs,
296
- reconnectTimeout: _c => C.TIMEOUT_SECONDS.RECONNECT * 1000 // client must reconnect in this time
296
+ reconnectTimeout: _c => C.TIMEOUT_MSECS.RECONNECT // client must reconnect in this time
297
297
  }
298
298
  }
299
299
 
@@ -23,8 +23,9 @@ const AppMachineTransition = (anearEvent) => {
23
23
  // Check if AppM has reached a final state (handle different XState versions)
24
24
  const isDone = appEventMachineState?.done || appEventMachineState?.value === 'done'
25
25
 
26
- // Process meta FIRST (including exit displays) before sending CLOSE
27
- if (metaObjects.length > 0) {
26
+ // Process meta FIRST (including exit displays) before sending CLOSE.
27
+ // Do not re-process meta on the RENDERED event from AEM to avoid an infinite loop.
28
+ if (event.type !== 'RENDERED' && metaObjects.length > 0) {
28
29
  const appStateName = _stringifiedState(value)
29
30
 
30
31
  const displayEvents = []
@@ -7,11 +7,17 @@ module.exports = {
7
7
  ImagesDirPath: 'assets/images',
8
8
  CssDirPath: 'assets/css',
9
9
  PugSuffix: '.pug',
10
- TIMEOUT_MINUTES: {
11
- START: 60, // 1 hour
12
- ANNOUNCE: 120 // 2 hours
10
+ TIMEOUT_MSECS: {
11
+ ANNOUNCE: 5 * 60 * 1000, // 5 minutes
12
+ START: 5 * 60 * 1000, // 5 minutes
13
+ RENDERED_EVENT_DELAY: 100, // 100 milliseconds
14
+ RECONNECT: 30 * 1000 // 30 seconds
13
15
  },
14
- TIMEOUT_SECONDS: {
15
- RECONNECT: 30
16
+ EventStates: {
17
+ CREATED: 'created',
18
+ STARTED: 'started',
19
+ ENDED: 'ended',
20
+ CANCELLED: 'cancelled',
21
+ FAILED: 'failed'
16
22
  }
17
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anear-js-api",
3
- "version": "0.4.36",
3
+ "version": "0.4.37",
4
4
  "description": "Javascript Developer API for Anear Apps",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {