/* * Copyright (C) 2019, 2020 StApps * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ import {Injectable} from '@angular/core'; import {Client} from '@openstapps/api/lib/client'; import {SCAppConfiguration, SCIndexResponse} from '@openstapps/core'; import {NGXLogger} from 'ngx-logger'; import packageJson from '../../../../package.json'; import {environment} from '../../../environments/environment'; import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider'; import {StorageProvider} from '../storage/storage.provider'; import { ConfigFetchError, ConfigInitError, ConfigValueNotAvailable, SavedConfigNotAvailable, WrongConfigVersionInStorage, } from './errors'; /** * Key to store config in storage module * * TODO: Issue #41 centralise storage keys */ export const STORAGE_KEY_CONFIG = 'stapps.config'; /** * Provides configuration */ @Injectable() export class ConfigProvider { /** * Api client */ client: Client; /** * App configuration as IndexResponse */ config: SCIndexResponse; /** * Version of the @openstapps/core package that app is using */ scVersion = packageJson.dependencies['@openstapps/core']; /** * First session indicator (config not found in storage) */ firstSession = true; /** * Constructor, initialise api client * * @param storageProvider StorageProvider to load persistent configuration * @param swHttpClient Api client * @param logger An angular logger */ constructor( private readonly storageProvider: StorageProvider, swHttpClient: StAppsWebHttpClient, private readonly logger: NGXLogger, ) { this.client = new Client( swHttpClient, environment.backend_url, environment.backend_version, ); } /** * Fetches configuration from backend */ async fetch(): Promise { try { return await this.client.handshake(this.scVersion); } catch { throw new ConfigFetchError(); } } /** * Returns the value of an app configuration * * @param attribute requested attribute from app configuration */ public getValue(attribute: keyof SCAppConfiguration) { if (typeof this.config.app[attribute] !== 'undefined') { return this.config.app[attribute]; } throw new ConfigValueNotAvailable(attribute); } /** * Returns a value of the configuration (not only app configuration) * * @param attribute requested attribute from the configuration */ public getAnyValue(attribute: keyof SCIndexResponse) { if (typeof this.config[attribute] !== 'undefined') { return this.config[attribute]; } throw new ConfigValueNotAvailable(attribute); } /** * Initialises the ConfigProvider * * @throws ConfigInitError if no configuration could be loaded. * @throws WrongConfigVersionInStorage if fetch failed and saved config has wrong SCVersion */ async init(): Promise { let loadError; let fetchError; // load saved configuration try { this.config = await this.loadLocal(); this.firstSession = false; this.logger.log(`initialised configuration from storage`); if (this.config.backend.SCVersion !== this.scVersion) { loadError = new WrongConfigVersionInStorage( this.scVersion, this.config.backend.SCVersion, ); } } catch (error) { loadError = error; } // fetch remote configuration from backend try { const fetchedConfig: SCIndexResponse = await this.fetch(); await this.set(fetchedConfig); this.logger.log(`initialised configuration from remote`); } catch (error) { fetchError = error; } // check for occurred errors and throw them if (typeof loadError !== 'undefined' && typeof fetchError !== 'undefined') { throw new ConfigInitError(); } if (typeof loadError !== 'undefined') { this.logger.warn(loadError); } if (typeof fetchError !== 'undefined') { this.logger.warn(fetchError); } } /** * Returns saved configuration from StorageModule * * @throws SavedConfigNotAvailable if no configuration could be loaded */ async loadLocal(): Promise { // get local configuration if (await this.storageProvider.has(STORAGE_KEY_CONFIG)) { return this.storageProvider.get(STORAGE_KEY_CONFIG); } throw new SavedConfigNotAvailable(); } /** * Saves the configuration from the provider * * @param config configuration to save */ async save(config: SCIndexResponse): Promise { await this.storageProvider.put(STORAGE_KEY_CONFIG, config); } /** * Sets the configuration in the module and writes it into app storage * * @param config SCIndexResponse to set */ async set(config: SCIndexResponse): Promise { this.config = config; await this.save(this.config); } }