From ba430d7516bc5b1324b60571ba7594460969b7fb Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 18 Dec 2019 15:31:54 +0100 Subject: Lazy load static objects --- client/src/app/core/plugins/plugin.service.ts | 6 +- client/src/app/core/routing/redirect.service.ts | 12 +- .../core/routing/server-config-resolver.service.ts | 12 +- client/src/app/core/server/server.service.ts | 205 +++++++++++---------- client/src/app/core/theme/theme.service.ts | 15 +- 5 files changed, 131 insertions(+), 119 deletions(-) (limited to 'client/src/app/core') diff --git a/client/src/app/core/plugins/plugin.service.ts b/client/src/app/core/plugins/plugin.service.ts index e24468da5..da5114048 100644 --- a/client/src/app/core/plugins/plugin.service.ts +++ b/client/src/app/core/plugins/plugin.service.ts @@ -70,9 +70,9 @@ export class PluginService implements ClientHook { } initializePlugins () { - this.server.configLoaded - .subscribe(() => { - this.plugins = this.server.getConfig().plugin.registered + this.server.getConfig() + .subscribe(config => { + this.plugins = config.plugin.registered this.buildScopeStruct() diff --git a/client/src/app/core/routing/redirect.service.ts b/client/src/app/core/routing/redirect.service.ts index 43b89f08d..3982cf36f 100644 --- a/client/src/app/core/routing/redirect.service.ts +++ b/client/src/app/core/routing/redirect.service.ts @@ -16,15 +16,15 @@ export class RedirectService { private serverService: ServerService ) { // The config is first loaded from the cache so try to get the default route - const config = this.serverService.getConfig() - if (config && config.instance && config.instance.defaultClientRoute) { - RedirectService.DEFAULT_ROUTE = config.instance.defaultClientRoute + const tmpConfig = this.serverService.getTmpConfig() + if (tmpConfig && tmpConfig.instance && tmpConfig.instance.defaultClientRoute) { + RedirectService.DEFAULT_ROUTE = tmpConfig.instance.defaultClientRoute } // Load default route - this.serverService.configLoaded - .subscribe(() => { - const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute + this.serverService.getConfig() + .subscribe(config => { + const defaultRouteConfig = config.instance.defaultClientRoute if (defaultRouteConfig) { RedirectService.DEFAULT_ROUTE = defaultRouteConfig diff --git a/client/src/app/core/routing/server-config-resolver.service.ts b/client/src/app/core/routing/server-config-resolver.service.ts index ec7d6428f..3b7ed99bf 100644 --- a/client/src/app/core/routing/server-config-resolver.service.ts +++ b/client/src/app/core/routing/server-config-resolver.service.ts @@ -1,17 +1,13 @@ import { Injectable } from '@angular/core' import { Resolve } from '@angular/router' import { ServerService } from '@app/core/server' +import { ServerConfig } from '@shared/models' @Injectable() -export class ServerConfigResolver implements Resolve { - constructor ( - private server: ServerService - ) {} +export class ServerConfigResolver implements Resolve { + constructor (private server: ServerService) {} resolve () { - // FIXME: directly returning this.server.configLoaded does not seem to work - return new Promise(res => { - return this.server.configLoaded.subscribe(() => res(true)) - }) + return this.server.getConfig() } } diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index fdcc51cc5..ec904bf57 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -1,34 +1,36 @@ -import { map, shareReplay, switchMap, tap } from 'rxjs/operators' +import { first, map, share, shareReplay, switchMap, tap } from 'rxjs/operators' import { HttpClient } from '@angular/common/http' import { Inject, Injectable, LOCALE_ID } from '@angular/core' import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' -import { Observable, of, ReplaySubject } from 'rxjs' +import { Observable, of, Subject } from 'rxjs' import { getCompleteLocale, ServerConfig } from '../../../../../shared' import { environment } from '../../../environments/environment' -import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos' +import { VideoConstant } from '../../../../../shared/models/videos' import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n' import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' import { sortBy } from '@app/shared/misc/utils' -import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' -import { cloneDeep } from 'lodash-es' @Injectable() export class ServerService { - private static BASE_SERVER_URL = environment.apiUrl + '/api/v1/server/' private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/' private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' private static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/' private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/' private static CONFIG_LOCAL_STORAGE_KEY = 'server-config' - configLoaded = new ReplaySubject(1) - videoPrivaciesLoaded = new ReplaySubject(1) - videoPlaylistPrivaciesLoaded = new ReplaySubject(1) - videoCategoriesLoaded = new ReplaySubject(1) - videoLicencesLoaded = new ReplaySubject(1) - videoLanguagesLoaded = new ReplaySubject(1) - localeObservable: Observable + configReloaded = new Subject() + private localeObservable: Observable + private videoLicensesObservable: Observable[]> + private videoCategoriesObservable: Observable[]> + private videoPrivaciesObservable: Observable[]> + private videoPlaylistPrivaciesObservable: Observable[]> + private videoLanguagesObservable: Observable[]> + private configObservable: Observable + + private configReset = false + + private configLoaded = false private config: ServerConfig = { instance: { name: 'PeerTube', @@ -121,132 +123,141 @@ export class ServerService { enabled: true } } - private videoCategories: Array> = [] - private videoLicences: Array> = [] - private videoLanguages: Array> = [] - private videoPrivacies: Array> = [] - private videoPlaylistPrivacies: Array> = [] constructor ( private http: HttpClient, @Inject(LOCALE_ID) private localeId: string ) { - this.loadServerLocale() this.loadConfigLocally() } - loadConfig () { - this.http.get(ServerService.BASE_CONFIG_URL) - .pipe(tap(this.saveConfigLocally)) - .subscribe(data => { - this.config = data + getServerVersionAndCommit () { + const serverVersion = this.config.serverVersion + const commit = this.config.serverCommit || '' - this.configLoaded.next(true) - }) - } + let result = serverVersion + if (commit) result += '...' + commit - loadVideoCategories () { - return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'categories', this.videoCategories, this.videoCategoriesLoaded, true) + return result } - loadVideoLicences () { - return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'licences', this.videoLicences, this.videoLicencesLoaded) + resetConfig () { + this.configLoaded = false + this.configReset = true } - loadVideoLanguages () { - return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'languages', this.videoLanguages, this.videoLanguagesLoaded, true) - } + getConfig () { + if (this.configLoaded) return of(this.config) - loadVideoPrivacies () { - return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'privacies', this.videoPrivacies, this.videoPrivaciesLoaded) - } + if (!this.configObservable) { + this.configObservable = this.http.get(ServerService.BASE_CONFIG_URL) + .pipe( + tap(this.saveConfigLocally), + tap(() => this.configLoaded = true), + tap(() => { + if (this.configReset) { + this.configReloaded.next() + this.configReset = false + } + }), + share() + ) + } - loadVideoPlaylistPrivacies () { - return this.loadAttributeEnum( - ServerService.BASE_VIDEO_PLAYLIST_URL, - 'privacies', - this.videoPlaylistPrivacies, - this.videoPlaylistPrivaciesLoaded - ) + return this.configObservable } - getConfig () { - return cloneDeep(this.config) - } - - getServerVersionAndCommit () { - const serverVersion = this.config.serverVersion - const commit = this.config.serverCommit || '' - - let result = `v${serverVersion}` - if (commit) result += '...' + commit - - return result + getTmpConfig () { + return this.config } getVideoCategories () { - return cloneDeep(this.videoCategories) + if (!this.videoCategoriesObservable) { + this.videoCategoriesObservable = this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'categories', true) + } + + return this.videoCategoriesObservable.pipe(first()) } getVideoLicences () { - return cloneDeep(this.videoLicences) + if (!this.videoLicensesObservable) { + this.videoLicensesObservable = this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'licences') + } + + return this.videoLicensesObservable.pipe(first()) } getVideoLanguages () { - return cloneDeep(this.videoLanguages) + if (!this.videoLanguagesObservable) { + this.videoLanguagesObservable = this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'languages', true) + } + + return this.videoLanguagesObservable.pipe(first()) } getVideoPrivacies () { - return cloneDeep(this.videoPrivacies) + if (!this.videoPrivaciesObservable) { + this.videoPrivaciesObservable = this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'privacies') + } + + return this.videoPrivaciesObservable.pipe(first()) } getVideoPlaylistPrivacies () { - return cloneDeep(this.videoPlaylistPrivacies) + if (!this.videoPlaylistPrivaciesObservable) { + this.videoPlaylistPrivaciesObservable = this.loadAttributeEnum(ServerService.BASE_VIDEO_PLAYLIST_URL, 'privacies') + } + + return this.videoPlaylistPrivaciesObservable.pipe(first()) + } + + getServerLocale () { + if (!this.localeObservable) { + const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId) + + // Default locale, nothing to translate + if (isDefaultLocale(completeLocale)) { + this.localeObservable = of({}).pipe(shareReplay()) + } else { + this.localeObservable = this.http + .get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json') + .pipe(shareReplay()) + } + } + + return this.localeObservable.pipe(first()) } - private loadAttributeEnum ( + private loadAttributeEnum ( baseUrl: string, attributeName: 'categories' | 'licences' | 'languages' | 'privacies', - hashToPopulate: VideoConstant[], - notifier: ReplaySubject, sort = false ) { - this.localeObservable - .pipe( - switchMap(translations => { - return this.http.get<{ [id: string]: string }>(baseUrl + attributeName) - .pipe(map(data => ({ data, translations }))) - }) - ) - .subscribe(({ data, translations }) => { - Object.keys(data) - .forEach(dataKey => { - const label = data[ dataKey ] - - hashToPopulate.push({ - id: attributeName === 'languages' ? dataKey : parseInt(dataKey, 10), - label: peertubeTranslate(label, translations) - }) - }) - - if (sort === true) sortBy(hashToPopulate, 'label') - - notifier.next(true) - }) - } + return this.getServerLocale() + .pipe( + switchMap(translations => { + return this.http.get<{ [ id: string ]: string }>(baseUrl + attributeName) + .pipe(map(data => ({ data, translations }))) + }), + map(({ data, translations }) => { + const hashToPopulate: VideoConstant[] = [] - private loadServerLocale () { - const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId) + Object.keys(data) + .forEach(dataKey => { + const label = data[ dataKey ] - // Default locale, nothing to translate - if (isDefaultLocale(completeLocale)) { - this.localeObservable = of({}).pipe(shareReplay()) - return - } + hashToPopulate.push({ + id: (attributeName === 'languages' ? dataKey : parseInt(dataKey, 10)) as T, + label: peertubeTranslate(label, translations) + }) + }) + + if (sort === true) sortBy(hashToPopulate, 'label') - this.localeObservable = this.http - .get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json') - .pipe(shareReplay()) + return hashToPopulate + }), + shareReplay() + ) } private saveConfigLocally (config: ServerConfig) { diff --git a/client/src/app/core/theme/theme.service.ts b/client/src/app/core/theme/theme.service.ts index 3eebc1acc..2c5873cb3 100644 --- a/client/src/app/core/theme/theme.service.ts +++ b/client/src/app/core/theme/theme.service.ts @@ -3,7 +3,7 @@ import { AuthService } from '@app/core/auth' import { ServerService } from '@app/core/server' import { environment } from '../../../environments/environment' import { PluginService } from '@app/core/plugins/plugin.service' -import { ServerConfigTheme } from '@shared/models' +import { ServerConfig, ServerConfigTheme } from '@shared/models' import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' import { first } from 'rxjs/operators' @@ -20,6 +20,8 @@ export class ThemeService { private themeFromLocalStorage: ServerConfigTheme private themeDOMLinksFromLocalStorage: HTMLLinkElement[] = [] + private serverConfig: ServerConfig + constructor ( private auth: AuthService, private pluginService: PluginService, @@ -30,9 +32,12 @@ export class ThemeService { // Try to load from local storage first, so we don't have to wait network requests this.loadAndSetFromLocalStorage() - this.server.configLoaded - .subscribe(() => { - const themes = this.server.getConfig().theme.registered + this.serverConfig = this.server.getTmpConfig() + this.server.getConfig() + .subscribe(config => { + this.serverConfig = config + + const themes = this.serverConfig.theme.registered this.removeThemeFromLocalStorageIfNeeded(themes) this.injectThemes(themes) @@ -77,7 +82,7 @@ export class ThemeService { if (theme !== 'instance-default') return theme } - return this.server.getConfig().theme.default + return this.serverConfig.theme.default } private loadTheme (name: string) { -- cgit v1.2.3