diff --git a/client/src/app/app.component.spec.ts b/client/src/app/app.component.spec.ts deleted file mode 100644 index acbb8f85e..000000000 --- a/client/src/app/app.component.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -// import { async, fakeAsync, TestBed, tick } from '@angular/core/testing'; - -// import { TranslateService } from '@ngx-translate/core'; - -// import { AppComponent } from './app.component'; -// import { E2EImportsModule } from './../e2e-imports.module'; -// import { ServertimeService } from './core/core-services/servertime.service'; - -describe('AppComponent', () => { - // let servertimeService, translate; - // beforeEach(async(() => { - // TestBed.configureTestingModule({ - // imports: [E2EImportsModule] - // }).compileComponents(); - // servertimeService = TestBed.inject(ServertimeService); - // translate = TestBed.inject(TranslateService); - // spyOn(servertimeService, 'startScheduler').and.stub(); - // spyOn(translate, 'addLangs').and.stub(); - // spyOn(translate, 'setDefaultLang').and.stub(); - // spyOn(translate, 'getBrowserLang').and.stub(); - // spyOn(translate, 'getLangs').and.returnValue([]); - // spyOn(translate, 'use').and.stub(); - // })); - // it('should create the app', fakeAsync(() => { - // const fixture = TestBed.createComponent(AppComponent); - // const app = fixture.debugElement.componentInstance; - // expect(app).toBeTruthy(); - // tick(1000); - // fixture.whenStable().then(() => { - // expect(servertimeService.startScheduler).toHaveBeenCalled(); - // }); - // })); -}); diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index a15485813..eecfe4cf5 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -14,12 +14,12 @@ import { DataStoreUpgradeService } from './core/core-services/data-store-upgrade import { LoadFontService } from './core/ui-services/load-font.service'; import { LoginDataService } from './core/ui-services/login-data.service'; import { OfflineService } from './core/core-services/offline.service'; +import { OpenSlidesStatusService } from './core/core-services/openslides-status.service'; import { OpenSlidesService } from './core/core-services/openslides.service'; import { OperatorService } from './core/core-services/operator.service'; import { OverlayService } from './core/ui-services/overlay.service'; import { RoutingStateService } from './core/ui-services/routing-state.service'; import { ServertimeService } from './core/core-services/servertime.service'; -import { StableService } from './core/core-services/stable.service'; import { ThemeService } from './core/ui-services/theme.service'; import { VotingBannerService } from './core/ui-services/voting-banner.service'; @@ -73,7 +73,7 @@ export class AppComponent { appRef: ApplicationRef, servertimeService: ServertimeService, openslidesService: OpenSlidesService, - stableService: StableService, + openslidesStatus: OpenSlidesStatusService, router: Router, offlineService: OfflineService, operator: OperatorService, @@ -113,8 +113,7 @@ export class AppComponent { tap(() => console.debug('App is now stable!')) ) .subscribe(() => { - openslidesService.setStable(); - stableService.setStable(); + openslidesStatus.setStable(); servertimeService.startScheduler(); }); } diff --git a/client/src/app/core/core-services/http-interceptors/index.ts b/client/src/app/core/core-services/http-interceptors/index.ts index c463909e6..b818531ec 100644 --- a/client/src/app/core/core-services/http-interceptors/index.ts +++ b/client/src/app/core/core-services/http-interceptors/index.ts @@ -1,5 +1,7 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http'; -import { NoopInterceptorService } from './noop-interceptor.service'; +import { StableInterceptorService } from './stable-interceptor.service'; -export const httpInterceptorProviders = [{ provide: HTTP_INTERCEPTORS, useClass: NoopInterceptorService, multi: true }]; +export const httpInterceptorProviders = [ + { provide: HTTP_INTERCEPTORS, useClass: StableInterceptorService, multi: true } +]; diff --git a/client/src/app/core/core-services/http-interceptors/noop-interceptor.service.spec.ts b/client/src/app/core/core-services/http-interceptors/noop-interceptor.service.spec.ts deleted file mode 100644 index 298d82771..000000000 --- a/client/src/app/core/core-services/http-interceptors/noop-interceptor.service.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -// import { TestBed } from '@angular/core/testing'; - -// import { NoopInterceptorService } from './noop-interceptor.service'; - -describe('NoopInterceptorService', () => { - // let service: NoopInterceptorService; - // beforeEach(() => { - // TestBed.configureTestingModule({}); - // service = TestBed.inject(NoopInterceptorService); - // }); - // it('should be created', () => { - // expect(service).toBeTruthy(); - // }); -}); diff --git a/client/src/app/core/core-services/http-interceptors/noop-interceptor.service.ts b/client/src/app/core/core-services/http-interceptors/noop-interceptor.service.ts deleted file mode 100644 index 39b1e3283..000000000 --- a/client/src/app/core/core-services/http-interceptors/noop-interceptor.service.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; -import { Injectable } from '@angular/core'; - -import { Observable, Subject } from 'rxjs'; -import { first, mergeMap } from 'rxjs/operators'; - -import { StableService } from '../stable.service'; - -@Injectable({ - providedIn: 'root' -}) -export class NoopInterceptorService implements HttpInterceptor { - public constructor(private openslidesService: StableService) {} - public intercept(req: HttpRequest, next: HttpHandler): Observable> { - return this.openslidesService.booted.pipe( - first(stable => stable), - mergeMap(() => { - return next.handle(req); - }) - ); - } -} diff --git a/client/src/app/core/core-services/http-interceptors/stable-interceptor.service.ts b/client/src/app/core/core-services/http-interceptors/stable-interceptor.service.ts new file mode 100644 index 000000000..17d400268 --- /dev/null +++ b/client/src/app/core/core-services/http-interceptors/stable-interceptor.service.ts @@ -0,0 +1,36 @@ +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { BehaviorSubject, Observable } from 'rxjs'; +import { first, mergeMap } from 'rxjs/operators'; + +import { OpenSlidesStatusService } from '../openslides-status.service'; + +/** + * An http interceptor to make sure, that every request is made + * only when this application is stable. + */ +@Injectable({ + providedIn: 'root' +}) +export class StableInterceptorService implements HttpInterceptor { + private readonly stableSubject = new BehaviorSubject(false); + + public constructor(private openslidesStatus: OpenSlidesStatusService) { + this.update(); + } + + public intercept(req: HttpRequest, next: HttpHandler): Observable> { + return this.stableSubject.pipe( + first(stable => stable), + mergeMap(() => { + return next.handle(req); + }) + ); + } + + private async update(): Promise { + await this.openslidesStatus.stable; + this.stableSubject.next(true); + } +} diff --git a/client/src/app/core/core-services/openslides-status.service.ts b/client/src/app/core/core-services/openslides-status.service.ts index 90594a0ea..056ea21c8 100644 --- a/client/src/app/core/core-services/openslides-status.service.ts +++ b/client/src/app/core/core-services/openslides-status.service.ts @@ -1,7 +1,10 @@ import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; + import { History } from 'app/shared/models/core/history'; import { BannerDefinition, BannerService } from '../ui-services/banner.service'; +import { Deferred } from '../promises/deferred'; /** * Holds information about OpenSlides. This is not included into other services to @@ -26,13 +29,25 @@ export class OpenSlidesStatusService { return !!this.history; } + public get stable(): Promise { + return this._stable; + } + public isPrioritizedClient = false; + private _stable = new Deferred(); + private _bootedSubject = new BehaviorSubject(false); + /** * Ctor, does nothing. */ public constructor(private banner: BannerService) {} + public setStable(): void { + this._stable.resolve(); + this._bootedSubject.next(true); + } + /** * Calls the getLocaleString function of the history object, if present. * diff --git a/client/src/app/core/core-services/openslides.service.ts b/client/src/app/core/core-services/openslides.service.ts index 7edb8cb97..497f32e01 100644 --- a/client/src/app/core/core-services/openslides.service.ts +++ b/client/src/app/core/core-services/openslides.service.ts @@ -5,8 +5,8 @@ import { BehaviorSubject } from 'rxjs'; import { CommunicationManagerService } from './communication-manager.service'; import { DataStoreService } from './data-store.service'; -import { Deferred } from '../promises/deferred'; import { OfflineBroadcastService, OfflineReason } from './offline-broadcast.service'; +import { OpenSlidesStatusService } from './openslides-status.service'; import { OperatorService, WhoAmI } from './operator.service'; import { StorageService } from './storage.service'; @@ -35,15 +35,10 @@ export class OpenSlidesService { return this.booted.value; } - public get isStable(): Promise { - return this.stable; - } - - private stable = new Deferred(); - public constructor( private storageService: StorageService, private operator: OperatorService, + private openslidesStatus: OpenSlidesStatusService, private router: Router, private DS: DataStoreService, private communicationManager: CommunicationManagerService, @@ -52,10 +47,6 @@ export class OpenSlidesService { this.bootup(); } - public setStable(): void { - this.stable.resolve(); - } - /** * the bootup-sequence: Do a whoami request and if it was successful, do * {@method afterLoginBootup}. If not, redirect the user to the login page. @@ -129,7 +120,7 @@ export class OpenSlidesService { */ private async setupDataStoreAndStartCommunication(): Promise { await this.DS.initFromStorage(); - await this.stable; + await this.openslidesStatus.stable; this.communicationManager.startCommunication(); } diff --git a/client/src/app/core/core-services/stable.service.spec.ts b/client/src/app/core/core-services/stable.service.spec.ts deleted file mode 100644 index 6e66eaf1c..000000000 --- a/client/src/app/core/core-services/stable.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { StableService } from './stable.service'; - -describe('StableService', () => { - let service: StableService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(StableService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/client/src/app/core/core-services/stable.service.ts b/client/src/app/core/core-services/stable.service.ts deleted file mode 100644 index e2ea2623a..000000000 --- a/client/src/app/core/core-services/stable.service.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Injectable } from '@angular/core'; - -import { BehaviorSubject, Observable } from 'rxjs'; - -import { Deferred } from '../promises/deferred'; - -@Injectable({ - providedIn: 'root' -}) -export class StableService { - public get isStable(): Promise { - return this.stable; - } - - public get booted(): Observable { - return this.bootSubject.asObservable(); - } - - private stable = new Deferred(); - - private bootSubject = new BehaviorSubject(false); - - public constructor() {} - - public setStable(): void { - this.stable.resolve(); - this.bootSubject.next(true); - } -} diff --git a/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts b/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts index 5b59e4bf6..b4685b39e 100644 --- a/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts +++ b/client/src/app/site/projector/components/projector-detail/projector-detail.component.ts @@ -8,9 +8,9 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { timer } from 'rxjs'; +import { OpenSlidesStatusService } from 'app/core/core-services/openslides-status.service'; import { OperatorService, Permission } from 'app/core/core-services/operator.service'; import { ProjectorService } from 'app/core/core-services/projector.service'; -import { StableService } from 'app/core/core-services/stable.service'; import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service'; import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projector-message-repository.service'; import { @@ -98,7 +98,7 @@ export class ProjectorDetailComponent extends BaseViewComponentDirective impleme private cd: ChangeDetectorRef, private promptService: PromptService, private opertator: OperatorService, - private stableService: StableService + private openslidesStatus: OpenSlidesStatusService ) { super(titleService, translate, matSnackBar); } @@ -119,8 +119,10 @@ export class ProjectorDetailComponent extends BaseViewComponentDirective impleme }) ); }); + this.countdownRepo.getViewModelListObservable().subscribe(countdowns => (this.countdowns = countdowns)); + this.messageRepo.getViewModelListObservable().subscribe(messages => (this.messages = messages)); + this.repo.getViewModelListObservable().subscribe(projectors => (this.projectorCount = projectors.length)); this.installUpdater(); - this.loadSubscriptions(); } public editProjector(): void { @@ -351,15 +353,8 @@ export class ProjectorDetailComponent extends BaseViewComponentDirective impleme } } - private async loadSubscriptions(): Promise { - await this.stableService.isStable; - this.countdownRepo.getViewModelListObservable().subscribe(countdowns => (this.countdowns = countdowns)); - this.messageRepo.getViewModelListObservable().subscribe(messages => (this.messages = messages)); - this.repo.getViewModelListObservable().subscribe(projectors => (this.projectorCount = projectors.length)); - } - private async installUpdater(): Promise { - await this.stableService.isStable; + await this.openslidesStatus.stable; this.subscriptions.push(timer(0, 500).subscribe(() => this.cd.detectChanges())); } } diff --git a/client/src/app/site/projector/components/projector-list/projector-list.component.ts b/client/src/app/site/projector/components/projector-list/projector-list.component.ts index 37e00aaff..b7c900e47 100644 --- a/client/src/app/site/projector/components/projector-list/projector-list.component.ts +++ b/client/src/app/site/projector/components/projector-list/projector-list.component.ts @@ -16,7 +16,7 @@ import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, timer } from 'rxjs'; -import { OpenSlidesService } from 'app/core/core-services/openslides.service'; +import { OpenSlidesStatusService } from 'app/core/core-services/openslides-status.service'; import { OperatorService, Permission } from 'app/core/core-services/operator.service'; import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-repository.service'; import { Projector } from 'app/shared/models/core/projector'; @@ -78,7 +78,7 @@ export class ProjectorListComponent extends BaseViewComponentDirective implement private repo: ProjectorRepositoryService, private formBuilder: FormBuilder, private operator: OperatorService, - private openslidesService: OpenSlidesService, + private openslidesStatus: OpenSlidesStatusService, private dialogService: MatDialog, private cd: ChangeDetectorRef ) { @@ -135,7 +135,7 @@ export class ProjectorListComponent extends BaseViewComponentDirective implement } private async installUpdater(): Promise { - await this.openslidesService.isStable; + await this.openslidesStatus.stable; /** * Angulars change detection goes nuts, since countdown and motios with long texts are pushing too much data */