Files
openstapps/src/app/modules/config/config.provider.ts
2019-11-27 20:56:47 +01:00

174 lines
5.1 KiB
TypeScript

/*
* 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 <https://www.gnu.org/licenses/>.
*/
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<SCIndexResponse> {
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<void> {
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<SCIndexResponse> {
await this.storageProvider.init();
// get local configuration
if (await this.storageProvider.has(STORAGE_KEY_CONFIG)) {
return this.storageProvider.get<SCIndexResponse>(STORAGE_KEY_CONFIG);
}
throw new SavedConfigNotAvailable();
}
/**
* Saves the configuration from the provider
*
* @param config configuration to save
*/
async save(config: SCIndexResponse): Promise<void> {
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<void> {
this.config = config;
await this.save(this.config);
}
}