UNPKG

@engie-group/ngx-gem-spaas

Version:

This library contains services, components, images and styles to provide a unified look and way-of-working throughout GEM SPaaS.

253 lines (245 loc) 11.4 kB
import * as i0 from '@angular/core'; import { Injectable, Optional, Inject, Component, Input, HostListener, NgModule } from '@angular/core'; import * as i2 from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip'; import { CommonModule } from '@angular/common'; import * as i1 from '@engie-group/ngx-gem-spaas'; import { BaseComponent } from '@engie-group/ngx-gem-spaas'; import { takeUntil } from 'rxjs/operators'; import * as signalr from '@microsoft/signalr'; import { HubConnectionState } from '@microsoft/signalr'; import { ReplaySubject } from 'rxjs'; import { DateTime } from 'luxon'; /** * SignalR state object provided by the signalrService.onNewState observable * * @property {HubConnectionState} state the actual state of the signalr hub connection * @property {string} message any additional info received from SignalR on state change events */ class SignalrStateModel { } /** * SignalR response object provided by the signalrService.onNewMessage observable * * @property {any} data the actual data received from the SignalR hub connection * @property {string} received the ISO timestamp of when the event was received * @property {string} type the type of the event, which matches the event name as given in the * SignalR configuration model via the signalrEvents list */ class SignalrResponseModel { constructor(ts = '') { this.type = ''; this.received = ts || DateTime.now().toISO(); } } class SignalrSendModel { constructor() { this.type = ''; } } /** * SignalR configuration object to be provided via "forRoot" method. * * @property {string} signalrUrl the URL of your SignalR hub * @property {string[]} signalrEvents the list of events to listen to on the SignalR hub */ class SignalrConfigModel { constructor(props) { this.signalrUrl = ''; this.signalrEvents = []; this.signalrEvents = props.signalrEvents || ['']; this.signalrUrl = props.signalrUrl || ''; } } class SignalrService { constructor(signalrConfig, oktaService) { this.signalrConfig = signalrConfig; this.oktaService = oktaService; this.signalrMsg$ = new ReplaySubject(1); this.signalrState$ = new ReplaySubject(1); if (!this.signalrConfig?.signalrUrl || !this.signalrConfig?.signalrEvents?.length) { throw new Error('please provide a valid SpaasSignalrConfigModel using the forRoot method of the SpaasSignalrModule'); } this.buildConnection(); } buildConnection() { this.signalrHubConnection = new signalr.HubConnectionBuilder() .withUrl(this.signalrConfig?.signalrUrl, { accessTokenFactory: () => this.oktaService.getCachedAccessToken(), // logger: new MyLogger(), withCredentials: false, }) .withAutomaticReconnect({ nextRetryDelayInMilliseconds(retryContext) { // divide by 30 seconds to increment more aggressively. Could be switched to 60 for less steep incrementing // floor at 2 seconds, cap at 2 minutes return Math.min(Math.max(Math.ceil(retryContext.elapsedMilliseconds / 30), 2000), 120000); } }) .build(); } startConnection() { this.signalrHubConnection.start() .then(() => { this.newState('signalr connected'); this.listenToMessages(); }) .catch((error) => { this.newState('signalr failed to connect: ' + error); }); } listenToMessages() { // state related events this.signalrHubConnection.onclose((error) => { const errStr = error ? ' with error: ' + error : ' intentionally'; this.newState('signalr closed' + errStr); }); this.signalrHubConnection.onreconnecting((error) => { const errStr = error ? '. Reason for disconnect: ' + error : ''; this.newState('signalr disconnected, starting reconnection process' + errStr); }); this.signalrHubConnection.onreconnected(() => { this.newState('signalr reconnected successfully'); }); // user provided events for (const t of this.signalrConfig?.signalrEvents) { this.signalrHubConnection.on(t, (msg) => { const resp = new SignalrResponseModel(); resp.type = t; resp.data = msg; this.signalrMsg$.next(resp); }); } } stopConnection() { this.signalrHubConnection.stop() .then(() => { // no need to do anything, the "onclose" will fire }) .catch((error) => { this.newState('signalr connection closing failed: ' + error); }); } sendMessage(msg) { this.signalrHubConnection.invoke(msg.type, msg.data); } // ******************************************************************************************************** // BROADCAST DATA // ******************************************************************************************************** onNewMessage() { return this.signalrMsg$.asObservable(); } newState(msg) { this.signalrState$.next({ state: this.signalrHubConnection?.state, message: msg || '', }); } onNewState() { return this.signalrState$.asObservable(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SignalrService, deps: [{ token: SignalrConfigModel, optional: true }, { token: i1.OktaService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SignalrService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SignalrService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: SignalrConfigModel, decorators: [{ type: Optional }, { type: Inject, args: [SignalrConfigModel] }] }, { type: i1.OktaService }] }); /** * This component creates the connection to the SignalR hub and * shows a state indicator in the bottom left corner of your app. * */ class SignalrStateComponent extends BaseComponent { constructor(signalrService) { super(); this.signalrService = signalrService; this.fromBottomPx = 14; this.signalrActive = false; this.getSignalrState(); } onFocus() { // ALSO CHECK IF TAB IS VISIBLE if (document.visibilityState !== 'hidden') { this.signalrConnect(); } } ngOnInit() { this.signalrConnect(); } ngOnDestroy() { this.signalrService.stopConnection(); super.ngOnDestroy(); } // ******************************************************************************************************** // LOADING DATA // ******************************************************************************************************** // AUTOBAHN signalrConnect() { if (this.signalrService.signalrHubConnection?.state !== HubConnectionState.Connected) { this.signalrService.startConnection(); } else { this.signalrActive = true; } } getSignalrState() { this.signalrService.onNewState() .pipe(takeUntil(this.onDestroy$)) .subscribe((state) => { this.signalrActive = state?.state === HubConnectionState.Connected; }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SignalrStateComponent, deps: [{ token: SignalrService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: SignalrStateComponent, isStandalone: false, selector: "spaas-signalr", inputs: { fromBottomPx: "fromBottomPx" }, host: { listeners: { "window:focus": "onFocus($event)" } }, usesInheritance: true, ngImport: i0, template: "<div [class.nok]=\"!signalrActive\"\r\n [class.ok]=\"signalrActive\"\r\n [style.bottom.px]=\"fromBottomPx\"\r\n class=\"ws-state\"\r\n matTooltip=\"{{signalrActive ? 'live update OK' : 'live update NOK'}}\">\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SignalrStateComponent, decorators: [{ type: Component, args: [{ selector: 'spaas-signalr', standalone: false, template: "<div [class.nok]=\"!signalrActive\"\r\n [class.ok]=\"signalrActive\"\r\n [style.bottom.px]=\"fromBottomPx\"\r\n class=\"ws-state\"\r\n matTooltip=\"{{signalrActive ? 'live update OK' : 'live update NOK'}}\">\r\n</div>\r\n" }] }], ctorParameters: () => [{ type: SignalrService }], propDecorators: { fromBottomPx: [{ type: Input }], onFocus: [{ type: HostListener, args: ['window:focus', ['$event']] }] } }); class SpaasSignalrModule { static forRoot(config) { return { ngModule: SpaasSignalrModule, providers: [{ provide: SignalrConfigModel, useValue: config }] }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SpaasSignalrModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.5", ngImport: i0, type: SpaasSignalrModule, declarations: [SignalrStateComponent], imports: [CommonModule, MatTooltipModule], exports: [SignalrStateComponent] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SpaasSignalrModule, imports: [CommonModule, MatTooltipModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SpaasSignalrModule, decorators: [{ type: NgModule, args: [{ declarations: [ SignalrStateComponent, ], exports: [ SignalrStateComponent, ], imports: [ CommonModule, MatTooltipModule, ], providers: [] }] }] }); // MODULE /** * Generated bundle index. Do not edit. */ export { SignalrConfigModel, SignalrResponseModel, SignalrSendModel, SignalrService, SignalrStateComponent, SignalrStateModel, SpaasSignalrModule }; //# sourceMappingURL=engie-group-ngx-gem-spaas-signalr.mjs.map