src/app/test-controller/command.service.ts
constructor(isProductionMode: boolean, tcs: TestControllerService, serverUrl: string, http: HttpClient)
|
|||||||||||||||
Parameters :
|
Private commandFromTerminal | |||||||||
commandFromTerminal(keyword: string, args: string[])
|
|||||||||
Parameters :
Returns :
void
|
Private Static commandToString | ||||||
commandToString(command: Command)
|
||||||
Parameters :
Returns :
string
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
Private setUpGlobalCommandsForDebug |
setUpGlobalCommandsForDebug()
|
Returns :
void
|
Private subscribeReceivedCommands |
subscribeReceivedCommands()
|
Returns :
void
|
Private subscribeTestStarted |
subscribeTestStarted()
|
Returns :
void
|
Private Static testStartedOrStopped | ||||||
testStartedOrStopped(testStatus: TestControllerState)
|
||||||
Parameters :
Returns :
TestStartedOrStopped
|
cutConnection |
cutConnection()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:75
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:34
|
Returns :
void
|
Protected observeEndpointAndChannel |
observeEndpointAndChannel()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:38
|
Returns :
Observable<T>
|
Private pollNext |
pollNext()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:46
|
Returns :
void
|
Private scheduleNextPoll |
scheduleNextPoll()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:87
|
Returns :
void
|
Private subScribeToWsChannel |
subScribeToWsChannel()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:110
|
Returns :
void
|
Private unsubscribeFromWebsocket |
unsubscribeFromWebsocket()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:100
|
Returns :
void
|
Protected closeConnection |
closeConnection()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:47
|
Returns :
void
|
connect |
connect()
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:18
|
Returns :
void
|
getChannel | ||||||
getChannel(channelName: string)
|
||||||
Inherited from
WebsocketBackendService
|
||||||
Defined in
WebsocketBackendService:66
|
||||||
Type parameters :
|
||||||
Parameters :
Returns :
Observable<T>
|
send |
send(event: string, data: any)
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:58
|
Returns :
void
|
Protected closeConnection |
closeConnection()
|
Inherited from
WebsocketService
|
Defined in
WebsocketService:47
|
Returns :
void
|
connect |
connect()
|
Inherited from
WebsocketService
|
Defined in
WebsocketService:18
|
Returns :
void
|
getChannel | ||||||
getChannel(channelName: string)
|
||||||
Inherited from
WebsocketService
|
||||||
Defined in
WebsocketService:66
|
||||||
Type parameters :
|
||||||
Parameters :
Returns :
Observable<T>
|
send |
send(event: string, data: any)
|
Inherited from
WebsocketService
|
Defined in
WebsocketService:58
|
Returns :
void
|
command$ |
Type : Subject<Command>
|
Default value : new Subject<Command>()
|
Private commandReceived$ |
Type : Subject<Command>
|
Default value : new Subject<Command>()
|
Private commandSubscription |
Type : Subscription
|
Private executedCommandIds |
Type : number[]
|
Default value : []
|
Protected initialData |
Type : []
|
Default value : []
|
Public isProductionMode |
Type : boolean
|
Decorators :
@Inject('IS_PRODUCTION_MODE')
|
Protected pollingEndpoint |
Type : string
|
Default value : ''
|
Protected pollingInterval |
Type : number
|
Default value : 5000
|
Private testStartedSubscription |
Type : Subscription
|
Protected wsChannelName |
Type : string
|
Default value : 'commands'
|
Protected connectionClosed |
Default value : true
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:25
|
connectionStatus$ |
Type : BehaviorSubject<ConnectionStatus>
|
Default value : new BehaviorSubject<ConnectionStatus>('initial')
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:19
|
data$ |
Type : BehaviorSubject<T>
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:18
|
Protected Abstract initialData |
Type : T
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:16
|
Protected Abstract pollingEndpoint |
Type : string
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:13
|
Protected Abstract pollingInterval |
Type : number
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:14
|
Private pollingTimeoutId |
Type : number
|
Default value : null
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:23
|
Protected Abstract wsChannelName |
Type : string
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:15
|
Private wsConnectionStatusSubscription |
Type : Subscription
|
Default value : null
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:21
|
Private wsDataSubscription |
Type : Subscription
|
Default value : null
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:22
|
wsConnected$ |
Default value : new BehaviorSubject<boolean>(null)
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:15
|
Private wsSubject$ |
Type : WebSocketSubject<any>
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:14
|
Private wsSubscription |
Type : Subscription
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:16
|
Protected wsUrl |
Type : string
|
Default value : ''
|
Inherited from
WebsocketBackendService
|
Defined in
WebsocketBackendService:13
|
wsConnected$ |
Default value : new BehaviorSubject<boolean>(null)
|
Inherited from
WebsocketService
|
Defined in
WebsocketService:15
|
Private wsSubject$ |
Type : WebSocketSubject<any>
|
Inherited from
WebsocketService
|
Defined in
WebsocketService:14
|
Private wsSubscription |
Type : Subscription
|
Inherited from
WebsocketService
|
Defined in
WebsocketService:16
|
Protected wsUrl |
Type : string
|
Default value : ''
|
Inherited from
WebsocketService
|
Defined in
WebsocketService:13
|
import { Inject, Injectable, OnDestroy } from '@angular/core';
import {
of, Subject, Subscription, timer
} from 'rxjs';
import {
concatMap,
distinctUntilChanged,
filter,
ignoreElements,
map,
mergeMap,
startWith,
switchMap,
tap
} from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import {
Command, commandKeywords, isKnownCommand, TestControllerState
} from './test-controller.interfaces';
import { TestControllerService } from './test-controller.service';
import { WebsocketBackendService } from '../shared/websocket-backend.service';
type TestStartedOrStopped = 'started' | 'terminated' | '';
@Injectable({
providedIn: 'root'
})
export class CommandService extends WebsocketBackendService<Command[]> implements OnDestroy {
command$: Subject<Command> = new Subject<Command>();
protected initialData = [];
protected pollingEndpoint = '';
protected pollingInterval = 5000;
protected wsChannelName = 'commands';
private commandReceived$: Subject<Command> = new Subject<Command>();
private commandSubscription: Subscription;
private testStartedSubscription: Subscription;
private executedCommandIds: number[] = [];
constructor(
@Inject('IS_PRODUCTION_MODE') public isProductionMode: boolean,
private tcs: TestControllerService,
@Inject('SERVER_URL') serverUrl: string,
protected http: HttpClient
) {
super(serverUrl, http);
if (!this.isProductionMode) {
this.setUpGlobalCommandsForDebug();
}
// as services don't have a OnInit Hook (see: https://v9.angular.io/api/core/OnInit) we subscribe here
this.subscribeReceivedCommands();
this.subscribeTestStarted();
}
private static commandToString(command: Command): string {
return `[${command.id}] ${command.keyword} ${command.arguments.join(' ')}`;
}
private static testStartedOrStopped(testStatus: TestControllerState): TestStartedOrStopped {
if ((testStatus === TestControllerState.RUNNING) || (testStatus === TestControllerState.PAUSED)) {
return 'started';
}
if ((testStatus === TestControllerState.FINISHED) || (testStatus === TestControllerState.ERROR)) {
return 'terminated';
}
return '';
}
// services are normally meant to live forever, so unsubscription *should* be unnecessary
// this unsubscriptions are only for the case, the project's architecture will be changed dramatically once
// while not having a OnInit-hook services *do have* an OnDestroy-hook (see: https://v9.angular.io/api/core/OnDestroy)
ngOnDestroy(): void {
if (this.commandSubscription) {
this.commandSubscription.unsubscribe();
}
if (this.testStartedSubscription) {
this.testStartedSubscription.unsubscribe();
}
}
private subscribeReceivedCommands() {
this.commandSubscription = this.commandReceived$
.pipe(
filter((command: Command) => (this.executedCommandIds.indexOf(command.id) < 0)),
// min delay between items
concatMap((command: Command) => timer(1000).pipe(ignoreElements(), startWith(command))),
mergeMap((command: Command) => {
return this.http.patch(`${this.serverUrl}test/${this.tcs.testId}/command/${command.id}/executed`, {})
.pipe(
map(() => command),
tap(cmd => this.executedCommandIds.push(cmd.id))
);
})
).subscribe(command => this.command$.next(command));
}
private subscribeTestStarted() {
if (typeof this.testStartedSubscription !== 'undefined') {
this.testStartedSubscription.unsubscribe();
}
this.testStartedSubscription = this.tcs.testStatus$
.pipe(
distinctUntilChanged(),
map(CommandService.testStartedOrStopped),
filter(testStartedOrStopped => testStartedOrStopped !== ''),
map(testStartedOrStopped => (((testStartedOrStopped === 'started') && (this.tcs.testMode.receiveRemoteCommands)) ? `test/${this.tcs.testId}/commands` : '')),
filter(newPollingEndpoint => newPollingEndpoint !== this.pollingEndpoint),
switchMap((pollingEndpoint: string) => {
this.pollingEndpoint = pollingEndpoint;
if (this.pollingEndpoint) {
return this.observeEndpointAndChannel();
}
this.cutConnection();
return of([]);
}),
switchMap(commands => of(...commands))
).subscribe(this.commandReceived$);
}
private setUpGlobalCommandsForDebug() {
// eslint-disable-next-line @typescript-eslint/dot-notation
window['tc'] = {};
commandKeywords.forEach((keyword: string) => {
// eslint-disable-next-line @typescript-eslint/dot-notation
window['tc'][keyword] = args => { this.commandFromTerminal(keyword, args); };
});
}
private commandFromTerminal(keyword: string, args: string[]): void {
if (this.isProductionMode) {
return;
}
const newArgs = (typeof args === 'undefined') ? [] : args;
const id = Math.round(Math.random() * -10000000);
const command = {
keyword,
arguments: newArgs,
id,
timestamp: Date.now()
};
if (!isKnownCommand(keyword)) {
return;
}
this.command$.next(command);
}
}