diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 0241cae4193d21113291bcf55f32e5503e7fe22a..9d87de3a85eacdb3433df9f194c8249ac3dedd9d 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -58,16 +58,6 @@ export class AppComponent implements OnInit, OnDestroy { return true; } - private static localTime(date: Date): string { - const year = date.getFullYear(); - const month = (`0${date.getMonth() + 1}`).slice(-2); - const day = (`0${date.getDate()}`).slice(-2); - const hours = (`0${date.getHours()}`).slice(-2); - const minutes = (`0${date.getMinutes()}`).slice(-2); - const seconds = (`0${date.getSeconds()}`).slice(-2); - return `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`; - } - closeErrorBox(): void { this.showError = false; } @@ -122,16 +112,6 @@ export class AppComponent implements OnInit, OnDestroy { // TODO implement SysConfig.mainLogo - const clientTime = new Date(); - const serverTime = new Date(sysConfig.serverTimestamp); - if (Math.abs(sysConfig.serverTimestamp - clientTime.getTime()) > 90000) { - this.mds.appError$.next({ - label: 'Server- und Client-Uhr stimmen nicht überein.', - description: `Server-Zeit: ${AppComponent.localTime(serverTime)}, - Client-Zeit: ${AppComponent.localTime(clientTime)}`, - category: 'WARNING' - }); - } this.mds.setTestConfig(sysConfig.testConfig); }); diff --git a/src/app/sys-check/backend.service.ts b/src/app/sys-check/backend.service.ts index 6ced56cc8e28321a3dc7c9c259d12ff454363a8c..01da8c0af473d05277cb16d6619a39243feae45e 100644 --- a/src/app/sys-check/backend.service.ts +++ b/src/app/sys-check/backend.service.ts @@ -6,7 +6,7 @@ import { CheckConfig, NetworkRequestTestResult, UnitAndPlayerContainer, - SysCheckReport + SysCheckReport, ServerTime } from './sys-check.interfaces'; import { ApiError } from '../app.interfaces'; @@ -58,6 +58,17 @@ export class BackendService { ); } + getServerTime(): Observable<ServerTime> { + return this.http + .get<ServerTime>(`${this.serverUrl}system/time`) + .pipe( + catchError((err: ApiError) => { + console.warn(`Could not get Time from Server: ${err.code} ${err.info} `); + return of(null); + }) + ); + } + benchmarkDownloadRequest(requestedDownloadSize: number): Promise<NetworkRequestTestResult> { const { serverUrl } = this; const cacheKiller = `&uid=${new Date().getTime()}`; diff --git a/src/app/sys-check/sys-check-data.service.ts b/src/app/sys-check/sys-check-data.service.ts index 47dcaabfdef305b1613ce5ce68f546e2a63a109b..e95a9543734f2adfbdc2bb40a8aaaf2e0e9908c2 100644 --- a/src/app/sys-check/sys-check-data.service.ts +++ b/src/app/sys-check/sys-check-data.service.ts @@ -12,10 +12,10 @@ import { }) export class SysCheckDataService { private steps: string[] = []; - public stepLabels: string[] = []; + stepLabels: string[] = []; private currentStep = 0; - public nextStep = ''; - public prevStep = ''; + nextStep = ''; + prevStep = ''; private stepDefs: StepDef[] = [ { route: 'w', @@ -39,20 +39,22 @@ export class SysCheckDataService { } ]; - public checkConfig: CheckConfig = null; - public loadConfigComplete = false; - public unitAndPlayerContainer: UnitAndPlayerContainer = null; - public environmentReport: ReportEntry[] = []; - public networkReport: ReportEntry[] = []; - public questionnaireReport: ReportEntry[] = []; - public networkCheckStatus: NetworkCheckStatus = { + checkConfig: CheckConfig = null; + loadConfigComplete = false; + unitAndPlayerContainer: UnitAndPlayerContainer = null; + environmentReport: ReportEntry[] = []; + networkReport: ReportEntry[] = []; + questionnaireReport: ReportEntry[] = []; + networkCheckStatus: NetworkCheckStatus = { done: true, message: 'Messung noch nicht gestartet', avgUploadSpeedBytesPerSecond: -1, avgDownloadSpeedBytesPerSecond: -1 }; - public setSteps(): void { + timeCheckDone = false; + + setSteps(): void { this.steps = []; this.stepLabels = []; this.stepDefs.forEach(step => { @@ -69,7 +71,7 @@ export class SysCheckDataService { }); } - public setNewCurrentStep(newStep: string): void { + setNewCurrentStep(newStep: string): void { for (let stepIndex = 0; stepIndex < this.steps.length; stepIndex++) { if (this.steps[stepIndex] === newStep) { this.currentStep = stepIndex; diff --git a/src/app/sys-check/sys-check.component.html b/src/app/sys-check/sys-check.component.html index 33acf616facee662b9dc95b141e8c1c9e85b5eb6..3f50d20a50cd570894a35caef3787ee6daee20e7 100644 --- a/src/app/sys-check/sys-check.component.html +++ b/src/app/sys-check/sys-check.component.html @@ -4,7 +4,7 @@ [routerLink]="[ds.prevStep]" matTooltip="Zurück" fxFlex="none"> <i class="material-icons">chevron_left</i> </button> - <button mat-fab [disabled]="!ds.nextStep || !ds.loadConfigComplete || !ds.networkCheckStatus.done" color="accent" + <button mat-fab [disabled]="!ds.nextStep || !ds.loadConfigComplete || !ds.networkCheckStatus.done || !ds.timeCheckDone" color="accent" [routerLink]="[ds.nextStep]" matTooltip="Weiter" fxFlex="none"> <i class="material-icons">chevron_right</i> </button> diff --git a/src/app/sys-check/sys-check.interfaces.ts b/src/app/sys-check/sys-check.interfaces.ts index 496f77e347283ef0268be3f46f38e882757d09cc..4dfcc33c8a77058748ce7b63ae52e86c5a317de8 100644 --- a/src/app/sys-check/sys-check.interfaces.ts +++ b/src/app/sys-check/sys-check.interfaces.ts @@ -43,6 +43,11 @@ export interface UnitAndPlayerContainer { duration: number; } +export interface ServerTime { + timestamp: number; + timezone: string; +} + export interface NetworkRequestTestResult { 'type': 'downloadTest' | 'uploadTest'; 'size': number; diff --git a/src/app/sys-check/welcome/welcome.component.ts b/src/app/sys-check/welcome/welcome.component.ts index 9cf791814c5a10f18b9ae758adaaab1a4aa94c80..3fe93e7bfc898b44dfbe0a0b0b3c4f302d52acd4 100644 --- a/src/app/sys-check/welcome/welcome.component.ts +++ b/src/app/sys-check/welcome/welcome.component.ts @@ -1,6 +1,9 @@ import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; import { SysCheckDataService } from '../sys-check-data.service'; import { ReportEntry } from '../sys-check.interfaces'; +import { BackendService } from '../backend.service'; @Component({ styleUrls: ['../sys-check.component.css'], @@ -25,27 +28,31 @@ export class WelcomeComponent implements OnInit { }; constructor( - public ds: SysCheckDataService + public ds: SysCheckDataService, + private bs: BackendService ) { } ngOnInit(): void { setTimeout(() => { this.ds.setNewCurrentStep('w'); - this.getBrowser(); // fallback if UAParser does not work - this.setOS(); // fallback if UAParser does not work - this.setScreenData(); + this.getBrowserFromUserAgent(); // fallback if UAParser does not work + this.getOSFromUserAgent(); // fallback if UAParser does not work + this.getScreenData(); this.getFromUAParser(); - this.setNavigatorInfo(); - this.setBrowserPluginInfo(); - this.rateBrowser(); - - const report = Array.from(this.report.values()) - .sort((item1: ReportEntry, item2: ReportEntry) => (item1.label > item2.label ? 1 : -1)); - this.ds.environmentReport = Object.values(report); + this.getNavigatorInfo(); + this.getBrowserPluginInfo(); + this.getBrowserRating(); + this.getTime() + .subscribe(() => { + const report = Array.from(this.report.values()) + .sort((item1: ReportEntry, item2: ReportEntry) => (item1.label > item2.label ? 1 : -1)); + this.ds.environmentReport = Object.values(report); + this.ds.timeCheckDone = true; + }); }); } - private getBrowser() { + private getBrowserFromUserAgent() { const userAgent = window.navigator.userAgent; // eslint-disable-next-line max-len const regex = /(MSIE|Trident|(?!Gecko.+)Firefox|(?!AppleWebKit.+Chrome.+)Safari(?!.+Edge)|(?!AppleWebKit.+)Chrome(?!.+Edge)|(?!AppleWebKit.+Chrome.+Safari.+)Edge|AppleWebKit(?!.+Chrome|.+Safari)|Gecko(?!.+Firefox))(?: |\/)([\d\.apre]+)/; @@ -99,7 +106,7 @@ export class WelcomeComponent implements OnInit { }); } - private rateBrowser() { + private getBrowserRating() { const browser = this.report.get('Browser').value; const browserVersion = this.report.get('Browser-Version').value; if ((typeof this.rating.browser[browser] !== 'undefined') && (browserVersion < this.rating.browser[browser])) { @@ -110,7 +117,7 @@ export class WelcomeComponent implements OnInit { } } - private setNavigatorInfo() { + private getNavigatorInfo() { [ ['hardwareConcurrency', 'CPU-Kerne'], ['cookieEnabled', 'Browser-Cookies aktiviert'], @@ -128,7 +135,7 @@ export class WelcomeComponent implements OnInit { }); } - private setBrowserPluginInfo() { + private getBrowserPluginInfo() { if ((typeof navigator.plugins === 'undefined') || (!navigator.plugins.length)) { return; } @@ -145,7 +152,7 @@ export class WelcomeComponent implements OnInit { }); } - private setOS() { + private getOSFromUserAgent() { const userAgent = window.navigator.userAgent; let osName; if (userAgent.indexOf('Windows') !== -1) { @@ -180,7 +187,7 @@ export class WelcomeComponent implements OnInit { }); } - private setScreenData() { + private getScreenData() { const isLargeEnough = (window.screen.width >= this.rating.screen.width) && (window.screen.height >= this.rating.screen.height); this.report.set('Bildschirm-Auflösung', { @@ -200,4 +207,30 @@ export class WelcomeComponent implements OnInit { warning: false }); } + + private getTime(): Observable<true> { + const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; + const clientTime = new Date().getTime(); + return this.bs.getServerTime() + .pipe( + map(serverTime => { + const timeDifferenceSeconds = Math.round((clientTime - serverTime.timestamp) / 1000); + this.report.set('Zeitabweichung', { + id: 'time-difference', + type: 'environment', + label: 'Zeitabweichung', + value: timeDifferenceSeconds.toString(10), + warning: timeDifferenceSeconds >= 60 + }); + this.report.set('Zeitzone', { + id: 'time-zone', + type: 'environment', + label: 'Zeitzone', + value: timeZone, + warning: timeZone !== serverTime.timezone + }); + return true; + }) + ); + } }