diff --git a/src/backend/model/ObjectManagers.ts b/src/backend/model/ObjectManagers.ts index 83faa850..1729e4ed 100644 --- a/src/backend/model/ObjectManagers.ts +++ b/src/backend/model/ObjectManagers.ts @@ -12,6 +12,8 @@ import {LocationManager} from './database/LocationManager'; import {IAlbumManager} from './database/interfaces/IAlbumManager'; import {JobManager} from './jobs/JobManager'; import {IPreviewManager} from './database/interfaces/IPreviewManager'; +import {ParentDirectoryDTO} from '../../common/entities/DirectoryDTO'; +import {IObjectManager} from './database/interfaces/IObjectManager'; const LOG_TAG = '[ObjectManagers]'; @@ -19,6 +21,7 @@ export class ObjectManagers { private static instance: ObjectManagers = null; + private readonly managers: IObjectManager[]; private galleryManager: IGalleryManager; private userManager: IUserManager; private searchManager: ISearchManager; @@ -32,12 +35,20 @@ export class ObjectManagers { private albumManager: IAlbumManager; + constructor() { + this.managers = []; + } + get VersionManager(): IVersionManager { return this.versionManager; } set VersionManager(value: IVersionManager) { + if (this.versionManager) { + this.managers.splice(this.managers.indexOf(this.versionManager), 1); + } this.versionManager = value; + this.managers.push(this.versionManager); } get LocationManager(): LocationManager { @@ -45,7 +56,11 @@ export class ObjectManagers { } set LocationManager(value: LocationManager) { + if (this.locationManager) { + this.managers.splice(this.managers.indexOf(this.locationManager), 1); + } this.locationManager = value; + this.managers.push(this.locationManager); } get AlbumManager(): IAlbumManager { @@ -53,7 +68,11 @@ export class ObjectManagers { } set AlbumManager(value: IAlbumManager) { + if (this.albumManager) { + this.managers.splice(this.managers.indexOf(this.albumManager), 1); + } this.albumManager = value; + this.managers.push(this.albumManager); } get PersonManager(): IPersonManager { @@ -61,14 +80,23 @@ export class ObjectManagers { } set PersonManager(value: IPersonManager) { + if (this.personManager) { + this.managers.splice(this.managers.indexOf(this.personManager), 1); + } this.personManager = value; + this.managers.push(this.personManager); } + get PreviewManager(): IPreviewManager { return this.previewManager; } set PreviewManager(value: IPreviewManager) { + if (this.previewManager) { + this.managers.splice(this.managers.indexOf(this.previewManager), 1); + } this.previewManager = value; + this.managers.push(this.previewManager); } get IndexingManager(): IIndexingManager { @@ -76,7 +104,11 @@ export class ObjectManagers { } set IndexingManager(value: IIndexingManager) { + if (this.indexingManager) { + this.managers.splice(this.managers.indexOf(this.indexingManager), 1); + } this.indexingManager = value; + this.managers.push(this.indexingManager); } @@ -85,7 +117,11 @@ export class ObjectManagers { } set GalleryManager(value: IGalleryManager) { + if (this.galleryManager) { + this.managers.splice(this.managers.indexOf(this.galleryManager), 1); + } this.galleryManager = value; + this.managers.push(this.galleryManager); } get UserManager(): IUserManager { @@ -93,7 +129,11 @@ export class ObjectManagers { } set UserManager(value: IUserManager) { + if (this.userManager) { + this.managers.splice(this.managers.indexOf(this.userManager), 1); + } this.userManager = value; + this.managers.push(this.userManager); } get SearchManager(): ISearchManager { @@ -101,7 +141,11 @@ export class ObjectManagers { } set SearchManager(value: ISearchManager) { + if (this.searchManager) { + this.managers.splice(this.managers.indexOf(this.searchManager), 1); + } this.searchManager = value; + this.managers.push(this.searchManager); } get SharingManager(): ISharingManager { @@ -109,7 +153,11 @@ export class ObjectManagers { } set SharingManager(value: ISharingManager) { + if (this.sharingManager) { + this.managers.splice(this.managers.indexOf(this.sharingManager), 1); + } this.sharingManager = value; + this.managers.push(this.sharingManager); } get JobManager(): IJobManager { @@ -117,7 +165,11 @@ export class ObjectManagers { } set JobManager(value: IJobManager) { + if (this.jobManager) { + this.managers.splice(this.managers.indexOf(this.jobManager), 1); + } this.jobManager = value; + this.managers.push(this.jobManager); } public static getInstance(): ObjectManagers { @@ -128,6 +180,7 @@ export class ObjectManagers { } public static async reset(): Promise { + Logger.silly(LOG_TAG, 'Object manager reset begin'); if (ObjectManagers.getInstance().IndexingManager && ObjectManagers.getInstance().IndexingManager.IsSavingInProgress) { await ObjectManagers.getInstance().IndexingManager.SavingReady; @@ -140,7 +193,6 @@ export class ObjectManagers { Logger.debug(LOG_TAG, 'Object manager reset'); } - public static async InitMemoryManagers(): Promise { await ObjectManagers.reset(); this.initManagers('memory'); @@ -168,4 +220,17 @@ export class ObjectManagers { ObjectManagers.getInstance().LocationManager = new LocationManager(); } + public async onDataChange(changedDir: ParentDirectoryDTO = null): Promise { + await this.VersionManager.onNewDataVersion(changedDir); + + for (const manager of this.managers) { + if (manager === this.versionManager) { + continue; + } + if (manager.onNewDataVersion) { + await manager.onNewDataVersion(changedDir); + } + } + } + } diff --git a/src/backend/model/database/LocationManager.ts b/src/backend/model/database/LocationManager.ts index 5045459a..d2031098 100644 --- a/src/backend/model/database/LocationManager.ts +++ b/src/backend/model/database/LocationManager.ts @@ -2,8 +2,12 @@ import {GPSMetadata} from '../../../common/entities/PhotoDTO'; import * as NodeGeocoder from 'node-geocoder'; import {LocationLookupException} from '../../exceptions/LocationLookupException'; import {LRU} from '../../../common/Utils'; +import {IObjectManager} from './interfaces/IObjectManager'; +import {ParentDirectoryDTO} from '../../../common/entities/DirectoryDTO'; -export class LocationManager { +export class LocationManager implements IObjectManager { + // onNewDataVersion only need for TypeScript, otherwise the interface is not implemented. + readonly onNewDataVersion: (changedDir?: ParentDirectoryDTO) => Promise; readonly geocoder: NodeGeocoder.Geocoder; cache = new LRU(100); diff --git a/src/backend/model/database/interfaces/IAlbumManager.ts b/src/backend/model/database/interfaces/IAlbumManager.ts index f031c10f..cf84d7ea 100644 --- a/src/backend/model/database/interfaces/IAlbumManager.ts +++ b/src/backend/model/database/interfaces/IAlbumManager.ts @@ -1,7 +1,8 @@ import {SearchQueryDTO} from '../../../../common/entities/SearchQueryDTO'; import {AlbumBaseDTO} from '../../../../common/entities/album/AlbumBaseDTO'; +import {IObjectManager} from './IObjectManager'; -export interface IAlbumManager { +export interface IAlbumManager extends IObjectManager{ /** * Creates a saved search type of album */ @@ -27,5 +28,5 @@ export interface IAlbumManager { /** * Updates previews and album counts */ - onGalleryIndexUpdate(): Promise; + onNewDataVersion(): Promise; } diff --git a/src/backend/model/database/interfaces/IGalleryManager.ts b/src/backend/model/database/interfaces/IGalleryManager.ts index 3f61ceae..14c163ba 100644 --- a/src/backend/model/database/interfaces/IGalleryManager.ts +++ b/src/backend/model/database/interfaces/IGalleryManager.ts @@ -1,6 +1,7 @@ import {ParentDirectoryDTO} from '../../../../common/entities/DirectoryDTO'; +import {IObjectManager} from './IObjectManager'; -export interface IGalleryManager { +export interface IGalleryManager extends IObjectManager { listDirectory(relativeDirectoryName: string, knownLastModified?: number, knownLastScanned?: number): Promise; diff --git a/src/backend/model/database/interfaces/IIndexingManager.ts b/src/backend/model/database/interfaces/IIndexingManager.ts index edf0b753..f7a06680 100644 --- a/src/backend/model/database/interfaces/IIndexingManager.ts +++ b/src/backend/model/database/interfaces/IIndexingManager.ts @@ -1,10 +1,13 @@ import {ParentDirectoryDTO} from '../../../../common/entities/DirectoryDTO'; +import {IObjectManager} from './IObjectManager'; -export interface IIndexingManager { +export interface IIndexingManager extends IObjectManager { SavingReady: Promise; IsSavingInProgress: boolean; indexDirectory(relativeDirectoryName: string): Promise; resetDB(): Promise; + + saveToDB(scannedDirectory: ParentDirectoryDTO): Promise; } diff --git a/src/backend/model/database/interfaces/IJobManager.ts b/src/backend/model/database/interfaces/IJobManager.ts index 867d6f32..ec33990b 100644 --- a/src/backend/model/database/interfaces/IJobManager.ts +++ b/src/backend/model/database/interfaces/IJobManager.ts @@ -1,7 +1,8 @@ import {JobProgressDTO} from '../../../../common/entities/job/JobProgressDTO'; import {JobDTO} from '../../../../common/entities/job/JobDTO'; +import {IObjectManager} from './IObjectManager'; -export interface IJobManager { +export interface IJobManager extends IObjectManager { run(jobId: string, config: any, soloRun: boolean, allowParallelRun: boolean): Promise; diff --git a/src/backend/model/database/interfaces/IObjectManager.ts b/src/backend/model/database/interfaces/IObjectManager.ts new file mode 100644 index 00000000..37eff20a --- /dev/null +++ b/src/backend/model/database/interfaces/IObjectManager.ts @@ -0,0 +1,5 @@ +import {ParentDirectoryDTO} from '../../../../common/entities/DirectoryDTO'; + +export interface IObjectManager { + onNewDataVersion?: (changedDir?: ParentDirectoryDTO) => Promise; +} diff --git a/src/backend/model/database/interfaces/IPersonManager.ts b/src/backend/model/database/interfaces/IPersonManager.ts index 4c9f0e29..13c17520 100644 --- a/src/backend/model/database/interfaces/IPersonManager.ts +++ b/src/backend/model/database/interfaces/IPersonManager.ts @@ -1,14 +1,13 @@ import {PersonEntry} from '../sql/enitites/PersonEntry'; import {PersonDTO} from '../../../../common/entities/PersonDTO'; +import {IObjectManager} from './IObjectManager'; -export interface IPersonManager { +export interface IPersonManager extends IObjectManager { getAll(): Promise; get(name: string): Promise; saveAll(names: string[]): Promise; - onGalleryIndexUpdate(): Promise; - updatePerson(name: string, partialPerson: PersonDTO): Promise; } diff --git a/src/backend/model/database/interfaces/IPreviewManager.ts b/src/backend/model/database/interfaces/IPreviewManager.ts index ac95eebd..a9a2f441 100644 --- a/src/backend/model/database/interfaces/IPreviewManager.ts +++ b/src/backend/model/database/interfaces/IPreviewManager.ts @@ -1,7 +1,8 @@ import {SavedSearchDTO} from '../../../../common/entities/album/SavedSearchDTO'; import {PreviewPhotoDTO} from '../../../../common/entities/PhotoDTO'; +import {IObjectManager} from './IObjectManager'; -export interface IPreviewManager { +export interface IPreviewManager extends IObjectManager { getPreviewForDirectory(dir: { id: number, name: string, path: string }): Promise; getAlbumPreview(album: SavedSearchDTO): Promise; diff --git a/src/backend/model/database/interfaces/ISearchManager.ts b/src/backend/model/database/interfaces/ISearchManager.ts index 37272cfe..1d905bc6 100644 --- a/src/backend/model/database/interfaces/ISearchManager.ts +++ b/src/backend/model/database/interfaces/ISearchManager.ts @@ -2,8 +2,9 @@ import {AutoCompleteItem} from '../../../../common/entities/AutoCompleteItem'; import {SearchResultDTO} from '../../../../common/entities/SearchResultDTO'; import {SearchQueryDTO, SearchQueryTypes} from '../../../../common/entities/SearchQueryDTO'; import {PhotoDTO} from '../../../../common/entities/PhotoDTO'; +import {IObjectManager} from './IObjectManager'; -export interface ISearchManager { +export interface ISearchManager extends IObjectManager{ autocomplete(text: string, type: SearchQueryTypes): Promise; search(query: SearchQueryDTO): Promise; diff --git a/src/backend/model/database/interfaces/ISharingManager.ts b/src/backend/model/database/interfaces/ISharingManager.ts index 85823bc6..ffe6be87 100644 --- a/src/backend/model/database/interfaces/ISharingManager.ts +++ b/src/backend/model/database/interfaces/ISharingManager.ts @@ -1,6 +1,7 @@ import {SharingDTO} from '../../../../common/entities/SharingDTO'; +import {IObjectManager} from './IObjectManager'; -export interface ISharingManager { +export interface ISharingManager extends IObjectManager { findOne(filter: any): Promise; createSharing(sharing: SharingDTO): Promise; diff --git a/src/backend/model/database/interfaces/IUserManager.ts b/src/backend/model/database/interfaces/IUserManager.ts index d190ad65..6f642299 100644 --- a/src/backend/model/database/interfaces/IUserManager.ts +++ b/src/backend/model/database/interfaces/IUserManager.ts @@ -1,6 +1,7 @@ import {UserDTO, UserRoles} from '../../../../common/entities/UserDTO'; +import {IObjectManager} from './IObjectManager'; -export interface IUserManager { +export interface IUserManager extends IObjectManager { findOne(filter: any): Promise; find(filter: any): Promise; diff --git a/src/backend/model/database/interfaces/IVersionManager.ts b/src/backend/model/database/interfaces/IVersionManager.ts index 6360d4b4..76ecea25 100644 --- a/src/backend/model/database/interfaces/IVersionManager.ts +++ b/src/backend/model/database/interfaces/IVersionManager.ts @@ -1,5 +1,5 @@ -export interface IVersionManager { - getDataVersion(): Promise; +import {IObjectManager} from './IObjectManager'; - updateDataVersion(): Promise; +export interface IVersionManager extends IObjectManager { + getDataVersion(): Promise; } diff --git a/src/backend/model/database/sql/AlbumManager.ts b/src/backend/model/database/sql/AlbumManager.ts index d9f8a936..3da855c4 100644 --- a/src/backend/model/database/sql/AlbumManager.ts +++ b/src/backend/model/database/sql/AlbumManager.ts @@ -48,7 +48,7 @@ export class AlbumManager implements IAlbumManager { 'directory.path']).getMany(); } - public async onGalleryIndexUpdate(): Promise { + public async onNewDataVersion(): Promise { await this.updateAlbums(); } diff --git a/src/backend/model/database/sql/GalleryManager.ts b/src/backend/model/database/sql/GalleryManager.ts index 16d52046..4f48102d 100644 --- a/src/backend/model/database/sql/GalleryManager.ts +++ b/src/backend/model/database/sql/GalleryManager.ts @@ -72,7 +72,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager { // not indexed since a while, index it in a lazy manner if ((Date.now() - dir.lastScanned > Config.Server.Indexing.cachedFolderTimeout && - Config.Server.Indexing.reIndexingSensitivity >= ReIndexingSensitivity.medium) || + Config.Server.Indexing.reIndexingSensitivity >= ReIndexingSensitivity.medium) || Config.Server.Indexing.reIndexingSensitivity >= ReIndexingSensitivity.high) { // on the fly reindexing @@ -224,7 +224,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager { dir.media = []; dir.preview = await ObjectManagers.getInstance().PreviewManager.getPreviewForDirectory(dir); dir.isPartial = true; - + if (dir.preview) { dir.preview.readyThumbnails = []; dir.preview.readyIcon = false; diff --git a/src/backend/model/database/sql/IndexingManager.ts b/src/backend/model/database/sql/IndexingManager.ts index 6e055426..0b91b10d 100644 --- a/src/backend/model/database/sql/IndexingManager.ts +++ b/src/backend/model/database/sql/IndexingManager.ts @@ -95,6 +95,23 @@ export class IndexingManager implements IIndexingManager { .execute(); } + public async saveToDB(scannedDirectory: ParentDirectoryDTO): Promise { + this.isSaving = true; + try { + const connection = await SQLConnection.getConnection(); + const serverSideConfigs = scannedDirectory.metaFile.filter(m => !!ServerPG2ConfMap[m.name]); + scannedDirectory.metaFile = scannedDirectory.metaFile.filter(m => !ServerPG2ConfMap[m.name]); + const currentDirId: number = await this.saveParentDir(connection, scannedDirectory); + await this.saveChildDirs(connection, currentDirId, scannedDirectory); + await this.saveMedia(connection, currentDirId, scannedDirectory.media); + await this.saveMetaFiles(connection, currentDirId, scannedDirectory); + await IndexingManager.processServerSidePG2Conf(serverSideConfigs); + await ObjectManagers.getInstance().onDataChange(scannedDirectory); + } finally { + this.isSaving = false; + } + } + // Todo fix it, once typeorm support connection pools for sqlite /** * Queues up a directory to save to the DB. @@ -359,25 +376,6 @@ export class IndexingManager implements IIndexingManager { } - protected async saveToDB(scannedDirectory: ParentDirectoryDTO): Promise { - this.isSaving = true; - try { - const connection = await SQLConnection.getConnection(); - const serverSideConfigs = scannedDirectory.metaFile.filter(m => !!ServerPG2ConfMap[m.name]); - scannedDirectory.metaFile = scannedDirectory.metaFile.filter(m => !ServerPG2ConfMap[m.name]); - const currentDirId: number = await this.saveParentDir(connection, scannedDirectory); - await this.saveChildDirs(connection, currentDirId, scannedDirectory); - await this.saveMedia(connection, currentDirId, scannedDirectory.media); - await this.saveMetaFiles(connection, currentDirId, scannedDirectory); - await ObjectManagers.getInstance().PersonManager.onGalleryIndexUpdate(); - await ObjectManagers.getInstance().AlbumManager.onGalleryIndexUpdate(); - await ObjectManagers.getInstance().VersionManager.updateDataVersion(); - await IndexingManager.processServerSidePG2Conf(serverSideConfigs); - } finally { - this.isSaving = false; - } - } - private async saveChunk(repository: Repository, entities: T[], size: number): Promise { if (entities.length === 0) { return []; diff --git a/src/backend/model/database/sql/PersonManager.ts b/src/backend/model/database/sql/PersonManager.ts index 90a22845..b81bc2d2 100644 --- a/src/backend/model/database/sql/PersonManager.ts +++ b/src/backend/model/database/sql/PersonManager.ts @@ -77,7 +77,7 @@ export class PersonManager implements ISQLPersonManager { } - public async onGalleryIndexUpdate(): Promise { + public async onNewDataVersion(): Promise { await this.updateCounts(); await this.updateSamplePhotos(); await this.loadAll(); diff --git a/src/backend/model/database/sql/VersionManager.ts b/src/backend/model/database/sql/VersionManager.ts index b6f8c0fe..5495c2b5 100644 --- a/src/backend/model/database/sql/VersionManager.ts +++ b/src/backend/model/database/sql/VersionManager.ts @@ -16,7 +16,7 @@ export class VersionManager implements IVersionManager { async getDataVersion(): Promise { if (this.latestDirectoryStatus === null) { - await this.updateDataVersion(); + await this.onNewDataVersion(); } if (!this.latestDirectoryStatus) { @@ -31,7 +31,7 @@ export class VersionManager implements IVersionManager { return crypto.createHash('md5').update(versionString).digest('hex'); } - async updateDataVersion(): Promise { + async onNewDataVersion(): Promise { const connection = await SQLConnection.getConnection(); const dir = await connection.getRepository(DirectoryEntity) .createQueryBuilder('directory') diff --git a/test/backend/DBTestHelper.ts b/test/backend/DBTestHelper.ts index 5fc08ce5..cd6b0b96 100644 --- a/test/backend/DBTestHelper.ts +++ b/test/backend/DBTestHelper.ts @@ -5,7 +5,6 @@ import {SQLConnection} from '../../src/backend/model/database/sql/SQLConnection' import {DatabaseType} from '../../src/common/config/private/PrivateConfig'; import {ProjectPath} from '../../src/backend/ProjectPath'; import {DirectoryBaseDTO, ParentDirectoryDTO} from '../../src/common/entities/DirectoryDTO'; -import {DirectoryEntity} from '../../src/backend/model/database/sql/enitites/DirectoryEntity'; import {ObjectManagers} from '../../src/backend/model/ObjectManagers'; import {DiskMangerWorker} from '../../src/backend/model/threading/DiskMangerWorker'; import {IndexingManager} from '../../src/backend/model/database/sql/IndexingManager'; @@ -89,8 +88,7 @@ export class DBTestHelper { ObjectManagers.getInstance().IndexingManager.indexDirectory = () => Promise.resolve(null); - const im = new IndexingManagerTest(); - await im.saveToDB(directory as ParentDirectoryDTO); + await ObjectManagers.getInstance().IndexingManager.saveToDB(directory as ParentDirectoryDTO); // not saving subdirs. saveToDB destroys data // await im.saveToDB(subDir); // await im.saveToDB(subDir2);