All files / src/app/core/utils/feature-event feature-event.service.ts

50% Statements 13/26
0% Branches 0/5
11.11% Functions 1/9
52.17% Lines 12/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114  7x 7x 7x   7x                                             7x         7x 35x 35x   35x   35x         35x         35x                                                                                                                                
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Injectable, InjectionToken, Injector, inject } from '@angular/core';
import { Observable, Subject, switchMap } from 'rxjs';
import { v4 as uuid } from 'uuid';
 
import { FeatureToggleService, FeatureToggleType } from 'ish-core/feature-toggle.module';
import { InjectMultiple } from 'ish-core/utils/injection';
 
export interface FeatureEventResultListener {
  feature: string;
  event: string;
  resultListener$(id: string): Observable<FeatureEventResult>;
}
 
export interface FeatureEventResult {
  id: string;
  event: string;
  successful: boolean;
  data?: any;
}
 
export interface FeatureEventNotifier {
  id: string;
  feature: string;
  event: string;
  data?: any;
}
 
export const FEATURE_EVENT_RESULT_LISTENER = new InjectionToken<FeatureEventResultListener>(
  'featureEventResultListener'
);
 
@Injectable({ providedIn: 'root' })
export class FeatureEventService {
  private internalEventNotifier$ = new Subject<FeatureEventNotifier>();
  private internalEventResult$ = new Subject<FeatureEventResult>();
 
  private eventListeners: FeatureEventResultListener[] = [];
 
  private featureToggleService = inject(FeatureToggleService);
 
  /**
   * Event stream to notify extensions for further actions
   */
  eventNotifier$ = this.internalEventNotifier$.asObservable();
 
  /**
   * Event stream to notify for event results
   */
  eventResults$ = this.internalEventResult$.asObservable();
 
  /**
   * Will send new notification to event stream. Subscriber (extensions) to this event stream could react accordingly.
   * @param feature responsible extension
   * @param event event type
   * @param data optional data for event
   * @returns identifier of generated event
   */
  sendNotification(feature: string, event: string, data?: any): string {
    const id = uuid();
    this.internalEventNotifier$.next({ id, feature, event, data });
    return id;
  }
 
  /**
   * Will send results of event back. Subscriber (event trigger) to this result stream could react accordingly.
   * @param id identifier of generated even
   * @param event event type
   * @param successful Is result successful?
   * @param data optional data for event
   */
  sendResult(id: string, event: string, successful: boolean, data?: any) {
    this.internalEventResult$.next({ id, event, successful, data });
  }
 
  /**
   * Will append all configured FEATURE_EVENT_RESULT_LISTENER together to be available in the FeatureEventNotifierService
   * @param injector current injector instance
   */
  setupAvailableResultListener(injector: Injector) {
    // get all configured result listener by FEATURE_EVENT_RESULT_LISTENER injection token from current injector instance
    const eventListeners = injector.get<InjectMultiple<typeof FEATURE_EVENT_RESULT_LISTENER>>(
      FEATURE_EVENT_RESULT_LISTENER,
      []
    );
 
    // append configured listener to available eventListeners list in case it is not yet available
    eventListeners.forEach(eventListener => {
      Iif (this.eventListeners.find(el => el.feature === eventListener.feature && el.event === eventListener.event)) {
        return;
      }
 
      this.eventListeners.push(eventListener);
    });
  }
 
  /**
   * Find correct event result listener
   * @param feature responsible extension
   * @param event event type
   * @param id id of generated notification event
   * @returns result listener stream, which should notify about results of notification event
   */
  eventResultListener$(feature: FeatureToggleType, event: string, id: string): Observable<FeatureEventResult> {
    return this.featureToggleService
      .enabled$(feature)
      .pipe(
        switchMap(() =>
          this.eventListeners.find(el => el.feature === feature && el.event === event)?.resultListener$(id)
        )
      );
  }
}