UNPKG

@reactivex/rxjs

Version:

Reactive Extensions for modern JavaScript

132 lines (110 loc) 3.27 kB
import {Subject, SubjectSubscriber} from '../Subject'; import {Operator} from '../Operator'; import {Observable} from '../Observable'; import {Subscriber} from '../Subscriber'; import {Subscription} from '../Subscription'; /** * @class ConnectableObservable<T> */ export class ConnectableObservable<T> extends Observable<T> { protected _subject: Subject<T>; protected _refCount: number = 0; protected _connection: Subscription; constructor(protected source: Observable<T>, protected subjectFactory: () => Subject<T>) { super(); } protected _subscribe(subscriber: Subscriber<T>) { return this.getSubject().subscribe(subscriber); } protected getSubject(): Subject<T> { const subject = this._subject; if (!subject || subject.isStopped) { this._subject = this.subjectFactory(); } return this._subject; } connect(): Subscription { let connection = this._connection; if (!connection) { connection = this.source.subscribe(new ConnectableSubscriber(this.getSubject(), this)); if (connection.isUnsubscribed) { this._connection = null; connection = Subscription.EMPTY; } else { this._connection = connection; } } return connection; } refCount(): Observable<T> { return this.lift(new RefCountOperator<T>(this)); } } class ConnectableSubscriber<T> extends SubjectSubscriber<T> { constructor(destination: Subject<T>, private connectable: ConnectableObservable<T>) { super(destination); } protected _error(err: any): void { this._unsubscribe(); super._error(err); } protected _complete(): void { this._unsubscribe(); super._complete(); } protected _unsubscribe() { const { connectable } = this; if (connectable) { this.connectable = null; (<any> connectable)._refCount = 0; (<any> connectable)._subject = null; (<any> connectable)._connection = null; } } } class RefCountOperator<T> implements Operator<T, T> { constructor(private connectable: ConnectableObservable<T>) { } call(subscriber: Subscriber<T>, source: any): any { const { connectable } = this; (<any> connectable)._refCount++; const refCounter = new RefCountSubscriber(subscriber, connectable); const subscription = source._subscribe(refCounter); if (!refCounter.isUnsubscribed) { (<any> refCounter).connection = connectable.connect(); } return subscription; } } class RefCountSubscriber<T> extends Subscriber<T> { private connection: Subscription; constructor(destination: Subscriber<T>, private connectable: ConnectableObservable<T>) { super(destination); } protected _unsubscribe() { const { connectable } = this; if (!connectable) { this.connection = null; return; } this.connectable = null; const refCount = (<any> connectable)._refCount; if (refCount <= 0) { this.connection = null; return; } (<any> connectable)._refCount = refCount - 1; if (refCount > 1) { this.connection = null; return; } const { connection } = this; if (connection) { this.connection = null; connection.unsubscribe(); } } }