mirror of
https://github.com/immich-app/immich.git
synced 2025-01-17 01:06:46 +01:00
refactor(server): simplify config init process (#5702)
This commit is contained in:
parent
5f6d09d3da
commit
03eb5ffc5c
8 changed files with 35 additions and 35 deletions
|
@ -19,7 +19,7 @@ import { SharedLinkService } from './shared-link';
|
||||||
import { SmartInfoService } from './smart-info';
|
import { SmartInfoService } from './smart-info';
|
||||||
import { StorageService } from './storage';
|
import { StorageService } from './storage';
|
||||||
import { StorageTemplateService } from './storage-template';
|
import { StorageTemplateService } from './storage-template';
|
||||||
import { INITIAL_SYSTEM_CONFIG, SystemConfigService } from './system-config';
|
import { SystemConfigService } from './system-config';
|
||||||
import { TagService } from './tag';
|
import { TagService } from './tag';
|
||||||
import { UserService } from './user';
|
import { UserService } from './user';
|
||||||
|
|
||||||
|
@ -47,14 +47,6 @@ const providers: Provider[] = [
|
||||||
TagService,
|
TagService,
|
||||||
UserService,
|
UserService,
|
||||||
ImmichLogger,
|
ImmichLogger,
|
||||||
{
|
|
||||||
provide: INITIAL_SYSTEM_CONFIG,
|
|
||||||
inject: [SystemConfigService, DatabaseService],
|
|
||||||
useFactory: async (configService: SystemConfigService, databaseService: DatabaseService) => {
|
|
||||||
await databaseService.init();
|
|
||||||
return configService.getConfig();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
|
|
|
@ -207,15 +207,15 @@ describe(JobService.name, () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('registerHandlers', () => {
|
describe('init', () => {
|
||||||
it('should register a handler for each queue', async () => {
|
it('should register a handler for each queue', async () => {
|
||||||
await sut.registerHandlers(makeMockHandlers(true));
|
await sut.init(makeMockHandlers(true));
|
||||||
expect(configMock.load).toHaveBeenCalled();
|
expect(configMock.load).toHaveBeenCalled();
|
||||||
expect(jobMock.addHandler).toHaveBeenCalledTimes(Object.keys(QueueName).length);
|
expect(jobMock.addHandler).toHaveBeenCalledTimes(Object.keys(QueueName).length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should subscribe to config changes', async () => {
|
it('should subscribe to config changes', async () => {
|
||||||
await sut.registerHandlers(makeMockHandlers(false));
|
await sut.init(makeMockHandlers(false));
|
||||||
|
|
||||||
SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({
|
SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({
|
||||||
job: {
|
job: {
|
||||||
|
@ -323,7 +323,7 @@ describe(JobService.name, () => {
|
||||||
assetMock.getByIds.mockResolvedValue([]);
|
assetMock.getByIds.mockResolvedValue([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
await sut.registerHandlers(makeMockHandlers(true));
|
await sut.init(makeMockHandlers(true));
|
||||||
await jobMock.addHandler.mock.calls[0][2](item);
|
await jobMock.addHandler.mock.calls[0][2](item);
|
||||||
await asyncTick(3);
|
await asyncTick(3);
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ describe(JobService.name, () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should not queue any jobs when ${item.name} finishes with 'false'`, async () => {
|
it(`should not queue any jobs when ${item.name} finishes with 'false'`, async () => {
|
||||||
await sut.registerHandlers(makeMockHandlers(false));
|
await sut.init(makeMockHandlers(false));
|
||||||
await jobMock.addHandler.mock.calls[0][2](item);
|
await jobMock.addHandler.mock.calls[0][2](item);
|
||||||
await asyncTick(3);
|
await asyncTick(3);
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ export class JobService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerHandlers(jobHandlers: Record<JobName, JobHandler>) {
|
async init(jobHandlers: Record<JobName, JobHandler>) {
|
||||||
const config = await this.configCore.getConfig();
|
const config = await this.configCore.getConfig();
|
||||||
for (const queueName of Object.values(QueueName)) {
|
for (const queueName of Object.values(QueueName)) {
|
||||||
let concurrency = 1;
|
let concurrency = 1;
|
||||||
|
|
|
@ -27,6 +27,7 @@ import {
|
||||||
} from '@test';
|
} from '@test';
|
||||||
import { when } from 'jest-when';
|
import { when } from 'jest-when';
|
||||||
import { Stats } from 'node:fs';
|
import { Stats } from 'node:fs';
|
||||||
|
import { SystemConfigCore } from '../system-config';
|
||||||
|
|
||||||
describe(StorageTemplateService.name, () => {
|
describe(StorageTemplateService.name, () => {
|
||||||
let sut: StorageTemplateService;
|
let sut: StorageTemplateService;
|
||||||
|
@ -38,7 +39,7 @@ describe(StorageTemplateService.name, () => {
|
||||||
let storageMock: jest.Mocked<IStorageRepository>;
|
let storageMock: jest.Mocked<IStorageRepository>;
|
||||||
let userMock: jest.Mocked<IUserRepository>;
|
let userMock: jest.Mocked<IUserRepository>;
|
||||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||||
let databaseRepository: jest.Mocked<IDatabaseRepository>;
|
let databaseMock: jest.Mocked<IDatabaseRepository>;
|
||||||
|
|
||||||
it('should work', () => {
|
it('should work', () => {
|
||||||
expect(sut).toBeDefined();
|
expect(sut).toBeDefined();
|
||||||
|
@ -53,22 +54,23 @@ describe(StorageTemplateService.name, () => {
|
||||||
storageMock = newStorageRepositoryMock();
|
storageMock = newStorageRepositoryMock();
|
||||||
userMock = newUserRepositoryMock();
|
userMock = newUserRepositoryMock();
|
||||||
cryptoMock = newCryptoRepositoryMock();
|
cryptoMock = newCryptoRepositoryMock();
|
||||||
databaseRepository = newDatabaseRepositoryMock();
|
databaseMock = newDatabaseRepositoryMock();
|
||||||
|
|
||||||
|
configMock.load.mockResolvedValue([{ key: SystemConfigKey.STORAGE_TEMPLATE_ENABLED, value: true }]);
|
||||||
|
|
||||||
sut = new StorageTemplateService(
|
sut = new StorageTemplateService(
|
||||||
albumMock,
|
albumMock,
|
||||||
assetMock,
|
assetMock,
|
||||||
configMock,
|
configMock,
|
||||||
defaults,
|
|
||||||
moveMock,
|
moveMock,
|
||||||
personMock,
|
personMock,
|
||||||
storageMock,
|
storageMock,
|
||||||
userMock,
|
userMock,
|
||||||
cryptoMock,
|
cryptoMock,
|
||||||
databaseRepository,
|
databaseMock,
|
||||||
);
|
);
|
||||||
|
|
||||||
configMock.load.mockResolvedValue([{ key: SystemConfigKey.STORAGE_TEMPLATE_ENABLED, value: true }]);
|
SystemConfigCore.create(configMock).config$.next(defaults);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('handleMigrationSingle', () => {
|
describe('handleMigrationSingle', () => {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import {
|
||||||
} from '../repositories';
|
} from '../repositories';
|
||||||
import { StorageCore, StorageFolder } from '../storage';
|
import { StorageCore, StorageFolder } from '../storage';
|
||||||
import {
|
import {
|
||||||
INITIAL_SYSTEM_CONFIG,
|
|
||||||
supportedDayTokens,
|
supportedDayTokens,
|
||||||
supportedHourTokens,
|
supportedHourTokens,
|
||||||
supportedMinuteTokens,
|
supportedMinuteTokens,
|
||||||
|
@ -49,32 +48,33 @@ export class StorageTemplateService {
|
||||||
private logger = new ImmichLogger(StorageTemplateService.name);
|
private logger = new ImmichLogger(StorageTemplateService.name);
|
||||||
private configCore: SystemConfigCore;
|
private configCore: SystemConfigCore;
|
||||||
private storageCore: StorageCore;
|
private storageCore: StorageCore;
|
||||||
private template: {
|
private _template: {
|
||||||
compiled: HandlebarsTemplateDelegate<any>;
|
compiled: HandlebarsTemplateDelegate<any>;
|
||||||
raw: string;
|
raw: string;
|
||||||
needsAlbum: boolean;
|
needsAlbum: boolean;
|
||||||
};
|
} | null = null;
|
||||||
|
|
||||||
|
private get template() {
|
||||||
|
if (!this._template) {
|
||||||
|
throw new Error('Template not initialized');
|
||||||
|
}
|
||||||
|
return this._template;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
|
@Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
|
||||||
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
||||||
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
|
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
|
||||||
@Inject(INITIAL_SYSTEM_CONFIG) config: SystemConfig,
|
|
||||||
@Inject(IMoveRepository) moveRepository: IMoveRepository,
|
@Inject(IMoveRepository) moveRepository: IMoveRepository,
|
||||||
@Inject(IPersonRepository) personRepository: IPersonRepository,
|
@Inject(IPersonRepository) personRepository: IPersonRepository,
|
||||||
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
|
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
|
||||||
@Inject(IUserRepository) private userRepository: IUserRepository,
|
@Inject(IUserRepository) private userRepository: IUserRepository,
|
||||||
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository,
|
@Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
|
||||||
@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository,
|
@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository,
|
||||||
) {
|
) {
|
||||||
this.template = this.compile(config.storageTemplate.template);
|
|
||||||
this.configCore = SystemConfigCore.create(configRepository);
|
this.configCore = SystemConfigCore.create(configRepository);
|
||||||
this.configCore.addValidator((config) => this.validate(config));
|
this.configCore.addValidator((config) => this.validate(config));
|
||||||
this.configCore.config$.subscribe((config) => {
|
this.configCore.config$.subscribe((config) => this.onConfig(config));
|
||||||
const template = config.storageTemplate.template;
|
|
||||||
this.logger.debug(`Received config, compiling storage template: ${template}`);
|
|
||||||
this.template = this.compile(template);
|
|
||||||
});
|
|
||||||
this.storageCore = StorageCore.create(
|
this.storageCore = StorageCore.create(
|
||||||
assetRepository,
|
assetRepository,
|
||||||
moveRepository,
|
moveRepository,
|
||||||
|
@ -270,6 +270,14 @@ export class StorageTemplateService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onConfig(config: SystemConfig) {
|
||||||
|
const template = config.storageTemplate.template;
|
||||||
|
if (!this._template || template !== this.template.raw) {
|
||||||
|
this.logger.debug(`Compiling new storage template: ${template}`);
|
||||||
|
this._template = this.compile(template);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private compile(template: string) {
|
private compile(template: string) {
|
||||||
return {
|
return {
|
||||||
raw: template,
|
raw: template,
|
||||||
|
|
|
@ -25,5 +25,3 @@ export const supportedPresetTokens = [
|
||||||
'{{y}}/{{y}}-{{WW}}/{{assetId}}',
|
'{{y}}/{{y}}-{{WW}}/{{assetId}}',
|
||||||
'{{album}}/{{filename}}',
|
'{{album}}/{{filename}}',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const INITIAL_SYSTEM_CONFIG = 'INITIAL_SYSTEM_CONFIG';
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ export class SystemConfigService {
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
const config = await this.core.getConfig();
|
const config = await this.core.getConfig();
|
||||||
await this.setLogLevel(config);
|
this.config$.next(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
get config$() {
|
get config$() {
|
||||||
|
|
|
@ -38,7 +38,7 @@ export class AppService {
|
||||||
async init() {
|
async init() {
|
||||||
await this.databaseService.init();
|
await this.databaseService.init();
|
||||||
await this.configService.init();
|
await this.configService.init();
|
||||||
await this.jobService.registerHandlers({
|
await this.jobService.init({
|
||||||
[JobName.ASSET_DELETION]: (data) => this.assetService.handleAssetDeletion(data),
|
[JobName.ASSET_DELETION]: (data) => this.assetService.handleAssetDeletion(data),
|
||||||
[JobName.ASSET_DELETION_CHECK]: () => this.assetService.handleAssetDeletionCheck(),
|
[JobName.ASSET_DELETION_CHECK]: () => this.assetService.handleAssetDeletionCheck(),
|
||||||
[JobName.DELETE_FILES]: (data: IDeleteFilesJob) => this.storageService.handleDeleteFiles(data),
|
[JobName.DELETE_FILES]: (data: IDeleteFilesJob) => this.storageService.handleDeleteFiles(data),
|
||||||
|
|
Loading…
Reference in a new issue