mirror of
				https://github.com/avatao-content/frontend-tutorial-framework
				synced 2025-11-04 12:22:54 +00:00 
			
		
		
		
	Extract status code polling logic into a class
This commit is contained in:
		@@ -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()">↻</button>
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								src/app/dashboard/statuscodepoller.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/app/dashboard/statuscodepoller.ts
									
									
									
									
									
										Normal 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();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user