我有一个典型的用例,我必须使用不同的端点websocket URL连接到不同的后端服务。
我在Angular 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;
};
}
现在问题是如何创建具有不同配置的新实例?
我认为可以扩展到子类并传递configure的一种方法。是否有更好的方法而不是创建扩展类?
配置是动态的!我的意思是它将被写入服务器端的页面(我们在后端使用把手来渲染模板)。
答案 0 :(得分: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,
...
],
答案 1 :(得分:0)
我的应用程序中有类似的要求,只需使用基本服务,效果很好。你对配置对象继承的反对意见是什么?这是我如何设置我的例子,这很方便......
export class BaseService {
protected options: { ... };
constructor(...) { }
init(options) {
this.options = options;
...
}
然后你需要的任何子类都可以构建你的选项对象并用它们调用init。这样,您只需编写一次所有方法的抽象版本。我的基本服务非常丰富,但所有的儿童课程都非常简洁。