Files
openstapps/src/app/modules/config/config.provider.ts
2022-02-10 16:21:35 +01:00

192 lines
5.4 KiB
TypeScript

/*
* 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 <https://www.gnu.org/licenses/>.
*/
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<SCIndexResponse> {
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<void> {
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<SCIndexResponse> {
// 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);
}
}