2016-12-25 9 views
0

異なるバックエンドサービスに接続するために、異なるエンドポイントwebsocket URLを使用する必要がある典型的な使用例があります。角2:作成前にサービス設定を渡すには?

import {Injectable} from "@angular/core"; 
import {Subject} from "rxjs/subject"; 
import {Observable} from "rxjs/observable"; 
import {WebSocketSubject, WebSocketSubjectConfig} from "rxjs/observable/dom/WebSocketSubject"; 
import {Observer} from "rxjs/observer"; 

@Injectable() 
export class WebSocketService<T> extends Subject<T> { 
    private reconnectionObservable: Observable<number>; 
    private wsSubjectConfig: WebSocketSubjectConfig; 
    private socket: WebSocketSubject<any>; 
    private connectionObserver: Observer<boolean>; 
    public connectionStatus: Observable<boolean>; 


    constructor(private config: WebServiceConfig) { 
     super(); 

     // connection status 
     this.connectionStatus = new Observable((observer) => { 
      this.connectionObserver = observer; 
     }).share().distinctUntilChanged(); 

     // config for WebSocketSubject 
     // except the url, here is closeObserver and openObserver to update connection status 
     this.wsSubjectConfig = { 
      url: config.URL, 
      closeObserver: { 
       next: (e:CloseEvent) => { 
        this.socket = null; 
        this.connectionObserver.next(false); 
       } 
      }, 
      openObserver: { 
       next: (e:Event) => { 
        this.connectionObserver.next(true); 
       } 
      } 
     }; 
     this.connect(); 
     // we follow the connection status and run the reconnect while losing the connection 
     this.connectionStatus.subscribe((isConnected) => { 
      if (!this.reconnectionObservable && typeof(isConnected) == "boolean" && !isConnected) { 
       this.reconnect(); 
      } 
     }); 
    } 

    connect():void { 
     this.socket = new WebSocketSubject(this.wsSubjectConfig); 
     this.socket.subscribe(
      (m) => { 
       this.next(m); // when receiving a message, we just send it to our Subject 
      }, 
      (error:Event) => { 
       if (!this.socket) { 
        // in case of an error with a loss of connection, we restore it 
        this.reconnect(); 
       } 
      }); 
    } 

    reconnect():void { 
     this.reconnectionObservable = Observable.interval(this.config.getRetryInterval()) 
      .takeWhile((v, index) => { 
       return index < this.config.attempts && !this.socket 
      }); 
     this.reconnectionObservable.subscribe(
      () => { 
       this.connect(); 
      }, 
      null, 
      () => { 
       // if the reconnection attempts are failed, then we call complete of our Subject and status 
       this.reconnectionObservable = null; 
       if (!this.socket) { 
        this.complete(); 
        this.connectionObserver.complete(); 
       } 
      }); 
    } 

    send(data:any):void { 
     this.socket.next(this.config.serializer(data)); 
    } 
} 

export enum TimeUnits { 
    SECONDS = 1000, 
    MINUTES = SECONDS * 60, 
    HOURS = MINUTES * 60, 
    DAYS = HOURS * 24 
} 

export class WebServiceConfig { 
    URL: string = 'ws://localhost:4242/ws'; 
    attempts: number = 10; /// number of connection attempts 
    retryUnit: TimeUnits = TimeUnits.SECONDS; /// pause between connections 
    retryInterval: number = 5; 

    serializer: (data: any) => any = function (data: any) { 
     return JSON.stringify(data); 
    }; 
    deserializer: (e: MessageEvent) => any = function (e: MessageEvent) { 
     return e; 
    }; 

    getRetryInterval(): number { 
     return this.retryUnit * this.retryInterval; 
    }; 
} 

今の質問は、私は別の設定で新しいインスタンスを作成する方法である:2角度は、以下を参照して

私は、一般的なサービスを書かれていますか?

私はサブクラスに拡張してconfigureをパスすると思います。むしろ拡張クラスを作成するより良い方法はありますか?

設定は動的です。つまり、サーバーサイドのページに書き込まれるということです(バックエンドのハンドルバーを使用してテンプレートをレンダリングします)。

答えて

1

あなたが欲しいものを行うにはいくつかの方法があります。

export class SampleConfig { 

    constructor(public value:string) 
    { 
    } 
} 

@Injectable() 
export class SampleService { 

    constructor(config:SampleConfig) 
    { 
     console.debug('config', config); 
    } 
} 

providers  : [ 
    ... 
    {provide: SampleService, useFactory:() => new SampleService(new SampleConfig('1'))}, 
    ... 
], 

providers  : [ 
    ... 
    {provide: SampleConfig, useValue: new SampleConfig('1')}, 
    SampleService, 
    ... 
], 
+0

はありがとう、私はこのソリューションを実装しているし、この一つの方法は、(制限隔離することができますスコープ)をモジュールまたはコンポーネントに割り当てます。 – user3130446

0

私のアプリでも同様の要件があり、基本サービスを使用するだけで完璧に動作します。あなたはconfigオブジェクトを使って継承することに反対していますか?ここではそれは便利だ包み、私は私のセットアップを持っている方法の例は、次に、必要な任意のサブクラスがちょうどオブジェクトと彼らとのinitを呼び出して、あなたのオプションを構築することができます...

export class BaseService { 

    protected options: { ... }; 

    constructor(...) { } 

    init(options) { 
    this.options = options; 
    ... 
    } 

です。この方法では、すべてのメソッドの抽象版を一度書くだけです。私の基本サービスはかなり肉薄ですが、すべての子クラスは超簡潔です。

+0

コードとテストの多すぎる;)... – user3130446

関連する問題