abstruse
Version:
Abstruse CI
65 lines (57 loc) • 2.02 kB
text/typescript
import { Injectable, Provider, EventEmitter } from '@angular/core';
import { RxWebSocket, ConnectionStates } from '../classes/rx-web-socket.class';
import { Observable, Subscriber, BehaviorSubject, timer, fromEvent } from 'rxjs';
import { share, retryWhen, switchMap, take } from 'rxjs/operators';
export class SocketService {
connectionState: BehaviorSubject<ConnectionStates>;
socket: RxWebSocket;
outputEvents: EventEmitter<any>;
timeSyncDiff: number;
constructor() {
this.socket = new RxWebSocket();
this.connectionState = new BehaviorSubject<ConnectionStates>(ConnectionStates.CONNECTING);
this.socket.didOpen = () => this.connectionState.next(ConnectionStates.CONNECTED);
this.socket.willOpen = () => this.connectionState.next(ConnectionStates.CONNECTING);
this.socket.didClose = () => this.connectionState.next(ConnectionStates.CLOSED);
this.outputEvents = new EventEmitter<any>();
this.onMessage().subscribe(event => {
if (event.type === 'time') {
this.timeSyncDiff = new Date().getTime() - event.data;
} else {
this.outputEvents.emit(event);
}
});
}
connect(): Observable<any> {
return new Observable((subscriber: Subscriber<any>) => {
const sub = this.socket.out.subscribe(subscriber);
return () => {
sub.unsubscribe();
};
})
.pipe(
share(),
retryWhen(errors => {
return errors.pipe(switchMap(err => {
this.connectionState.next(ConnectionStates.RETRYING);
if (navigator.onLine) {
return timer(3000);
} else {
return fromEvent(window, 'online').pipe(take(1));
}
}));
})
);
}
onMessage(): Observable<any> {
return this.connect();
}
emit(msg: any) {
const data = typeof msg === 'string' ? msg : JSON.stringify(msg);
this.socket.in.next(data);
}
}
export const SocketServiceProvider: Provider = {
provide: SocketService, useClass: SocketService
};