From dea9a82105872f1c7e29c6cca04cd50235e18842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jovan=20Kruni=C4=87?= Date: Fri, 14 Jun 2024 17:43:32 +0200 Subject: [PATCH] fix: do not fetch remote configuration if offline Closes #206 --- .../modules/config/config.provider.spec.ts | 24 +++++++++++++++++++ .../src/app/modules/config/config.provider.ts | 15 +++++++++--- frontend/app/src/app/modules/config/errors.ts | 6 +++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/frontend/app/src/app/modules/config/config.provider.spec.ts b/frontend/app/src/app/modules/config/config.provider.spec.ts index 93555478..aaf7bdea 100644 --- a/frontend/app/src/app/modules/config/config.provider.spec.ts +++ b/frontend/app/src/app/modules/config/config.provider.spec.ts @@ -24,13 +24,17 @@ import { } from './errors'; import {NGXLogger} from 'ngx-logger'; import {sampleIndexResponse} from '../../_helpers/data/sample-configuration'; +import {BehaviorSubject} from 'rxjs'; +import {InternetConnectionService} from '../../util/internet-connection.service'; describe('ConfigProvider', () => { + let internetConnectionServiceMock: {offline$: BehaviorSubject}; let configProvider: ConfigProvider; let storageProviderSpy: jasmine.SpyObj; let ngxLogger: jasmine.SpyObj; beforeEach(() => { + internetConnectionServiceMock = {offline$: new BehaviorSubject(false)}; storageProviderSpy = jasmine.createSpyObj('StorageProvider', ['init', 'get', 'has', 'put']); const webHttpClientMethodSpy = jasmine.createSpyObj('StAppsWebHttpClient', ['request']); ngxLogger = jasmine.createSpyObj('NGXLogger', ['log', 'error', 'warn']); @@ -51,6 +55,10 @@ describe('ConfigProvider', () => { provide: NGXLogger, useValue: ngxLogger, }, + { + provide: InternetConnectionService, + useValue: internetConnectionServiceMock, + }, ], }); @@ -75,6 +83,22 @@ describe('ConfigProvider', () => { expect(error).toEqual(new ConfigFetchError()); }); + it('should throw device offline error when offline', async () => { + // eslint-disable-next-line unicorn/error-message + let error = new Error(''); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + internetConnectionServiceMock.offline$ = new BehaviorSubject(true); + + try { + await configProvider.fetch(); + } catch (error_) { + error = error_ as Error; + expect(error).toBeInstanceOf(ConfigFetchError); + expect(error.message).toContain('Device is offline.'); + } + }); + it('should init from remote and saved config not available', async () => { storageProviderSpy.has.and.returnValue(Promise.resolve(false)); spyOn(configProvider.client, 'handshake').and.returnValue(Promise.resolve(sampleIndexResponse)); diff --git a/frontend/app/src/app/modules/config/config.provider.ts b/frontend/app/src/app/modules/config/config.provider.ts index 46671e03..aaa9ff18 100644 --- a/frontend/app/src/app/modules/config/config.provider.ts +++ b/frontend/app/src/app/modules/config/config.provider.ts @@ -27,6 +27,8 @@ import { SavedConfigNotAvailable, WrongConfigVersionInStorage, } from './errors'; +import {InternetConnectionService} from '../../util/internet-connection.service'; +import {firstValueFrom} from 'rxjs'; /** * Key to store config in storage module @@ -72,6 +74,7 @@ export class ConfigProvider { private readonly storageProvider: StorageProvider, swHttpClient: StAppsWebHttpClient, private readonly logger: NGXLogger, + private readonly internetConnectionService: InternetConnectionService, ) { console.log('config init'); this.client = new Client(swHttpClient, environment.backend_url, environment.backend_version); @@ -82,9 +85,15 @@ export class ConfigProvider { */ async fetch(): Promise { try { - return await this.client.handshake(this.scVersion); - } catch { - throw new ConfigFetchError(); + const isOffline = await firstValueFrom(this.internetConnectionService.offline$); + if (isOffline) { + throw new Error('Device is offline.'); + } else { + return await this.client.handshake(this.scVersion); + } + } catch (error) { + const error_ = error instanceof Error ? new ConfigFetchError(error.message) : new ConfigFetchError(); + throw error_; } } diff --git a/frontend/app/src/app/modules/config/errors.ts b/frontend/app/src/app/modules/config/errors.ts index f9fcd84d..b10c7567 100644 --- a/frontend/app/src/app/modules/config/errors.ts +++ b/frontend/app/src/app/modules/config/errors.ts @@ -19,8 +19,10 @@ import {AppError} from '../../_helpers/errors'; * Error that is thrown when fetching from backend fails */ export class ConfigFetchError extends AppError { - constructor() { - super('ConfigFetchError', 'App configuration could not be fetched!'); + constructor(reason?: string) { + const defaultMessage = 'App configuration could not be fetched!'; + const message = reason ? `${defaultMessage} ${reason}` : defaultMessage; + super('ConfigFetchError', message); } }