1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2025-01-26 05:27:35 +02:00

improving caching with gallery version string

This commit is contained in:
Patrik J. Braun 2019-02-15 11:47:09 -05:00
parent 24eb4f0815
commit 2017fc642c
31 changed files with 329 additions and 124 deletions

View File

@ -1,6 +1,6 @@
import {NextFunction, Request, Response} from 'express';
import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {ObjectManagerRepository} from '../model/ObjectManagerRepository';
import {ObjectManagers} from '../model/ObjectManagers';
import {Logger} from '../Logger';
import {SQLConnection} from '../model/sql/SQLConnection';
import {DataBaseConfig, DatabaseType, IndexingConfig, ThumbnailConfig} from '../../common/config/private/IPrivateConfig';
@ -25,7 +25,7 @@ export class AdminMWs {
}
const galleryManager = <ISQLGalleryManager>ObjectManagerRepository.getInstance().GalleryManager;
const galleryManager = <ISQLGalleryManager>ObjectManagers.getInstance().GalleryManager;
try {
req.resultPipe = {
directories: await galleryManager.countDirectories(),
@ -49,7 +49,7 @@ export class AdminMWs {
}
const galleryManager = <ISQLGalleryManager>ObjectManagerRepository.getInstance().GalleryManager;
const galleryManager = <ISQLGalleryManager>ObjectManagers.getInstance().GalleryManager;
try {
req.resultPipe = await galleryManager.getPossibleDuplicates();
return next();
@ -86,11 +86,11 @@ export class AdminMWs {
Logger.info(LOG_TAG, 'new config:');
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
await ObjectManagerRepository.reset();
await ObjectManagers.reset();
if (Config.Server.database.type !== DatabaseType.memory) {
await ObjectManagerRepository.InitSQLManagers();
await ObjectManagers.InitSQLManagers();
} else {
await ObjectManagerRepository.InitMemoryManagers();
await ObjectManagers.InitMemoryManagers();
}
return next();
@ -418,7 +418,7 @@ export class AdminMWs {
public static startIndexing(req: Request, res: Response, next: NextFunction) {
try {
const createThumbnails: boolean = (<IndexingDTO>req.body).createThumbnails || false;
ObjectManagerRepository.getInstance().IndexingTaskManager.startIndexing(createThumbnails);
ObjectManagers.getInstance().IndexingTaskManager.startIndexing(createThumbnails);
req.resultPipe = 'ok';
return next();
} catch (err) {
@ -432,7 +432,7 @@ export class AdminMWs {
public static getIndexingProgress(req: Request, res: Response, next: NextFunction) {
try {
req.resultPipe = ObjectManagerRepository.getInstance().IndexingTaskManager.getProgress();
req.resultPipe = ObjectManagers.getInstance().IndexingTaskManager.getProgress();
return next();
} catch (err) {
if (err instanceof Error) {
@ -444,7 +444,7 @@ export class AdminMWs {
public static cancelIndexing(req: Request, res: Response, next: NextFunction) {
try {
ObjectManagerRepository.getInstance().IndexingTaskManager.cancelIndexing();
ObjectManagers.getInstance().IndexingTaskManager.cancelIndexing();
req.resultPipe = 'ok';
return next();
} catch (err) {
@ -457,7 +457,7 @@ export class AdminMWs {
public static async resetIndexes(req: Express.Request, res: Response, next: NextFunction) {
try {
await ObjectManagerRepository.getInstance().IndexingTaskManager.reset();
await ObjectManagers.getInstance().IndexingTaskManager.reset();
req.resultPipe = 'ok';
return next();
} catch (err) {

View File

@ -3,7 +3,7 @@ import * as fs from 'fs';
import {NextFunction, Request, Response} from 'express';
import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {DirectoryDTO} from '../../common/entities/DirectoryDTO';
import {ObjectManagerRepository} from '../model/ObjectManagerRepository';
import {ObjectManagers} from '../model/ObjectManagers';
import {SearchTypes} from '../../common/entities/AutoCompleteItem';
import {ContentWrapper} from '../../common/entities/ConentWrapper';
import {PhotoDTO} from '../../common/entities/PhotoDTO';
@ -32,7 +32,7 @@ export class GalleryMWs {
}
try {
const directory = await ObjectManagerRepository.getInstance()
const directory = await ObjectManagers.getInstance()
.GalleryManager.listDirectory(directoryName,
parseInt(req.query[QueryParams.gallery.knownLastModified], 10),
parseInt(req.query[QueryParams.gallery.knownLastScanned], 10));
@ -146,7 +146,7 @@ export class GalleryMWs {
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'Input error: to date is earlier than from date'));
}
const photo = await ObjectManagerRepository.getInstance()
const photo = await ObjectManagers.getInstance()
.GalleryManager.getRandomPhoto(query);
if (!photo) {
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'No photo found'));
@ -189,11 +189,11 @@ export class GalleryMWs {
}
let type: SearchTypes;
if (req.query.type) {
type = parseInt(req.query.type, 10);
if (req.query[QueryParams.gallery.search.type]) {
type = parseInt(req.query[QueryParams.gallery.search.type], 10);
}
try {
const result = await ObjectManagerRepository.getInstance().SearchManager.search(req.params.text, type);
const result = await ObjectManagers.getInstance().SearchManager.search(req.params.text, type);
result.directories.forEach(dir => dir.media = dir.media || []);
req.resultPipe = new ContentWrapper(null, result);
@ -213,7 +213,7 @@ export class GalleryMWs {
}
try {
const result = await ObjectManagerRepository.getInstance().SearchManager.instantSearch(req.params.text);
const result = await ObjectManagers.getInstance().SearchManager.instantSearch(req.params.text);
result.directories.forEach(dir => dir.media = dir.media || []);
req.resultPipe = new ContentWrapper(null, result);
@ -232,7 +232,7 @@ export class GalleryMWs {
}
try {
req.resultPipe = await ObjectManagerRepository.getInstance().SearchManager.autocomplete(req.params.text);
req.resultPipe = await ObjectManagers.getInstance().SearchManager.autocomplete(req.params.text);
return next();
} catch (err) {
return next(new ErrorDTO(ErrorCodes.GENERAL_ERROR, 'Error during searching', err));

View File

@ -1,6 +1,6 @@
import {NextFunction, Request, Response} from 'express';
import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {ObjectManagerRepository} from '../model/ObjectManagerRepository';
import {ObjectManagers} from '../model/ObjectManagers';
const LOG_TAG = '[PersonMWs]';
@ -12,7 +12,7 @@ export class PersonMWs {
try {
req.resultPipe = await ObjectManagerRepository.getInstance()
req.resultPipe = await ObjectManagers.getInstance()
.PersonManager.getAll();
return next();
@ -29,7 +29,7 @@ export class PersonMWs {
}
const name = req.params.name;
try {
const photo = await ObjectManagerRepository.getInstance()
const photo = await ObjectManagers.getInstance()
.PersonManager.getSamplePhoto(name);
if (photo === null) {

View File

@ -1,6 +1,6 @@
import {NextFunction, Request, Response} from 'express';
import {CreateSharingDTO, SharingDTO} from '../../common/entities/SharingDTO';
import {ObjectManagerRepository} from '../model/ObjectManagerRepository';
import {ObjectManagers} from '../model/ObjectManagers';
import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {Config} from '../../common/config/private/Config';
import {QueryParams} from '../../common/QueryParams';
@ -28,7 +28,7 @@ export class SharingMWs {
const sharingKey = req.params[QueryParams.gallery.sharingKey_long];
try {
req.resultPipe = await ObjectManagerRepository.getInstance().SharingManager.findOne({sharingKey: sharingKey});
req.resultPipe = await ObjectManagers.getInstance().SharingManager.findOne({sharingKey: sharingKey});
return next();
} catch (err) {
@ -51,7 +51,7 @@ export class SharingMWs {
while (true) {
try {
await ObjectManagerRepository.getInstance().SharingManager.findOne({sharingKey: sharingKey});
await ObjectManagers.getInstance().SharingManager.findOne({sharingKey: sharingKey});
sharingKey = this.generateKey();
} catch (err) {
break;
@ -73,7 +73,7 @@ export class SharingMWs {
try {
req.resultPipe = await ObjectManagerRepository.getInstance().SharingManager.createSharing(sharing);
req.resultPipe = await ObjectManagers.getInstance().SharingManager.createSharing(sharing);
return next();
} catch (err) {
@ -103,7 +103,7 @@ export class SharingMWs {
};
try {
req.resultPipe = await ObjectManagerRepository.getInstance().SharingManager.updateSharing(sharing);
req.resultPipe = await ObjectManagers.getInstance().SharingManager.updateSharing(sharing);
return next();
} catch (err) {
return next(new ErrorDTO(ErrorCodes.GENERAL_ERROR, 'Error during updating sharing link', err));

View File

@ -0,0 +1,27 @@
import {NextFunction, Request, Response} from 'express';
import {ObjectManagers} from '../model/ObjectManagers';
import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {CostumHeaders} from '../../common/CostumHeaders';
const LOG_TAG = '[VersionMWs]';
export class VersionMWs {
/**
* This version data is mainly used on the client side to invalidate the cache
* @param req
* @param res
* @param next
*/
public static async injectGalleryVersion(req: Request, res: Response, next: NextFunction) {
try {
res.header(CostumHeaders.dataVersion, await ObjectManagers.getInstance().VersionManager.getDataVersion());
next();
} catch (err) {
return next(new ErrorDTO(ErrorCodes.GENERAL_ERROR, 'Can not get data version', err.toString()));
}
}
}

View File

@ -2,7 +2,7 @@
import {NextFunction, Request, Response} from 'express';
import {ErrorCodes, ErrorDTO} from '../../../common/entities/Error';
import {UserDTO, UserRoles} from '../../../common/entities/UserDTO';
import {ObjectManagerRepository} from '../../model/ObjectManagerRepository';
import {ObjectManagers} from '../../model/ObjectManagers';
import {Config} from '../../../common/config/private/Config';
import {PasswordHelper} from '../../model/PasswordHelper';
import {Utils} from '../../../common/Utils';
@ -91,7 +91,7 @@ export class AuthenticationMWs {
try {
const password = (req.body ? req.body.password : null) || null;
const sharing = await ObjectManagerRepository.getInstance().SharingManager.findOne({
const sharing = await ObjectManagers.getInstance().SharingManager.findOne({
sharingKey: req.query[QueryParams.gallery.sharingKey_short] || req.params[QueryParams.gallery.sharingKey_long]
});
@ -134,7 +134,7 @@ export class AuthenticationMWs {
}
try {
// lets find the user
const user = Utils.clone(await ObjectManagerRepository.getInstance().UserManager.findOne({
const user = Utils.clone(await ObjectManagers.getInstance().UserManager.findOne({
name: req.body.loginCredential.username,
password: req.body.loginCredential.password
}));
@ -155,7 +155,7 @@ export class AuthenticationMWs {
private static async getSharingUser(req: Request) {
if (Config.Client.Sharing.enabled === true &&
(!!req.params[QueryParams.gallery.sharingKey_short] || !!req.params[QueryParams.gallery.sharingKey_long])) {
const sharing = await ObjectManagerRepository.getInstance().SharingManager.findOne({
const sharing = await ObjectManagers.getInstance().SharingManager.findOne({
sharingKey: req.query[QueryParams.gallery.sharingKey_short] || req.params[QueryParams.gallery.sharingKey_long],
});
if (!sharing || sharing.expires < Date.now()) {

View File

@ -1,6 +1,6 @@
import {NextFunction, Request, Response} from 'express';
import {ErrorCodes, ErrorDTO} from '../../../common/entities/Error';
import {ObjectManagerRepository} from '../../model/ObjectManagerRepository';
import {ObjectManagers} from '../../model/ObjectManagers';
import {Utils} from '../../../common/Utils';
import {Config} from '../../../common/config/private/Config';
@ -18,7 +18,7 @@ export class UserMWs {
}
try {
await ObjectManagerRepository.getInstance().UserManager.changePassword(req.body.userModReq);
await ObjectManagers.getInstance().UserManager.changePassword(req.body.userModReq);
return next();
} catch (err) {
@ -36,7 +36,7 @@ export class UserMWs {
}
try {
await ObjectManagerRepository.getInstance().UserManager.createUser(req.body.newUser);
await ObjectManagers.getInstance().UserManager.createUser(req.body.newUser);
return next();
} catch (err) {
@ -56,7 +56,7 @@ export class UserMWs {
try {
await ObjectManagerRepository.getInstance().UserManager.deleteUser(req.params.id);
await ObjectManagers.getInstance().UserManager.deleteUser(req.params.id);
return next();
} catch (err) {
@ -76,7 +76,7 @@ export class UserMWs {
}
try {
await ObjectManagerRepository.getInstance().UserManager.changeRole(req.params.id, req.body.newRole);
await ObjectManagers.getInstance().UserManager.changeRole(req.params.id, req.body.newRole);
return next();
} catch (err) {
@ -91,7 +91,7 @@ export class UserMWs {
}
try {
let result = await ObjectManagerRepository.getInstance().UserManager.find({});
let result = await ObjectManagers.getInstance().UserManager.find({});
result = Utils.clone(result);
for (let i = 0; i < result.length; i++) {
result[i].password = '';

View File

@ -1,7 +1,7 @@
import {NextFunction, Request, Response} from 'express';
import {ErrorCodes, ErrorDTO} from '../../../common/entities/Error';
import {UserRoles} from '../../../common/entities/UserDTO';
import {ObjectManagerRepository} from '../../model/ObjectManagerRepository';
import {ObjectManagers} from '../../model/ObjectManagers';
export class UserRequestConstrainsMWs {
@ -40,7 +40,7 @@ export class UserRequestConstrainsMWs {
// TODO: fix it!
try {
const result = await ObjectManagerRepository.getInstance().UserManager.find({minRole: UserRoles.Admin});
const result = await ObjectManagers.getInstance().UserManager.find({minRole: UserRoles.Admin});
if (result.length <= 1) {
return next(new ErrorDTO(ErrorCodes.GENERAL_ERROR));
}

View File

@ -7,10 +7,11 @@ import {Logger} from '../Logger';
import {IIndexingTaskManager} from './interfaces/IIndexingTaskManager';
import {IIndexingManager} from './interfaces/IIndexingManager';
import {IPersonManager} from './interfaces/IPersonManager';
import {IVersionManager} from './interfaces/IVersionManager';
export class ObjectManagerRepository {
export class ObjectManagers {
private static _instance: ObjectManagerRepository = null;
private static _instance: ObjectManagers = null;
private _galleryManager: IGalleryManager;
private _userManager: IUserManager;
@ -19,6 +20,17 @@ export class ObjectManagerRepository {
private _indexingManager: IIndexingManager;
private _indexingTaskManager: IIndexingTaskManager;
private _personManager: IPersonManager;
private _versionManager: IVersionManager;
get VersionManager(): IVersionManager {
return this._versionManager;
}
set VersionManager(value: IVersionManager) {
this._versionManager = value;
}
get PersonManager(): IPersonManager {
return this._personManager;
@ -78,7 +90,7 @@ export class ObjectManagerRepository {
public static getInstance() {
if (this._instance === null) {
this._instance = new ObjectManagerRepository();
this._instance = new ObjectManagers();
}
return this._instance;
}
@ -89,7 +101,7 @@ export class ObjectManagerRepository {
}
public static async InitMemoryManagers() {
await ObjectManagerRepository.reset();
await ObjectManagers.reset();
const GalleryManager = require('./memory/GalleryManager').GalleryManager;
const UserManager = require('./memory/UserManager').UserManager;
const SearchManager = require('./memory/SearchManager').SearchManager;
@ -97,17 +109,19 @@ export class ObjectManagerRepository {
const IndexingTaskManager = require('./memory/IndexingTaskManager').IndexingTaskManager;
const IndexingManager = require('./memory/IndexingManager').IndexingManager;
const PersonManager = require('./memory/PersonManager').PersonManager;
ObjectManagerRepository.getInstance().GalleryManager = new GalleryManager();
ObjectManagerRepository.getInstance().UserManager = new UserManager();
ObjectManagerRepository.getInstance().SearchManager = new SearchManager();
ObjectManagerRepository.getInstance().SharingManager = new SharingManager();
ObjectManagerRepository.getInstance().IndexingTaskManager = new IndexingTaskManager();
ObjectManagerRepository.getInstance().IndexingManager = new IndexingManager();
ObjectManagerRepository.getInstance().PersonManager = new PersonManager();
const VersionManager = require('./memory/VersionManager').VersionManager;
ObjectManagers.getInstance().GalleryManager = new GalleryManager();
ObjectManagers.getInstance().UserManager = new UserManager();
ObjectManagers.getInstance().SearchManager = new SearchManager();
ObjectManagers.getInstance().SharingManager = new SharingManager();
ObjectManagers.getInstance().IndexingTaskManager = new IndexingTaskManager();
ObjectManagers.getInstance().IndexingManager = new IndexingManager();
ObjectManagers.getInstance().PersonManager = new PersonManager();
ObjectManagers.getInstance().VersionManager = new VersionManager();
}
public static async InitSQLManagers() {
await ObjectManagerRepository.reset();
await ObjectManagers.reset();
await SQLConnection.init();
const GalleryManager = require('./sql/GalleryManager').GalleryManager;
const UserManager = require('./sql/UserManager').UserManager;
@ -116,13 +130,15 @@ export class ObjectManagerRepository {
const IndexingTaskManager = require('./sql/IndexingTaskManager').IndexingTaskManager;
const IndexingManager = require('./sql/IndexingManager').IndexingManager;
const PersonManager = require('./sql/PersonManager').PersonManager;
ObjectManagerRepository.getInstance().GalleryManager = new GalleryManager();
ObjectManagerRepository.getInstance().UserManager = new UserManager();
ObjectManagerRepository.getInstance().SearchManager = new SearchManager();
ObjectManagerRepository.getInstance().SharingManager = new SharingManager();
ObjectManagerRepository.getInstance().IndexingTaskManager = new IndexingTaskManager();
ObjectManagerRepository.getInstance().IndexingManager = new IndexingManager();
ObjectManagerRepository.getInstance().PersonManager = new PersonManager();
const VersionManager = require('./sql/VersionManager').VersionManager;
ObjectManagers.getInstance().GalleryManager = new GalleryManager();
ObjectManagers.getInstance().UserManager = new UserManager();
ObjectManagers.getInstance().SearchManager = new SearchManager();
ObjectManagers.getInstance().SharingManager = new SharingManager();
ObjectManagers.getInstance().IndexingTaskManager = new IndexingTaskManager();
ObjectManagers.getInstance().IndexingManager = new IndexingManager();
ObjectManagers.getInstance().PersonManager = new PersonManager();
ObjectManagers.getInstance().VersionManager = new VersionManager();
Logger.debug('SQL DB inited');
}

View File

@ -0,0 +1,5 @@
export interface IVersionManager {
getDataVersion(): Promise<string>;
updateDataVersion(): Promise<void>;
}

View File

@ -0,0 +1,12 @@
import {IVersionManager} from '../interfaces/IVersionManager';
import {DataStructureVersion} from '../../../common/DataStructureVersion';
export class VersionManager implements IVersionManager {
async getDataVersion(): Promise<string> {
return DataStructureVersion.toString();
}
async updateDataVersion(): Promise<void> {
return;
}
}

View File

@ -17,7 +17,7 @@ import {VideoEntity} from './enitites/VideoEntity';
import {DiskMangerWorker} from '../threading/DiskMangerWorker';
import {Logger} from '../../Logger';
import {FaceRegionEntry} from './enitites/FaceRegionEntry';
import {ObjectManagerRepository} from '../ObjectManagerRepository';
import {ObjectManagers} from '../ObjectManagers';
import {DuplicatesDTO} from '../../../common/entities/DuplicatesDTO';
const LOG_TAG = '[GalleryManager]';
@ -56,7 +56,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
if (dir.lastModified !== lastModified) {
Logger.silly(LOG_TAG, 'Reindexing reason: lastModified mismatch: known: '
+ dir.lastModified + ', current:' + lastModified);
return ObjectManagerRepository.getInstance().IndexingManager.indexDirectory(relativeDirectoryName);
return ObjectManagers.getInstance().IndexingManager.indexDirectory(relativeDirectoryName);
}
@ -68,7 +68,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
Logger.silly(LOG_TAG, 'lazy reindexing reason: cache timeout: lastScanned: '
+ (Date.now() - dir.lastScanned) + ' ms ago, cachedFolderTimeout:' + Config.Server.indexing.cachedFolderTimeout);
ObjectManagerRepository.getInstance().IndexingManager.indexDirectory(relativeDirectoryName).catch((err) => {
ObjectManagers.getInstance().IndexingManager.indexDirectory(relativeDirectoryName).catch((err) => {
console.error(err);
});
}
@ -78,7 +78,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager {
// never scanned (deep indexed), do it and return with it
Logger.silly(LOG_TAG, 'Reindexing reason: never scanned');
return ObjectManagerRepository.getInstance().IndexingManager.indexDirectory(relativeDirectoryName);
return ObjectManagers.getInstance().IndexingManager.indexDirectory(relativeDirectoryName);
}

View File

@ -13,7 +13,7 @@ import {FileEntity} from './enitites/FileEntity';
import {FileDTO} from '../../../common/entities/FileDTO';
import {NotificationManager} from '../NotifocationManager';
import {FaceRegionEntry} from './enitites/FaceRegionEntry';
import {ObjectManagerRepository} from '../ObjectManagerRepository';
import {ObjectManagers} from '../ObjectManagers';
import {IIndexingManager} from '../interfaces/IIndexingManager';
const LOG_TAG = '[IndexingManager]';
@ -242,7 +242,7 @@ export class IndexingManager implements IIndexingManager {
persons.push(scannedFaces[i].name);
}
}
await ObjectManagerRepository.getInstance().PersonManager.saveAll(persons);
await ObjectManagers.getInstance().PersonManager.saveAll(persons);
const indexedFaces = await faceRepository.createQueryBuilder('face')
@ -270,7 +270,7 @@ export class IndexingManager implements IIndexingManager {
}
if (face == null) {
(<FaceRegionEntry>scannedFaces[i]).person = await ObjectManagerRepository.getInstance().PersonManager.get(scannedFaces[i].name);
(<FaceRegionEntry>scannedFaces[i]).person = await ObjectManagers.getInstance().PersonManager.get(scannedFaces[i].name);
faceToInsert.push(scannedFaces[i]);
}
}
@ -289,7 +289,8 @@ export class IndexingManager implements IIndexingManager {
await this.saveChildDirs(connection, currentDirId, scannedDirectory);
await this.saveMedia(connection, currentDirId, scannedDirectory.media);
await this.saveMetaFiles(connection, currentDirId, scannedDirectory);
await ObjectManagerRepository.getInstance().PersonManager.updateCounts();
await ObjectManagers.getInstance().PersonManager.updateCounts();
await ObjectManagers.getInstance().VersionManager.updateDataVersion();
} catch (e) {
throw e;
} finally {

View File

@ -1,6 +1,6 @@
import {IIndexingTaskManager} from '../interfaces/IIndexingTaskManager';
import {IndexingProgressDTO} from '../../../common/entities/settings/IndexingProgressDTO';
import {ObjectManagerRepository} from '../ObjectManagerRepository';
import {ObjectManagers} from '../ObjectManagers';
import * as path from 'path';
import * as fs from 'fs';
import {SQLConnection} from './SQLConnection';
@ -29,7 +29,7 @@ export class IndexingTaskManager implements IIndexingTaskManager {
const directory = this.directoriesToIndex.shift();
this.indexingProgress.current = directory;
this.indexingProgress.left = this.directoriesToIndex.length;
const scanned = await ObjectManagerRepository.getInstance().IndexingManager.indexDirectory(directory);
const scanned = await ObjectManagers.getInstance().IndexingManager.indexDirectory(directory);
if (this.enabled === false) {
return;
}

View File

@ -0,0 +1,56 @@
import * as crypto from 'crypto';
import {IVersionManager} from '../interfaces/IVersionManager';
import {DataStructureVersion} from '../../../common/DataStructureVersion';
import {SQLConnection} from './SQLConnection';
import {DirectoryEntity} from './enitites/DirectoryEntity';
import {MediaEntity} from './enitites/MediaEntity';
const LOG_TAG = '[VersionManager]';
export class VersionManager implements IVersionManager {
private allMediaCount = 0;
private latestDirectoryStatus: {
name: string,
lastModified: number,
mediaCount: number
} = null;
async getDataVersion(): Promise<string> {
if (this.latestDirectoryStatus === null) {
await this.updateDataVersion();
}
if (!this.latestDirectoryStatus) {
return DataStructureVersion.toString();
}
const versionString = DataStructureVersion + '_' +
this.latestDirectoryStatus.name + '_' +
this.latestDirectoryStatus.lastModified + '_' +
this.latestDirectoryStatus.mediaCount + '_' +
this.allMediaCount;
return crypto.createHash('md5').update(versionString).digest('hex');
}
async updateDataVersion() {
const connection = await SQLConnection.getConnection();
const dir = await connection.getRepository(DirectoryEntity)
.createQueryBuilder('directory')
.limit(1)
.orderBy('directory.lastModified').getOne();
this.allMediaCount = await connection.getRepository(MediaEntity)
.createQueryBuilder('media').getCount();
if (!dir) {
return;
}
this.latestDirectoryStatus = {
mediaCount: dir.mediaCount,
lastModified: dir.lastModified,
name: dir.name
};
}
}

View File

@ -5,6 +5,7 @@ import {RenderingMWs} from '../middlewares/RenderingMWs';
import {ThumbnailGeneratorMWs} from '../middlewares/thumbnail/ThumbnailGeneratorMWs';
import {UserRoles} from '../../common/entities/UserDTO';
import {ThumbnailSourceType} from '../model/threading/ThumbnailWorker';
import {VersionMWs} from '../middlewares/VersionMWs';
export class GalleryRouter {
public static route(app: Express) {
@ -28,6 +29,7 @@ export class GalleryRouter {
app.get(['/api/gallery/content/:directory(*)', '/api/gallery/', '/api/gallery//'],
AuthenticationMWs.authenticate,
AuthenticationMWs.authoriseDirectory,
VersionMWs.injectGalleryVersion,
GalleryMWs.listDirectory,
ThumbnailGeneratorMWs.addThumbnailInformation,
GalleryMWs.cleanUpGalleryResults,
@ -66,6 +68,7 @@ export class GalleryRouter {
private static addRandom(app: Express) {
app.get(['/api/gallery/random'],
AuthenticationMWs.authenticate,
VersionMWs.injectGalleryVersion,
// TODO: authorize path
GalleryMWs.getRandomImage,
GalleryMWs.loadFile,
@ -118,6 +121,7 @@ export class GalleryRouter {
app.get('/api/search/:text',
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.Guest),
VersionMWs.injectGalleryVersion,
GalleryMWs.search,
ThumbnailGeneratorMWs.addThumbnailInformation,
GalleryMWs.cleanUpGalleryResults,
@ -129,6 +133,7 @@ export class GalleryRouter {
app.get('/api/instant-search/:text',
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.Guest),
VersionMWs.injectGalleryVersion,
GalleryMWs.instantSearch,
ThumbnailGeneratorMWs.addThumbnailInformation,
GalleryMWs.cleanUpGalleryResults,
@ -140,6 +145,7 @@ export class GalleryRouter {
app.get('/api/autocomplete/:text',
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.Guest),
VersionMWs.injectGalleryVersion,
GalleryMWs.autocomplete,
RenderingMWs.renderResult
);

View File

@ -3,6 +3,7 @@ import {AuthenticationMWs} from '../middlewares/user/AuthenticationMWs';
import {RenderingMWs} from '../middlewares/RenderingMWs';
import {NotificationMWs} from '../middlewares/NotificationMWs';
import {Express} from 'express';
import {VersionMWs} from '../middlewares/VersionMWs';
export class NotificationRouter {
public static route(app: Express) {
@ -14,6 +15,7 @@ export class NotificationRouter {
app.get('/api/notifications',
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.Guest),
VersionMWs.injectGalleryVersion,
NotificationMWs.list,
RenderingMWs.renderResult
);

View File

@ -4,6 +4,7 @@ import {RenderingMWs} from '../middlewares/RenderingMWs';
import {UserRoles} from '../../common/entities/UserDTO';
import {PersonMWs} from '../middlewares/PersonMWs';
import {ThumbnailGeneratorMWs} from '../middlewares/thumbnail/ThumbnailGeneratorMWs';
import {VersionMWs} from '../middlewares/VersionMWs';
export class PersonRouter {
public static route(app: Express) {
@ -16,6 +17,7 @@ export class PersonRouter {
app.get(['/api/person'],
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.User),
VersionMWs.injectGalleryVersion,
PersonMWs.listPersons,
RenderingMWs.renderResult
);
@ -25,6 +27,7 @@ export class PersonRouter {
app.get(['/api/person/:name/thumbnail'],
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.User),
VersionMWs.injectGalleryVersion,
PersonMWs.getSamplePhoto,
ThumbnailGeneratorMWs.generatePersonThumbnail,
RenderingMWs.renderFile

View File

@ -11,7 +11,7 @@ import {GalleryRouter} from './routes/GalleryRouter';
import {AdminRouter} from './routes/AdminRouter';
import {ErrorRouter} from './routes/ErrorRouter';
import {SharingRouter} from './routes/SharingRouter';
import {ObjectManagerRepository} from './model/ObjectManagerRepository';
import {ObjectManagers} from './model/ObjectManagers';
import {Logger} from './Logger';
import {Config} from '../common/config/private/Config';
import {DatabaseType} from '../common/config/private/IPrivateConfig';
@ -81,9 +81,9 @@ export class Server {
this.app.use(locale(Config.Client.languages, 'en'));
if (Config.Server.database.type !== DatabaseType.memory) {
await ObjectManagerRepository.InitSQLManagers();
await ObjectManagers.InitSQLManagers();
} else {
await ObjectManagerRepository.InitMemoryManagers();
await ObjectManagers.InitMemoryManagers();
}
PublicRouter.route(this.app);

View File

@ -1,7 +1,7 @@
import {SQLConnection} from '../backend/model/sql/SQLConnection';
import {Config} from '../common/config/private/Config';
import {DatabaseType, ReIndexingSensitivity} from '../common/config/private/IPrivateConfig';
import {ObjectManagerRepository} from '../backend/model/ObjectManagerRepository';
import {ObjectManagers} from '../backend/model/ObjectManagers';
import {DiskMangerWorker} from '../backend/model/threading/DiskMangerWorker';
import {IndexingManager} from '../backend/model/sql/IndexingManager';
import {SearchManager} from '../backend/model/sql/SearchManager';
@ -124,7 +124,7 @@ export class Benchmarks {
}
Config.Server.database.type = DatabaseType.sqlite;
Config.Server.database.sqlite.storage = this.dbPath;
await ObjectManagerRepository.InitSQLManagers();
await ObjectManagers.InitSQLManagers();
};
private async setupDB() {

3
common/CostumHeaders.ts Normal file
View File

@ -0,0 +1,3 @@
export class CostumHeaders {
public static dataVersion = 'PI-GALLERY2-DATA-VERSION';
}

View File

@ -9,6 +9,9 @@ export const QueryParams = {
minResolution: 'fromRes',
maxResolution: 'toRes'
},
search: {
type: 'type'
},
photo: 'p',
sharingKey_short: 'sk',
sharingKey_long: 'sharingKey',

View File

@ -77,6 +77,7 @@ import {SeededRandomService} from './model/seededRandom.service';
import {FacesComponent} from './faces/faces.component';
import {FacesService} from './faces/faces.service';
import {FaceComponent} from './faces/face/face.component';
import {VersionService} from './model/version.service';
@Injectable()
@ -201,6 +202,7 @@ export function translationsFactory(locale: string) {
QueryService,
DuplicateService,
FacesService,
VersionService,
{
provide: TRANSLATIONS,
useFactory: translationsFactory,

View File

@ -5,8 +5,8 @@ import {Config} from '../../../common/config/public/Config';
import {AutoCompleteItem, SearchTypes} from '../../../common/entities/AutoCompleteItem';
import {SearchResultDTO} from '../../../common/entities/SearchResultDTO';
import {MediaDTO} from '../../../common/entities/MediaDTO';
import {DataStructureVersion} from '../../../common/DataStructureVersion';
import {SortingMethods} from '../../../common/entities/SortingMethods';
import {VersionService} from '../model/version.service';
interface CacheItem<T> {
timestamp: number;
@ -24,24 +24,18 @@ export class GalleryCacheService {
private static readonly SEARCH_TYPE_PREFIX = ':type:';
private static readonly VERSION = 'version';
constructor() {
const version = parseInt(localStorage.getItem(GalleryCacheService.VERSION), 10) || 0;
if (version !== DataStructureVersion) {
localStorage.clear();
localStorage.setItem(GalleryCacheService.VERSION, DataStructureVersion.toString());
}
constructor(private versionService: VersionService) {
const onNewVersion = (ver: string) => {
if (ver !== null &&
localStorage.getItem(GalleryCacheService.VERSION) !== ver) {
this.deleteCache();
localStorage.setItem(GalleryCacheService.VERSION, ver);
}
};
this.versionService.version.subscribe(onNewVersion);
onNewVersion(this.versionService.version.value);
}
private reset() {
try {
localStorage.clear();
localStorage.setItem(GalleryCacheService.VERSION, DataStructureVersion.toString());
} catch (e) {
}
}
public getSorting(dir: DirectoryDTO): SortingMethods {
const key = GalleryCacheService.SORTING_PREFIX + dir.path + '/' + dir.name;
const tmp = localStorage.getItem(key);
@ -73,6 +67,9 @@ export class GalleryCacheService {
}
public getAutoComplete(text: string): AutoCompleteItem[] {
if (Config.Client.Other.enableCache === false) {
return null;
}
const key = GalleryCacheService.AUTO_COMPLETE_PREFIX + text;
const tmp = localStorage.getItem(key);
if (tmp != null) {
@ -87,6 +84,9 @@ export class GalleryCacheService {
}
public setAutoComplete(text: string, items: Array<AutoCompleteItem>): void {
if (Config.Client.Other.enableCache === false) {
return;
}
const tmp: CacheItem<Array<AutoCompleteItem>> = {
timestamp: Date.now(),
item: items
@ -100,6 +100,9 @@ export class GalleryCacheService {
}
public getInstantSearch(text: string): SearchResultDTO {
if (Config.Client.Other.enableCache === false) {
return null;
}
const key = GalleryCacheService.INSTANT_SEARCH_PREFIX + text;
const tmp = localStorage.getItem(key);
if (tmp != null) {
@ -114,6 +117,9 @@ export class GalleryCacheService {
}
public setInstantSearch(text: string, searchResult: SearchResultDTO): void {
if (Config.Client.Other.enableCache === false) {
return;
}
const tmp: CacheItem<SearchResultDTO> = {
timestamp: Date.now(),
item: searchResult
@ -126,8 +132,10 @@ export class GalleryCacheService {
}
}
public getSearch(text: string, type?: SearchTypes): SearchResultDTO {
if (Config.Client.Other.enableCache === false) {
return null;
}
let key = GalleryCacheService.SEARCH_PREFIX + text;
if (typeof type !== 'undefined' && type !== null) {
key += GalleryCacheService.SEARCH_TYPE_PREFIX + type;
@ -145,6 +153,9 @@ export class GalleryCacheService {
}
public setSearch(text: string, type: SearchTypes, searchResult: SearchResultDTO): void {
if (Config.Client.Other.enableCache === false) {
return;
}
const tmp: CacheItem<SearchResultDTO> = {
timestamp: Date.now(),
item: searchResult
@ -161,7 +172,6 @@ export class GalleryCacheService {
}
}
public getDirectory(directoryName: string): DirectoryDTO {
if (Config.Client.Other.enableCache === false) {
return null;
@ -233,4 +243,34 @@ export class GalleryCacheService {
}
private deleteCache() {
try {
const toRemove = [];
for (let i = 0; i < localStorage.length; i++) {
if (localStorage.key(i).startsWith(GalleryCacheService.CONTENT_PREFIX) ||
localStorage.key(i).startsWith(GalleryCacheService.SEARCH_PREFIX) ||
localStorage.key(i).startsWith(GalleryCacheService.INSTANT_SEARCH_PREFIX) ||
localStorage.key(i).startsWith(GalleryCacheService.AUTO_COMPLETE_PREFIX)
) {
toRemove.push(localStorage.key(i));
}
}
for (let i = 0; i < toRemove.length; i++) {
localStorage.removeItem(toRemove[i]);
}
} catch (e) {
}
}
private reset() {
try {
localStorage.clear();
localStorage.setItem(GalleryCacheService.VERSION, this.versionService.version.value);
} catch (e) {
}
}
}

View File

@ -115,7 +115,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
private onRoute = async (params: Params) => {
const searchText = params[QueryParams.gallery.searchText];
if (searchText && searchText !== '') {
const typeString: string = params['type'];
const typeString: string = params[QueryParams.gallery.search.type];
let type: SearchTypes = null;
if (typeString && typeString !== '') {
type = <any>SearchTypes[<any>typeString];

View File

@ -133,9 +133,9 @@ export class GalleryService {
await this.instantSearch(text, type);
return;
}
const params: { type?: SearchTypes } = {};
const params: { [key: string]: any } = {};
if (typeof type !== 'undefined' && type !== null) {
params['type'] = type;
params[QueryParams.gallery.search.type] = type;
}
cw.searchResult = (await this.networkService.getJson<ContentWrapper>('/search/' + text, params)).searchResult;
if (this.ongoingSearch &&

View File

@ -1,11 +1,13 @@
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {HttpClient, HttpResponse} from '@angular/common/http';
import {Message} from '../../../../common/entities/Message';
import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
import 'rxjs/Rx';
import {ErrorCodes, ErrorDTO} from '../../../../common/entities/Error';
import {Config} from '../../../../common/config/public/Config';
import {Utils} from '../../../../common/Utils';
import {CostumHeaders} from '../../../../common/CostumHeaders';
import {VersionService} from '../version.service';
@Injectable()
export class NetworkService {
@ -14,7 +16,8 @@ export class NetworkService {
private globalErrorHandlers: Array<(error: ErrorDTO) => boolean> = [];
constructor(private _http: HttpClient,
private slimLoadingBarService: SlimLoadingBarService) {
private slimLoadingBarService: SlimLoadingBarService,
private versionService: VersionService) {
}
public static buildUrl(url: string, data?: { [key: string]: any }) {
@ -73,6 +76,10 @@ export class NetworkService {
return this.callJson('delete', url);
}
addGlobalErrorHandler(fn: (error: ErrorDTO) => boolean) {
this.globalErrorHandlers.push(fn);
}
private callJson<T>(method: 'get' | 'post' | 'delete' | 'put', url: string, data: any = {}): Promise<T> {
const body = data;
@ -81,40 +88,44 @@ export class NetworkService {
this.slimLoadingBarService.visible = false;
});
const process = (res: Message<T>): T => {
const process = (res: HttpResponse<Message<T>>): T => {
this.slimLoadingBarService.complete();
if (!!res.error) {
if (res.error.code) {
(<any>res.error)['title'] = ErrorCodes[res.error.code];
}
throw res.error;
const msg = res.body;
if (res.headers.has(CostumHeaders.dataVersion)) {
this.versionService.onNewVersion(res.headers.get(CostumHeaders.dataVersion));
}
return res.result;
if (!!msg.error) {
if (msg.error.code) {
(<any>msg.error)['title'] = ErrorCodes[msg.error.code];
}
throw msg.error;
}
return msg.result;
};
const err = (error:any) => {
const err = (error: any) => {
this.slimLoadingBarService.complete();
return this.handleError(error);
};
switch (method) {
case 'get':
return this._http.get<Message<T>>(this._apiBaseUrl + url)
return this._http.get<Message<T>>(this._apiBaseUrl + url, {observe: 'response'})
.toPromise()
.then(process)
.catch(err);
case 'delete':
return this._http.delete<Message<T>>(this._apiBaseUrl + url)
return this._http.delete<Message<T>>(this._apiBaseUrl + url, {observe: 'response'})
.toPromise()
.then(process)
.catch(err);
case 'post':
return this._http.post<Message<T>>(this._apiBaseUrl + url, body)
return this._http.post<Message<T>>(this._apiBaseUrl + url, body, {observe: 'response'})
.toPromise()
.then(process)
.catch(err);
case 'put':
return this._http.put<Message<T>>(this._apiBaseUrl + url, body)
return this._http.put<Message<T>>(this._apiBaseUrl + url, body, {observe: 'response'})
.toPromise()
.then(process)
.catch(err);
@ -137,9 +148,4 @@ export class NetworkService {
console.error('error:', error);
return Promise.reject(error.message || error || 'Server error');
}
addGlobalErrorHandler(fn: (error: ErrorDTO) => boolean) {
this.globalErrorHandlers.push(fn);
}
}

View File

@ -0,0 +1,19 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
@Injectable()
export class VersionService {
public version: BehaviorSubject<string>;
constructor() {
this.version = new BehaviorSubject<string>(null);
}
public onNewVersion(version: string) {
if (this.version.value === version) {
return;
}
this.version.next(version);
}
}

View File

@ -2,7 +2,7 @@ import {expect} from 'chai';
import {AuthenticationMWs} from '../../../../../backend/middlewares/user/AuthenticationMWs';
import {ErrorCodes, ErrorDTO} from '../../../../../common/entities/Error';
import {UserDTO, UserRoles} from '../../../../../common/entities/UserDTO';
import {ObjectManagerRepository} from '../../../../../backend/model/ObjectManagerRepository';
import {ObjectManagers} from '../../../../../backend/model/ObjectManagers';
import {UserManager} from '../../../../../backend/model/memory/UserManager';
import {Config} from '../../../../../common/config/private/Config';
import {IUserManager} from '../../../../../backend/model/interfaces/IUserManager';
@ -11,7 +11,7 @@ import {IUserManager} from '../../../../../backend/model/interfaces/IUserManager
describe('Authentication middleware', () => {
beforeEach(() => {
ObjectManagerRepository.reset();
ObjectManagers.reset();
});
describe('authenticate', () => {
@ -125,7 +125,7 @@ describe('Authentication middleware', () => {
describe('login', () => {
beforeEach(() => {
ObjectManagerRepository.reset();
ObjectManagers.reset();
});
describe('should call input ErrorDTO next on missing...', () => {
@ -193,7 +193,7 @@ describe('Authentication middleware', () => {
expect(err.code).to.be.eql(ErrorCodes.CREDENTIAL_NOT_FOUND);
done();
};
ObjectManagerRepository.getInstance().UserManager = <UserManager>{
ObjectManagers.getInstance().UserManager = <UserManager>{
findOne: (filter): Promise<UserDTO> => {
return Promise.reject(null);
}
@ -220,7 +220,7 @@ describe('Authentication middleware', () => {
expect(req.session.user).to.be.eql('test user');
done();
};
ObjectManagerRepository.getInstance().UserManager = <IUserManager>{
ObjectManagers.getInstance().UserManager = <IUserManager>{
findOne: (filter) => {
return Promise.resolve(<any>'test user');
}

View File

@ -5,9 +5,10 @@ import {GalleryManager} from '../../../../../backend/model/sql/GalleryManager';
import {IndexingManager} from '../../../../../backend/model/sql/IndexingManager';
import {DirectoryDTO} from '../../../../../common/entities/DirectoryDTO';
import {Utils} from '../../../../../common/Utils';
import {ObjectManagerRepository} from '../../../../../backend/model/ObjectManagerRepository';
import {ObjectManagers} from '../../../../../backend/model/ObjectManagers';
import {PersonManager} from '../../../../../backend/model/sql/PersonManager';
import {MediaEntity} from '../../../../../backend/model/sql/enitites/MediaEntity';
import {VersionManager} from '../../../../../backend/model/sql/VersionManager';
class IndexingManagerTest extends IndexingManager {
@ -26,7 +27,8 @@ describe('GalleryManager', (sqlHelper: SQLTestHelper) => {
beforeEach(async () => {
await sqlHelper.initDB();
ObjectManagerRepository.getInstance().PersonManager = new PersonManager();
ObjectManagers.getInstance().PersonManager = new PersonManager();
ObjectManagers.getInstance().VersionManager = new VersionManager();
});

View File

@ -12,9 +12,10 @@ import {Utils} from '../../../../../common/Utils';
import {MediaDTO} from '../../../../../common/entities/MediaDTO';
import {FileDTO} from '../../../../../common/entities/FileDTO';
import {IndexingManager} from '../../../../../backend/model/sql/IndexingManager';
import {ObjectManagerRepository} from '../../../../../backend/model/ObjectManagerRepository';
import {ObjectManagers} from '../../../../../backend/model/ObjectManagers';
import {PersonManager} from '../../../../../backend/model/sql/PersonManager';
import {SQLTestHelper} from '../../../SQLTestHelper';
import {VersionManager} from '../../../../../backend/model/sql/VersionManager';
class GalleryManagerTest extends GalleryManager {
@ -52,7 +53,8 @@ describe('IndexingManager', (sqlHelper: SQLTestHelper) => {
beforeEach(async () => {
await sqlHelper.initDB();
ObjectManagerRepository.getInstance().PersonManager = new PersonManager();
ObjectManagers.getInstance().PersonManager = new PersonManager();
ObjectManagers.getInstance().VersionManager = new VersionManager();
});
@ -296,7 +298,7 @@ describe('IndexingManager', (sqlHelper: SQLTestHelper) => {
beforeEach(() => {
dirTime = 0;
ObjectManagerRepository.getInstance().IndexingManager = new IndexingManagerTest();
ObjectManagers.getInstance().IndexingManager = new IndexingManagerTest();
indexedTime.lastModified = 0;
indexedTime.lastScanned = 0;
});
@ -319,7 +321,7 @@ describe('IndexingManager', (sqlHelper: SQLTestHelper) => {
return Promise.resolve();
};
ObjectManagerRepository.getInstance().IndexingManager.indexDirectory = (...args) => {
ObjectManagers.getInstance().IndexingManager.indexDirectory = (...args) => {
return <any>Promise.resolve('indexing');
};