ngx-gem-spaas
Version:
This library contains services, components, images and styles to provide a unified look and way-of-working throughout GEM SPaaS.
256 lines (248 loc) • 11.8 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Optional, Inject, Component, Input, HostListener, NgModule } from '@angular/core';
import { BaseComponent } from 'ngx-gem-spaas';
import * as autobahn from 'autobahn-browser';
import { DateTime } from 'luxon';
import { Subject } from 'rxjs';
import * as i2 from '@angular/material/tooltip';
import { MatTooltipModule } from '@angular/material/tooltip';
import { CommonModule } from '@angular/common';
class CrossbarResponseModel {
constructor(ts = '', topic = '') {
this.topic = '';
this.type = '';
this.received = ts || DateTime.now().toISO();
this.topic = topic;
}
}
class CrossbarSendModel {
constructor() {
this.type = '';
}
}
/**
* Crossbar configuration object to be provided via "forRoot" method.
*
* @property {string} xbarUrl the URL of your crossbar websocket server
* @property {string[]} xbarTopics the list of topics to listen to on the crossbar websocket server
* @property {string} xbarTopicsPrefix prefix to be added to all topics, usually indicating the environment.
* For example, on the Cylon xbar server, prefixes 'cb.preprod' and 'cb.prod' are used. Leave empty if none.
*/
class CrossbarConfigModel {
constructor(props) {
this.xbarUrl = '';
this.xbarTopics = [];
this.xbarTopicsPrefix = '';
this.xbarTopics = props.xbarTopics || [''];
this.xbarTopicsPrefix = props.xbarTopicsPrefix || '';
this.xbarUrl = props.xbarUrl || '';
}
}
// @ts-ignore
class CrossbarService {
constructor(crossbarConfig) {
this.crossbarConfig = crossbarConfig;
this.crossbarMsg$ = new Subject();
}
// ********************************************************************************************************
// AUTOBAHN
// ********************************************************************************************************
startConnection() {
if (!this.crossbarConfig?.xbarUrl || !this.crossbarConfig?.xbarTopics?.length) {
throw new Error('please provide a valid SpaasCrossbarConfigModel using the forRoot method of the SpaasCrossbarModule');
}
// CONNECT
this.crossbar = new autobahn.Connection({
url: this.crossbarConfig.xbarUrl,
realm: 'realm1',
headers: { 'Authorization': btoa('none:none') }
});
this.crossbar.open();
// CONNECT EVENTS
this.crossbar.onopen = (session) => {
// console.log('wsAutobahn opened');
this.crossbarSession = session;
const resp = new CrossbarResponseModel();
resp.data = 'websocket connected successfully';
resp.type = 'connected';
let topics = this.crossbarConfig.xbarTopics || [];
if (this.crossbarConfig.xbarTopicsPrefix) {
topics = topics.map((t) => this.crossbarConfig.xbarTopicsPrefix + '.' + t);
}
topics.forEach((topic) => session.subscribe(topic, (args, kwargs, details) => this.onChannelUpdate(args, kwargs, details)));
this.newWsMessage(resp);
};
// CLOSE EVENT
this.crossbar.onclose = (e) => {
const resp = new CrossbarResponseModel();
if (e.wasClean) {
console.log('wsAutobahn closed');
resp.data = 'disconnected';
resp.type = 'disconnected';
}
else {
console.log('wsAutobahn closed due to error');
// CLOSE WAS TRIGGERED BY AN ERROR (WS ERROR ALWAYS CALLS WS CLOSE)
if (this.crossbar.readyState !== 1) {
// FAILED CONNECTION
resp.data = 'Failed to connect. Is the server running and are you connected to the internet?';
resp.type = 'error';
}
else {
// OTHER ERROR
resp.data = JSON.stringify(e);
resp.type = 'error';
}
}
this.newWsMessage(resp);
};
// ERROR EVENT
this.crossbar.onerror = (e) => {
// TESTING ONLY
console.log(e);
};
// HARD DISCONNECT FROM BROWSER
return () => {
if (this.crossbar) {
this.crossbar.close();
}
};
}
onChannelUpdate(args, kwargs, details) {
const data = args[0];
const resp = new CrossbarResponseModel();
resp.data = data?.data || data;
resp.topic = details.topic ? details.topic.replace(this.crossbarConfig.xbarTopicsPrefix + '.', '') : '';
resp.type = data?.type || '';
this.newWsMessage(resp);
}
stopConnection() {
if (this.crossbar) {
this.crossbar.close();
}
}
sendMessage(topic, e, excludeMe = false) {
if (this.crossbar) {
this.crossbarSession.publish(this.crossbarConfig.xbarTopicsPrefix ? this.crossbarConfig.xbarTopicsPrefix + '.' + topic : topic, [e], null, { exclude_me: excludeMe });
}
}
// ********************************************************************************************************
// BROADCAST DATA
// ********************************************************************************************************
newWsMessage(msg) {
// console.log(msg);
this.crossbarMsg$.next(msg);
}
onNewWsMessage() {
return this.crossbarMsg$.asObservable();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CrossbarService, deps: [{ token: CrossbarConfigModel, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CrossbarService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CrossbarService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: CrossbarConfigModel, decorators: [{
type: Optional
}, {
type: Inject,
args: [CrossbarConfigModel]
}] }] });
/**
* This component creates the connection to the crossbar websocket server and
* shows a state indicator in the bottom left corner of your app.
* */
class CrossbarStateComponent extends BaseComponent {
constructor(crossbarService) {
super();
this.crossbarService = crossbarService;
this.fromBottomPx = 14;
this.crossbarActive = false;
}
onFocus() {
// ALSO CHECK IF TAB IS VISIBLE
if (document.visibilityState !== 'hidden') {
this.crossbarConnect();
}
}
ngOnInit() {
this.crossbarConnect();
}
ngOnDestroy() {
this.crossbarService.stopConnection();
super.ngOnDestroy();
}
// ********************************************************************************************************
// LOADING DATA
// ********************************************************************************************************
crossbarConnect() {
if (!this.crossbarService.crossbar || !this.crossbarService.crossbar.isConnected || !this.crossbarService.crossbar.isOpen) {
this.crossbarService.startConnection();
this.wsCrossbarSubscribe();
}
else {
this.crossbarActive = true;
}
}
wsCrossbarSubscribe() {
this.crossbarService.onNewWsMessage()
.subscribe((responseData) => {
if (responseData.type === 'connected') {
// DO NOTHING, JUST WS CONNECTING
this.crossbarActive = true;
}
else if (responseData.type === 'error' || responseData.type === 'disconnected') {
// DO NOTHING, ERROR OR DISCONNECT => XBAR RECONNECTS AUTOMATICALLY
this.crossbarActive = false;
}
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CrossbarStateComponent, deps: [{ token: CrossbarService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CrossbarStateComponent, selector: "spaas-crossbar", inputs: { fromBottomPx: "fromBottomPx" }, host: { listeners: { "window:focus": "onFocus($event)" } }, usesInheritance: true, ngImport: i0, template: "<div [class.nok]=\"!crossbarActive\"\r\n [class.ok]=\"crossbarActive\"\r\n [style.bottom.px]=\"fromBottomPx\"\r\n class=\"ws-state\"\r\n matTooltip=\"{{crossbarActive ? '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: "17.3.12", ngImport: i0, type: CrossbarStateComponent, decorators: [{
type: Component,
args: [{ selector: 'spaas-crossbar', template: "<div [class.nok]=\"!crossbarActive\"\r\n [class.ok]=\"crossbarActive\"\r\n [style.bottom.px]=\"fromBottomPx\"\r\n class=\"ws-state\"\r\n matTooltip=\"{{crossbarActive ? 'live update OK' : 'live update NOK'}}\">\r\n</div>\r\n" }]
}], ctorParameters: () => [{ type: CrossbarService }], propDecorators: { fromBottomPx: [{
type: Input
}], onFocus: [{
type: HostListener,
args: ['window:focus', ['$event']]
}] } });
class SpaasCrossbarModule {
static forRoot(config) {
return {
ngModule: SpaasCrossbarModule,
providers: [{ provide: CrossbarConfigModel, useValue: config }]
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasCrossbarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: SpaasCrossbarModule, declarations: [CrossbarStateComponent], imports: [CommonModule,
MatTooltipModule], exports: [CrossbarStateComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasCrossbarModule, imports: [CommonModule,
MatTooltipModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasCrossbarModule, decorators: [{
type: NgModule,
args: [{
declarations: [
CrossbarStateComponent,
],
exports: [
CrossbarStateComponent,
],
imports: [
CommonModule,
MatTooltipModule,
],
providers: []
}]
}] });
// MODULE
/**
* Generated bundle index. Do not edit.
*/
export { CrossbarConfigModel, CrossbarResponseModel, CrossbarSendModel, CrossbarService, CrossbarStateComponent, SpaasCrossbarModule };
//# sourceMappingURL=ngx-gem-spaas-crossbar.mjs.map