diff --git a/src/script/backup/BackupService.ts b/src/script/backup/BackupService.ts index c86ce5830de..8e407463e72 100644 --- a/src/script/backup/BackupService.ts +++ b/src/script/backup/BackupService.ts @@ -19,6 +19,7 @@ import type Dexie from 'dexie'; import DexieBatch from 'dexie-batch'; +import {container} from 'tsyringe'; import {Logger, getLogger} from 'Util/Logger'; @@ -26,7 +27,6 @@ import {StorageSchemata, StorageService} from '../storage'; export class BackupService { private readonly logger: Logger; - private readonly storageService: StorageService; static get CONFIG() { return { @@ -35,9 +35,8 @@ export class BackupService { }; } - constructor(storageService: StorageService) { + constructor(private readonly storageService = container.resolve(StorageService)) { this.logger = getLogger('BackupService'); - this.storageService = storageService; } public async exportTable(table: Dexie.Table, onProgress: (batch: any[]) => void): Promise { diff --git a/src/script/client/ClientService.ts b/src/script/client/ClientService.ts index 43c150a348d..3c8692042ce 100644 --- a/src/script/client/ClientService.ts +++ b/src/script/client/ClientService.ts @@ -22,12 +22,12 @@ import {container} from 'tsyringe'; import {Logger, getLogger} from 'Util/Logger'; -import type {ClientRecord, StorageService} from '../storage'; +import type {ClientRecord} from '../storage'; +import {StorageService} from '../storage'; import {StorageSchemata} from '../storage/StorageSchemata'; import {APIClient} from '../service/APIClientSingleton'; export class ClientService { - private readonly storageService: StorageService; private readonly logger: Logger; private readonly CLIENT_STORE_NAME: string; @@ -39,8 +39,10 @@ export class ClientService { return '/users'; } - constructor(storageService: StorageService, private readonly apiClient = container.resolve(APIClient)) { - this.storageService = storageService; + constructor( + private readonly storageService = container.resolve(StorageService), + private readonly apiClient = container.resolve(APIClient), + ) { this.logger = getLogger('ClientService'); this.CLIENT_STORE_NAME = StorageSchemata.OBJECT_STORE.CLIENTS; diff --git a/src/script/conversation/ConversationService.ts b/src/script/conversation/ConversationService.ts index 13451f9647c..b9792f6eaf0 100644 --- a/src/script/conversation/ConversationService.ts +++ b/src/script/conversation/ConversationService.ts @@ -49,22 +49,20 @@ import type {Conversation as ConversationEntity, SerializedConversation} from '. import type {EventService} from '../event/EventService'; import {MessageCategory} from '../message/MessageCategory'; import {search as fullTextSearch} from '../search/FullTextSearch'; -import type {StorageService} from '../storage'; +import {StorageService} from '../storage'; import {StorageSchemata} from '../storage/StorageSchemata'; import {APIClient} from '../service/APIClientSingleton'; export class ConversationService { private readonly eventService: EventService; private readonly logger: Logger; - private readonly storageService: StorageService; constructor( eventService: EventService, - storageService: StorageService, + private readonly storageService = container.resolve(StorageService), private readonly apiClient = container.resolve(APIClient), ) { this.eventService = eventService; - this.storageService = storageService; this.logger = getLogger('ConversationService'); } diff --git a/src/script/event/EventService.ts b/src/script/event/EventService.ts index 7b54732cac5..7cae420d107 100644 --- a/src/script/event/EventService.ts +++ b/src/script/event/EventService.ts @@ -18,6 +18,7 @@ */ import type {Dexie} from 'dexie'; +import {container} from 'tsyringe'; import {getLogger, Logger} from 'Util/Logger'; @@ -50,7 +51,7 @@ export const compareEventsByTime = (eventA: EventRecord, eventB: EventRecord) => export class EventService { logger: Logger; - constructor(public readonly storageService: StorageService) { + constructor(public readonly storageService = container.resolve(StorageService)) { this.logger = getLogger('EventService'); } diff --git a/src/script/event/EventServiceNoCompound.ts b/src/script/event/EventServiceNoCompound.ts index a04e51b3986..ade462099ed 100644 --- a/src/script/event/EventServiceNoCompound.ts +++ b/src/script/event/EventServiceNoCompound.ts @@ -17,6 +17,8 @@ * */ +import {container} from 'tsyringe'; + import { EventService, Includes, @@ -35,7 +37,7 @@ type DateComparator = (dateA: Date, dateB: Date) => boolean; // TODO: This function can be removed once Microsoft Edge's IndexedDB supports compound indices: // - https://developer.microsoft.com/en-us/microsoft-edge/platform/status/indexeddbarraysandmultientrysupport/ export class EventServiceNoCompound extends EventService { - constructor(storageService: StorageService) { + constructor(storageService = container.resolve(StorageService)) { super(storageService); } diff --git a/src/script/event/NotificationService.ts b/src/script/event/NotificationService.ts index 54ffe8a7a13..a63461cca30 100644 --- a/src/script/event/NotificationService.ts +++ b/src/script/event/NotificationService.ts @@ -31,7 +31,6 @@ import {APIClient} from '../service/APIClientSingleton'; export class NotificationService { private readonly logger: Logger; - private readonly storageService: StorageService; private readonly AMPLIFY_STORE_NAME: string; static get CONFIG() { @@ -42,8 +41,10 @@ export class NotificationService { }; } - constructor(storageService: StorageService, private readonly apiClient = container.resolve(APIClient)) { - this.storageService = storageService; + constructor( + private readonly storageService = container.resolve(StorageService), + private readonly apiClient = container.resolve(APIClient), + ) { this.logger = getLogger('NotificationService'); this.AMPLIFY_STORE_NAME = StorageSchemata.OBJECT_STORE.AMPLIFY; } diff --git a/src/script/main/app.ts b/src/script/main/app.ts index c70bafc8f7b..215404a67e4 100644 --- a/src/script/main/app.ts +++ b/src/script/main/app.ts @@ -230,13 +230,13 @@ class App { repositories.giphy = new GiphyRepository(new GiphyService()); repositories.properties = new PropertiesRepository(new PropertiesService(), selfService); repositories.serverTime = serverTimeHandler; - repositories.storage = new StorageRepository(this.service.storage); + repositories.storage = new StorageRepository(); repositories.cryptography = new CryptographyRepository(new CryptographyService(), repositories.storage); - repositories.client = new ClientRepository(new ClientService(this.service.storage), repositories.cryptography); + repositories.client = new ClientRepository(new ClientService(), repositories.cryptography); repositories.media = new MediaRepository(new PermissionRepository()); repositories.user = new UserRepository( - new UserService(this.service.storage), + new UserService(), repositories.asset, selfService, repositories.client, @@ -297,7 +297,7 @@ class App { readReceiptMiddleware.processEvent.bind(readReceiptMiddleware), ]); repositories.backup = new BackupRepository( - new BackupService(this.service.storage), + new BackupService(), repositories.connection, repositories.conversation, repositories.user, @@ -341,17 +341,16 @@ class App { * @returns All services */ private _setupServices(encryptedEngine: SQLeetEngine) { - const storageService = new StorageService(encryptedEngine); - const eventService = Runtime.isEdge() - ? new EventServiceNoCompound(storageService) - : new EventService(storageService); + container.registerInstance(StorageService, new StorageService(encryptedEngine)); + const storageService = container.resolve(StorageService); + const eventService = Runtime.isEdge() ? new EventServiceNoCompound() : new EventService(); return { asset: container.resolve(AssetService), - conversation: new ConversationService(eventService, storageService), + conversation: new ConversationService(eventService), event: eventService, integration: new IntegrationService(), - notification: new NotificationService(storageService), + notification: new NotificationService(), storage: storageService, webSocket: new WebSocketService(), }; @@ -609,7 +608,7 @@ class App { } } - await this.service.storage.init(userEntity.id); + await container.resolve(StorageService).init(userEntity.id); this.repository.client.init(userEntity); await this.repository.properties.init(userEntity); this._checkUserInformation(userEntity); diff --git a/src/script/storage/StorageRepository.ts b/src/script/storage/StorageRepository.ts index 668260754a5..21b52448174 100644 --- a/src/script/storage/StorageRepository.ts +++ b/src/script/storage/StorageRepository.ts @@ -18,9 +18,10 @@ */ import {Logger, getLogger} from 'Util/Logger'; +import {container} from 'tsyringe'; import {StorageSchemata} from '../storage/StorageSchemata'; -import type {StorageService} from './StorageService'; +import {StorageService} from './StorageService'; import {StorageError} from '../error/StorageError'; type AmplifyRecord = {key: string; value: string}; @@ -28,7 +29,6 @@ type AmplifyRecord = {key: string; value: string}; export class StorageRepository { private readonly AMPLIFY_STORE_NAME: string; private readonly logger: Logger; - public readonly storageService: StorageService; static get CONFIG() { return { @@ -42,8 +42,7 @@ export class StorageRepository { }; } - constructor(storageService: StorageService) { - this.storageService = storageService; + constructor(public readonly storageService = container.resolve(StorageService)) { this.logger = getLogger('StorageRepository'); this.AMPLIFY_STORE_NAME = StorageSchemata.OBJECT_STORE.AMPLIFY; } diff --git a/src/script/storage/StorageService.ts b/src/script/storage/StorageService.ts index 109f659301d..25eeac20223 100644 --- a/src/script/storage/StorageService.ts +++ b/src/script/storage/StorageService.ts @@ -22,6 +22,7 @@ import {ClientType} from '@wireapp/api-client/dist/client/'; import {IndexedDBEngine} from '@wireapp/store-engine-dexie'; import {SQLeetEngine} from '@wireapp/store-engine-sqleet'; import Dexie from 'dexie'; +import {singleton} from 'tsyringe'; import {getEphemeralValue} from 'Util/ephemeralValueStore'; import {Logger, getLogger} from 'Util/Logger'; @@ -49,6 +50,7 @@ enum DEXIE_CRUD_EVENT { UPDATING = 'updating', } +@singleton() export class StorageService { // Quickfix to use table name index; can be removed once we have proper db instance typings: https://dexie.org/docs/Typescript#create-a-subclass public db?: Dexie & DexieObservable & {[tableName: string]: any}; diff --git a/src/script/user/UserService.ts b/src/script/user/UserService.ts index b92f3a5aa7f..1016b2a20a8 100644 --- a/src/script/user/UserService.ts +++ b/src/script/user/UserService.ts @@ -24,18 +24,18 @@ import {Logger, getLogger} from 'Util/Logger'; import type {User} from '../entity/User'; import {StorageSchemata} from '../storage/StorageSchemata'; -import type {StorageService} from '../storage/StorageService'; +import {StorageService} from '../storage/StorageService'; import {APIClient} from '../service/APIClientSingleton'; export class UserService { private readonly logger: Logger; - private readonly storageService: StorageService; private readonly USER_STORE_NAME: string; - constructor(storageService: StorageService, private readonly apiClient = container.resolve(APIClient)) { + constructor( + private readonly storageService = container.resolve(StorageService), + private readonly apiClient = container.resolve(APIClient), + ) { this.logger = getLogger('UserService'); - this.storageService = storageService; - this.USER_STORE_NAME = StorageSchemata.OBJECT_STORE.USERS; } diff --git a/test/helper/TestFactory.js b/test/helper/TestFactory.js index b15aaa8d0c2..af6c1000c42 100644 --- a/test/helper/TestFactory.js +++ b/test/helper/TestFactory.js @@ -68,6 +68,9 @@ import {SearchService} from 'src/script/search/SearchService'; import {AssetRepository} from '../../src/script/assets/AssetRepository'; export class TestFactory { + constructor() { + container.clearInstances(); + } /** * @returns {Promise} The authentication repository. */ @@ -80,7 +83,8 @@ export class TestFactory { * @returns {Promise} The storage repository. */ async exposeStorageActors() { - this.storage_service = new StorageService(); + container.registerInstance(StorageService, new StorageService()); + this.storage_service = container.resolve(StorageService); if (!this.storage_service.db) { this.storage_service.init(entities.user.john_doe.id, false); } @@ -178,7 +182,7 @@ export class TestFactory { this.event_service = new EventService(this.storage_service); this.event_service_no_compound = new EventServiceNoCompound(this.storage_service); this.notification_service = new NotificationService(this.storage_service); - this.conversation_service = new ConversationService(this.event_service, this.storage_service); + this.conversation_service = new ConversationService(this.event_service); this.event_repository = new EventRepository( this.event_service, @@ -255,7 +259,7 @@ export class TestFactory { await this.exposeTeamActors(); await this.exposeEventActors(); - this.conversation_service = new ConversationService(this.event_service, this.storage_service); + this.conversation_service = new ConversationService(this.event_service); this.propertyRepository = new PropertiesRepository(new PropertiesService(), new SelfService()); diff --git a/test/unit_tests/storage/StorageServiceSpec.js b/test/unit_tests/storage/StorageServiceSpec.js index 718242eab9f..08b330d884e 100644 --- a/test/unit_tests/storage/StorageServiceSpec.js +++ b/test/unit_tests/storage/StorageServiceSpec.js @@ -17,13 +17,15 @@ * */ +import {container} from 'tsyringe'; + import {StorageSchemata, StorageService} from 'src/script/storage/'; import {StorageError} from 'src/script/error/StorageError'; describe('StorageRepository', () => { describe('save', () => { it('does not save "null" values', () => { - const storageService = new StorageService(); + const storageService = container.resolve(StorageService); return storageService .save(StorageSchemata.OBJECT_STORE.AMPLIFY, 'primary_key', null) .then(fail)