Extract status code polling logic into a class

This commit is contained in:
Kristóf Tóth 2019-11-07 16:08:54 +01:00
parent 9df954bcb1
commit b45f624ab3
3 changed files with 76 additions and 36 deletions

View File

@ -5,7 +5,7 @@
<app-messages></app-messages>
</div>
<div class="tfw-web tao-grid-top-left"
[ngClass]="{'deploy-blur': deploying || (polling | async)}">
[ngClass]="{'deploy-blur': deploying || (iframeReloadPoller.isPolling | async)}">
<div *ngIf="iframeUrl | async" class="iframe-container">
<div *ngIf="showUrlBar | async" class="urlbar-container">
<button class="refresh btn btn-sm rounded-circle" (click)="reloadIframe()">&#8635;</button>

View File

@ -1,13 +1,13 @@
import { Component, OnDestroy, OnInit, ChangeDetectorRef, ElementRef, ViewChild } from '@angular/core';
import { DeploymentNotificationService } from '../services/deployment-notification.service';
import { Subscription, BehaviorSubject } from 'rxjs';
import { Subscription } from 'rxjs';
import { WebSocketService } from '../services/websocket.service';
import { WebSocketMessage } from '../message-types/websocket-message';
import { DashboardConfigService } from '../services/config.service';
import { DashboardConfigService, ConfigReadyService } from '../services/config.service';
import { HttpClient } from '@angular/common/http';
import { delay, retryWhen, tap } from 'rxjs/operators';
import { FSMUpdateService } from '../services/fsmupdate.service';
import { MessagesComponent } from '../messages/messages.component';
import { StatusCodePoller } from './statuscodepoller';
@Component({
selector: 'app-dashboard',
@ -16,7 +16,6 @@ import { MessagesComponent } from '../messages/messages.component';
})
export class DashboardComponent implements OnInit, OnDestroy {
deploying = false;
polling = new BehaviorSubject<boolean>(false);
deploymentNotificationSubscription: Subscription;
@ViewChild('webiframe', {static: false}) webiframe: ElementRef;
@ViewChild(MessagesComponent, {static: false}) messages: MessagesComponent;
@ -28,7 +27,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
iframeUrl = this.configService.iframeUrl;
actualIframeUrl = this.iframeUrl.value;
terminalMenuItem = this.configService.terminalMenuItem;
iframeReloadSubscription: Subscription;
iframeReloadPoller: StatusCodePoller;
command_handlers = {
'dashboard.reloadFrontend': this.reloadFrontendHandlder.bind(this),
@ -39,6 +38,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
private webSocketService: WebSocketService,
private changeDetectorRef: ChangeDetectorRef,
private http: HttpClient,
private configReadyService: ConfigReadyService,
private configService: DashboardConfigService,
private fsmUpdateService: FSMUpdateService) {}
@ -46,6 +46,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
this.webSocketService.connect();
this.configService.init();
this.subscribeCheckSolution();
this.iframeReloadPoller = new StatusCodePoller(this.iframeUrl, this.http);
this.hideIframeUntilResponseOk();
this.subscribeResizeOnLayoutChange();
this.initCommandHandling();
@ -63,8 +64,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
}
hideIframeUntilResponseOk() {
// TODO: hide iframe and show it after this whole deal...
this.reloadIframeWhenResponseOk();
this.iframeReloadPoller.ok.subscribe(() => this.reloadIframe());
this.configReadyService.configDone.subscribe(() =>
this.iframeReloadPoller.start()
);
}
subscribeResizeOnLayoutChange() {
@ -86,7 +89,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
(deploying) => {
this.deploying = deploying;
if (!deploying && this.configService.reloadIframeOnDeploy.value) {
this.reloadIframeWhenResponseOk();
this.iframeReloadPoller.start();
}
});
}
@ -151,36 +154,10 @@ export class DashboardComponent implements OnInit, OnDestroy {
this.iframeUrl.next(this.urlbar.nativeElement.value);
}
reloadIframeWhenResponseOk() {
if (this.polling.value) {
this.iframeReloadSubscription.unsubscribe();
}
this.polling.next(true);
this.iframeReloadSubscription = this.http.get(this.actualIframeUrl, {observe: 'response'}).pipe(
retryWhen(errors =>
errors.pipe(
tap(
response => {
if (this.iframeUrl.value === '') {
this.iframeReloadSubscription.unsubscribe();
this.polling.next(false);
}
if (response.status === 200) {
this.iframeReloadSubscription.unsubscribe();
this.polling.next(false);
this.reloadIframe();
}}),
delay(1000)
))).subscribe();
}
ngOnDestroy() {
if (this.deploymentNotificationSubscription) {
this.deploymentNotificationSubscription.unsubscribe();
}
if (this.iframeReloadSubscription) {
this.iframeReloadSubscription.unsubscribe();
}
this.iframeReloadPoller.stop();
}
}

View File

@ -0,0 +1,63 @@
import { HttpClient } from '@angular/common/http';
import { Subject, Subscription, BehaviorSubject } from 'rxjs';
import { retryWhen, delay, tap, skip } from 'rxjs/operators';
export class StatusCodePoller {
http: HttpClient;
url: BehaviorSubject<string>;
pollFreq: number;
okCode: number;
stopOnOk: boolean;
pollSubscription: Subscription;
urlSubscription: Subscription;
poll = new Subject<any>();
ok = new Subject<any>();
isPolling = new BehaviorSubject<boolean>(false);
constructor(
url: BehaviorSubject<string>, http: HttpClient,
pollFreq = 1000, okCode = 200,
stopOnOk = true
) {
this.url = url;
this.http = http;
this.pollFreq = pollFreq;
this.okCode = okCode;
this.stopOnOk = stopOnOk;
}
start() {
this.stop();
if (this.url.value === '') {
return;
}
this.urlSubscription = this.url.pipe(skip(1)).subscribe(() => this.stop());
this.isPolling.next(true);
this.pollSubscription = this.http.get(this.url.value, {observe: 'response'}).pipe(
retryWhen(errors =>
errors.pipe(
tap(
response => {
this.poll.next(response);
if (response.status === this.okCode) {
if (this.stopOnOk) {
this.stop();
}
this.ok.next(response);
}
}),
delay(this.pollFreq)
))).subscribe();
}
stop() {
this.isPolling.next(false);
if (this.pollSubscription) {
this.pollSubscription.unsubscribe();
}
if (this.urlSubscription) {
this.urlSubscription.unsubscribe();
}
}
}