/* * Copyright (C) 2019 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 {Logger} from '@openstapps/logger'; 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; /** * Initialised status flag of config provider */ initialised = false; /** * Constructor, initialise api client * * @param storageProvider StorageProvider to load persistet configuration * @param swHttpClient Api client */ constructor(private readonly storageProvider: StorageProvider, swHttpClient: StAppsWebHttpClient) { this.client = new Client(swHttpClient, environment.backend_url, environment.backend_version); } /** * Fetches configuration from backend */ async fetch(): Promise { try { return await this.client.handshake(environment.backend_version); } catch (error) { throw new ConfigFetchError(); } } /** * Returns the value of an app configuration * * @param attribute requested attribute from app configuration */ public async getValue(attribute: keyof SCAppConfiguration) { if (!this.initialised) { try { await this.init(); } catch (error) { // don't throw ConfigFetchError if saved config is available if (!(error.name === 'ConfigFetchError' && this.initialised)) { throw error; } } } if (typeof this.config.app[attribute] !== 'undefined') { return this.config.app[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; this.initialised = false; // load saved configuration try { this.config = await this.loadLocal(); this.initialised = true; Logger.log(`initialised configuration from storage`); if (this.config.backend.SCVersion !== environment.backend_version) { loadError = new WrongConfigVersionInStorage(environment.backend_version, this.config.backend.SCVersion); Logger.warn(loadError); } } catch (error) { loadError = error; } // fetch remote configuration from backend try { const fetchedConfig: SCIndexResponse = await this.fetch(); await this.set(fetchedConfig); this.initialised = true; 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') { throw loadError; } if (typeof fetchError !== 'undefined') { throw fetchError; } } /** * Returns saved configuration from StorageModule * * @throws SavedConfigNotAvailable if no configuration could be loaded */ async loadLocal(): Promise { await this.storageProvider.init(); // 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); } }