@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
JavaScript
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