/*-------------------------------------------------------------------------------------------------------------- * Copyright (c) insite-gmbh. All rights reserved. * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------------------------*/ import { Injectable, Inject, ReflectiveInjector } from '@angular/core'; import { Observable, Subscription } from 'rxjs/Rx'; import { InaxConfiguration} from '../inaxConfiguration' import { Subject} from "rxjs/Subject"; import { ProfileService } from "../serviceAuthentication/profile.service"; import { Map } from "../types/map"; import { IHubService, IHUBSERVICE_TOKEN } from "./signalRServices"; //import { Window } from './../../../plc/test/mockClasses/mockWindow'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { IInaxConfig, IINAXCONFIGSERVICE_TOKEN, IInaxConfigService } from '../interfaces/IInaxConfigService.interface'; import { Guid } from '../guid'; /** * When SignalR runs it will add functions to the global $ variable * that you use to create connections to the hub. However, in this * class we won't want to depend on any global variables, so this * class provides an abstraction away from using $ directly in here. */ export class SignalrWindow extends Window { $: any; } export enum ConnectionState { Connecting = 1, Connected = 2, Reconnecting = 3, Disconnected = 4 } @Injectable() export class InaxSignalR{ private _hubConnection: any = null; private _connectionStateSubject = new Subject(); private _startingSubject = new Subject(); private _errorSubject = new Subject(); private _configSubscription: Subscription; private _configuration: InaxConfiguration; private _initialized: boolean = false; private _state: ConnectionState = ConnectionState.Disconnected; private _subscribtionId : Guid; private _hubProxies: Map = {}; public get isInitialized(): boolean{ return this._initialized; } public get state():ConnectionState{ return this._state; } public isHubConnected(hubName:string):boolean{ if(this._hubProxies[hubName] != null){ return this.state == ConnectionState.Connected; } return false; } /** * starting$ is an observable available to know if the signalr * connection is ready or not. On a successful connection this * stream will emit a value. */ public starting: Observable; /** * connectionState$ provides the current state of the underlying * connection as an observable stream. */ public connectionState: Observable; /** * error$ provides a stream of any error messages that occur on the * SignalR connection */ public error: Observable; constructor( @Inject(IHUBSERVICE_TOKEN) private _hubServices:IHubService[], @Inject(IINAXCONFIGSERVICE_TOKEN) private _configurationService: IInaxConfigService, private _window: SignalrWindow, private _profileService: ProfileService ) { this._subscribtionId = _profileService.addSubscriber( () => this.start()); this._configSubscription = _configurationService .getConfiguration() .subscribe( (configSettings: IInaxConfig) => { //TODO: may use the interface !!! this._configuration = _configurationService as InaxConfiguration; if (configSettings.UseSignalR) this.initialize(); else this.release(); }); } /** * stop signalR */ private release(){ try{ if(this._hubConnection != null){ this._hubConnection.stop(); this._initialized = false; } }catch(error){ console.error(`Could not stop SignalR because of an error: ${error}`); } } /** * initialize the components */ private initialize(){ if (this._window.$ === undefined || this._window.$.hubConnection === undefined) { throw new Error("The variable '$' or the .hubConnection() function are not defined...please check the SignalR scripts have been loaded properly"); } // Set up our observables this.connectionState = this._connectionStateSubject.asObservable(); this.error = this._errorSubject.asObservable(); this.starting = this._startingSubject.asObservable(); this._hubConnection = this._window.$.hubConnection(); this._hubConnection.url = this._configuration.ServerWithSignalRUrl; this.createHubProxies(); // Define handlers for the connection state events this._hubConnection.stateChanged((state: any) => { let newState = ConnectionState.Connecting; switch (state.newState) { case this._window.$.signalR.connectionState.connecting: newState = ConnectionState.Connecting; break; case this._window.$.signalR.connectionState.connected: newState = ConnectionState.Connected; break; case this._window.$.signalR.connectionState.reconnecting: newState = ConnectionState.Reconnecting; break; case this._window.$.signalR.connectionState.disconnected: newState = ConnectionState.Disconnected; break; } // Push the new state on our subject this._state = newState; this._connectionStateSubject.next(newState); }); // Define handlers for any errors this._hubConnection.error((error: any) => { // Push the error on our subject this._errorSubject.next(error); }); this._hubServices.forEach(service => { if(service != null){ service.registerEvents(this); } }); if(this._profileService.ensureAuthenticated()){ this.start(); } this._initialized = true; } /** * creats a hubproxy with the given name. */ public createHubProxy(name: string) : any{ if(this._hubConnection != null) return this._hubConnection.createHubProxy(name); return null; } public createHubProxies(){ this._configuration.EnabledSignalRHubs.forEach(element => { this._hubProxies[element] = this.createHubProxy(element); }); } public getHubProxy(name: string): any{ return this._hubProxies[name]; } /** * Start the SignalR connection. The starting$ stream will emit an * event if the connection is established, otherwise it will emit an * error. */ private start(): void { // Now we only want the connection started once, so we have a special // starting$ observable that clients can subscribe to know know if // if the startup sequence is done. // // If we just mapped the start() promise to an observable, then any time // a client subscried to it the start sequence would be triggered // again since it's a cold observable. let token = this._profileService.getToken(); if(token != null) this._hubConnection.qs = { BearerToken : token }; this._hubConnection.start() .done(() => { this._startingSubject.next(null); }) .fail((error: any) => { this._startingSubject.error(error); }); } }