2016-12-25 79 views
0

我有一個典型的用例,我必須使用不同的端點websocket URL來連接不同的後端服務。Angular 2:如何在創建之前傳遞服務配置?

我已經寫了通用的服務在角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; 
    }; 
} 

現在的問題是如何創建具有不同配置的新實例?

我認爲的一種方法是擴展到子類並通過配置。有更好的方法來創建擴展類嗎?

配置是動態的!我的意思是它將寫入服務器端的頁面(我們使用後端的句柄來渲染模板)。

回答

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

我在我的應用程序中有類似的要求,只是使用基本服務,完美的作品。你有什麼反對繼承配置對象?下面是我怎麼有我的設置櫃面它的方便的例子...

export class BaseService { 

    protected options: { ... }; 

    constructor(...) { } 

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

然後,你需要可以只是建立你的選擇任何子類對象,然後調用初始化它們。這樣,您只需編寫一次所有方法的抽象版本。我的基地服務非常豐富,但所有的兒童課程都非常簡潔。

+0

太多的代碼和測試)... – user3130446