fix: enable starting the app without backend

Closes #223
This commit is contained in:
Jovan Krunić
2024-09-19 15:01:54 +02:00
committed by Thea Schöbl
parent 0c49fd8c34
commit bb1f596bfc
2 changed files with 54 additions and 30 deletions

View File

@@ -67,7 +67,8 @@ describe('ConfigProvider', () => {
it('should fetch app configuration', async () => {
spyOn(configProvider.client, 'handshake').and.returnValue(Promise.resolve(sampleIndexResponse));
const result = await configProvider.fetch();
await configProvider.fetch();
const result = configProvider.config;
expect(result).toEqual(sampleIndexResponse);
});
@@ -110,7 +111,7 @@ describe('ConfigProvider', () => {
expect(storageProviderSpy.has).toHaveBeenCalled();
expect(storageProviderSpy.get).toHaveBeenCalledTimes(0);
expect(configProvider.client.handshake).toHaveBeenCalled();
expect(await configProvider.getValue('name')).toEqual(sampleIndexResponse.app.name);
expect(configProvider.getValue('name')).toEqual(sampleIndexResponse.app.name);
});
it('should throw error on failed initialisation', async () => {
@@ -192,4 +193,31 @@ describe('ConfigProvider', () => {
expect(configProvider.getValue('name')).toEqual(sampleIndexResponse.app.name);
});
it('should fetch new config from remote on init', async () => {
storageProviderSpy.has.and.returnValue(Promise.resolve(true));
storageProviderSpy.get.and.returnValue(Promise.resolve(sampleIndexResponse));
spyOn(configProvider, 'fetch');
await configProvider.init();
expect(configProvider.fetch).toHaveBeenCalled();
});
it('should update the local config with the one from remote', async () => {
storageProviderSpy.has.and.returnValue(Promise.resolve(true));
storageProviderSpy.get.and.returnValue(Promise.resolve(sampleIndexResponse));
const newConfig = structuredClone(sampleIndexResponse);
newConfig.app.name = 'New app name';
spyOn(configProvider.client, 'handshake').and.returnValue(Promise.resolve(newConfig));
await configProvider.init();
// Validate that the initial configuration is loaded
expect(configProvider.getValue('name')).toEqual(sampleIndexResponse.app.name);
// Fetch the new configuration from the remote
await configProvider.fetch();
// Validate that the new configuration is now set
expect(configProvider.getValue('name')).toEqual(newConfig.app.name);
});
});

View File

@@ -83,17 +83,20 @@ export class ConfigProvider {
/**
* Fetches configuration from backend
*/
async fetch(): Promise<SCIndexResponse> {
async fetch(): Promise<void> {
try {
const isOffline = await firstValueFrom(this.internetConnectionService.offline$);
if (isOffline) {
throw new Error('Device is offline.');
} else {
return await this.client.handshake(this.scVersion);
const fetchedConfig: SCIndexResponse = await this.client.handshake(this.scVersion);
await this.set(fetchedConfig);
this.logger.log(`Configuration updated from remote`);
}
} catch (error) {
const error_ = error instanceof Error ? new ConfigFetchError(error.message) : new ConfigFetchError();
throw error_;
this.logger.warn(`Failed to fetch remote configuration:`, error_);
throw error_; // Rethrow the error to handle it in init()
}
}
@@ -121,40 +124,33 @@ export class ConfigProvider {
/**
* Initialises the ConfigProvider
* @throws ConfigInitError if no configuration could be loaded.
* @throws WrongConfigVersionInStorage if fetch failed and saved config has wrong SCVersion
* @throws ConfigInitError if no configuration could be loaded both locally and remote.
*/
async init(): Promise<void> {
let loadError;
let fetchError;
// load saved configuration
try {
// Attempt to load the configuration from local storage
this.config = await this.loadLocal();
this.firstSession = false;
this.logger.log(`initialised configuration from storage`);
// Check if the stored configuration has the correct version
if (this.config.backend.SCVersion.split('.')[0] !== this.scVersion.split('.')[0]) {
loadError = new WrongConfigVersionInStorage(this.scVersion, this.config.backend.SCVersion);
throw 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 (loadError !== undefined && fetchError !== undefined) {
throw new ConfigInitError();
}
if (loadError !== undefined) {
// Fetch the remote configuration in a non-blocking manner
void this.fetch();
} catch (loadError) {
this.logger.warn(loadError);
}
if (fetchError !== undefined) {
this.logger.warn(fetchError);
try {
// If local loading fails, immediately try to fetch the configuration from remote
await this.fetch();
} catch (fetchError) {
this.logger.warn(`Failed to fetch remote configuration:`, fetchError);
// If both local loading and remote fetching fail, throw ConfigInitError
throw new ConfigInitError();
}
}
}