UNPKG

webstomp-obs

Version:

Stomp over websocket using observable

97 lines (80 loc) 4.01 kB
import { Observer } from 'rxjs/Observer'; import { Observable } from 'rxjs/Observable'; import { ConnectableObservable } from 'rxjs/Observable/ConnectableObservable'; import { ReplaySubject } from 'rxjs/ReplaySubject'; import 'rxjs/add/observable/timer'; import 'rxjs/add/observable/of'; import 'rxjs/add/observable/throw'; import 'rxjs/add/operator/multicast'; import 'rxjs/add/operator/retryWhen'; import 'rxjs/add/operator/scan'; import 'rxjs/add/operator/do'; import 'rxjs/add/operator/catch'; import { ConnectedClient } from './connectedClient'; import { ConnectionHeaders } from './headers'; import WebSocketHandler from './webSocketHandler'; import stompWebSocketHandler from './protocol/stomp/stompWebSocketHandler'; import { IWebSocketHandler, IConnectedObservable, WsOptions, IWebSocket } from './types'; export interface ClientOptions extends WsOptions { maxConnectAttempt: number, ttlConnectAttempt: number } const DEFAULT_MAX_CONNECT_ATTEMPT: number = 10 const DEFAULT_TTL_CONNECT_ATTEMPT: number = 1000 // STOMP Client Class // // All STOMP protocol is exposed as methods of this class ('connect()', // 'send()', etc.) class Client { private stompWebSockerHandler: IWebSocketHandler<IConnectedObservable> private observableConnection: Observable<ConnectedClient> private maxConnectAttempt: number private ttlConnectAttempt: number private isConnected: boolean constructor (createWsConnection: () => IWebSocket, options: ClientOptions) { this.stompWebSockerHandler = stompWebSocketHandler(createWsConnection, options); this.maxConnectAttempt = options.maxConnectAttempt || DEFAULT_MAX_CONNECT_ATTEMPT; this.ttlConnectAttempt = options.ttlConnectAttempt || DEFAULT_TTL_CONNECT_ATTEMPT; this.isConnected = false; } // [CONNECT Frame](http://stomp.github.com/stomp-specification-1.1.html#CONNECT_or_STOMP_Frame) // // Return an Observable containing the connectedClient public connect = (headers: ConnectionHeaders): Observable<ConnectedClient> => { // create one and only one dedicated observable per destination if (!this.observableConnection) { const multicastConnection: ConnectableObservable<ConnectedClient> = this.__connect(headers) .multicast(() => new ReplaySubject(1)); multicastConnection.connect(); this.observableConnection = multicastConnection.refCount(); } return this.observableConnection; } private __connect = (headers: ConnectionHeaders): Observable<ConnectedClient> => { return this.__initConnectedClient(headers).switchMap((connection: IConnectedObservable) => { this.isConnected = true; return Observable.of(new ConnectedClient(connection)); }) .catch(error => { return Observable.throw(error); }); } private __initConnectedClient = (headers: ConnectionHeaders) => { // we initialize the connection return this.stompWebSockerHandler.initConnection(headers) .retryWhen(attemps => attemps.scan( (errorCount, err) => { // we reinitialize the error count if we were previously connected if (this.isConnected) { this.isConnected = false; errorCount = 0; } if (this.maxConnectAttempt !== -1 && errorCount >= this.maxConnectAttempt) { throw 'Attempted to connect ' + errorCount + ' failed.'; } return errorCount + 1; }, 1) .do( errorCount => Observable.timer(errorCount * this.ttlConnectAttempt)) ); } } export default Client;