2024-03-17 20:16:02 +01:00
|
|
|
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
|
2023-12-14 17:55:40 +01:00
|
|
|
import { instanceToPlain } from 'class-transformer';
|
|
|
|
import _ from 'lodash';
|
2024-05-14 20:43:49 +02:00
|
|
|
import { LogLevel, SystemConfig, defaults } from 'src/config';
|
2023-01-21 17:11:55 +01:00
|
|
|
import {
|
|
|
|
supportedDayTokens,
|
|
|
|
supportedHourTokens,
|
|
|
|
supportedMinuteTokens,
|
|
|
|
supportedMonthTokens,
|
|
|
|
supportedPresetTokens,
|
|
|
|
supportedSecondTokens,
|
2023-09-28 19:47:31 +02:00
|
|
|
supportedWeekTokens,
|
2023-01-21 17:11:55 +01:00
|
|
|
supportedYearTokens,
|
2024-03-21 04:15:09 +01:00
|
|
|
} from 'src/constants';
|
|
|
|
import { SystemConfigCore } from 'src/cores/system-config.core';
|
2024-06-27 21:54:20 +02:00
|
|
|
import { EventHandlerOptions, OnServerEvent } from 'src/decorators';
|
2024-03-22 21:36:20 +01:00
|
|
|
import { SystemConfigDto, SystemConfigTemplateStorageOptionDto, mapConfig } from 'src/dtos/system-config.dto';
|
2024-03-20 21:42:58 +01:00
|
|
|
import {
|
|
|
|
ClientEvent,
|
2024-03-22 23:24:02 +01:00
|
|
|
IEventRepository,
|
2024-06-27 21:54:20 +02:00
|
|
|
OnEvents,
|
2024-03-20 21:42:58 +01:00
|
|
|
ServerEvent,
|
2024-06-27 21:54:20 +02:00
|
|
|
SystemConfigUpdate,
|
2024-03-22 23:24:02 +01:00
|
|
|
} from 'src/interfaces/event.interface';
|
2024-04-16 01:39:06 +02:00
|
|
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
2024-05-16 00:58:23 +02:00
|
|
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
2023-01-21 17:11:55 +01:00
|
|
|
|
|
|
|
@Injectable()
|
2024-06-27 21:54:20 +02:00
|
|
|
export class SystemConfigService implements OnEvents {
|
2023-01-21 17:11:55 +01:00
|
|
|
private core: SystemConfigCore;
|
2023-12-13 18:23:51 +01:00
|
|
|
|
2023-01-21 17:11:55 +01:00
|
|
|
constructor(
|
2024-05-29 17:51:01 +02:00
|
|
|
@Inject(ISystemMetadataRepository) repository: ISystemMetadataRepository,
|
2024-03-22 23:24:02 +01:00
|
|
|
@Inject(IEventRepository) private eventRepository: IEventRepository,
|
2024-04-16 01:39:06 +02:00
|
|
|
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
2023-01-21 17:11:55 +01:00
|
|
|
) {
|
2024-04-16 01:39:06 +02:00
|
|
|
this.logger.setContext(SystemConfigService.name);
|
2024-04-16 23:30:31 +02:00
|
|
|
this.core = SystemConfigCore.create(repository, this.logger);
|
|
|
|
this.core.config$.subscribe((config) => this.setLogLevel(config));
|
2023-12-14 17:55:40 +01:00
|
|
|
}
|
|
|
|
|
2024-06-27 21:54:20 +02:00
|
|
|
@EventHandlerOptions({ priority: -100 })
|
|
|
|
async onBootstrapEvent() {
|
2024-06-12 13:07:35 +02:00
|
|
|
const config = await this.core.getConfig({ withCache: false });
|
2024-01-01 19:16:44 +01:00
|
|
|
this.config$.next(config);
|
2023-01-21 17:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
get config$() {
|
|
|
|
return this.core.config$;
|
|
|
|
}
|
|
|
|
|
|
|
|
async getConfig(): Promise<SystemConfigDto> {
|
2024-06-12 13:07:35 +02:00
|
|
|
const config = await this.core.getConfig({ withCache: false });
|
2023-01-21 17:11:55 +01:00
|
|
|
return mapConfig(config);
|
|
|
|
}
|
|
|
|
|
|
|
|
getDefaults(): SystemConfigDto {
|
2024-05-14 20:43:49 +02:00
|
|
|
return mapConfig(defaults);
|
2023-01-21 17:11:55 +01:00
|
|
|
}
|
|
|
|
|
2024-06-27 21:54:20 +02:00
|
|
|
onConfigValidateEvent({ newConfig, oldConfig }: SystemConfigUpdate) {
|
2024-03-17 20:16:02 +01:00
|
|
|
if (!_.isEqual(instanceToPlain(newConfig.logging), oldConfig.logging) && this.getEnvLogLevel()) {
|
2024-05-17 17:44:22 +02:00
|
|
|
throw new Error('Logging cannot be changed while the environment variable IMMICH_LOG_LEVEL is set.');
|
2024-03-17 20:16:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-21 17:11:55 +01:00
|
|
|
async updateConfig(dto: SystemConfigDto): Promise<SystemConfigDto> {
|
2024-05-14 21:31:36 +02:00
|
|
|
if (this.core.isUsingConfigFile()) {
|
|
|
|
throw new BadRequestException('Cannot update configuration while IMMICH_CONFIG_FILE is in use');
|
|
|
|
}
|
|
|
|
|
2024-06-12 13:07:35 +02:00
|
|
|
const oldConfig = await this.core.getConfig({ withCache: false });
|
2024-03-17 20:16:02 +01:00
|
|
|
|
|
|
|
try {
|
2024-06-27 21:54:20 +02:00
|
|
|
await this.eventRepository.emit('onConfigValidateEvent', { newConfig: dto, oldConfig });
|
2024-03-17 20:16:02 +01:00
|
|
|
} catch (error) {
|
|
|
|
this.logger.warn(`Unable to save system config due to a validation error: ${error}`);
|
|
|
|
throw new BadRequestException(error instanceof Error ? error.message : error);
|
|
|
|
}
|
|
|
|
|
2023-12-08 17:15:46 +01:00
|
|
|
const newConfig = await this.core.updateConfig(dto);
|
2023-12-13 18:23:51 +01:00
|
|
|
|
2024-06-27 21:54:20 +02:00
|
|
|
// TODO probably move web socket emits to a separate service
|
2024-03-22 23:24:02 +01:00
|
|
|
this.eventRepository.clientBroadcast(ClientEvent.CONFIG_UPDATE, {});
|
|
|
|
this.eventRepository.serverSend(ServerEvent.CONFIG_UPDATE, null);
|
2024-06-27 21:54:20 +02:00
|
|
|
await this.eventRepository.emit('onConfigUpdateEvent', { newConfig, oldConfig });
|
2023-12-13 18:23:51 +01:00
|
|
|
|
2023-12-08 17:15:46 +01:00
|
|
|
return mapConfig(newConfig);
|
2023-01-21 17:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
getStorageTemplateOptions(): SystemConfigTemplateStorageOptionDto {
|
|
|
|
const options = new SystemConfigTemplateStorageOptionDto();
|
|
|
|
|
|
|
|
options.dayOptions = supportedDayTokens;
|
2023-09-28 19:47:31 +02:00
|
|
|
options.weekOptions = supportedWeekTokens;
|
2023-01-21 17:11:55 +01:00
|
|
|
options.monthOptions = supportedMonthTokens;
|
|
|
|
options.yearOptions = supportedYearTokens;
|
|
|
|
options.hourOptions = supportedHourTokens;
|
|
|
|
options.secondOptions = supportedSecondTokens;
|
|
|
|
options.minuteOptions = supportedMinuteTokens;
|
|
|
|
options.presetOptions = supportedPresetTokens;
|
|
|
|
|
|
|
|
return options;
|
|
|
|
}
|
2023-11-09 17:10:56 +01:00
|
|
|
|
2023-11-18 05:13:36 +01:00
|
|
|
async getCustomCss(): Promise<string> {
|
2024-06-12 13:07:35 +02:00
|
|
|
const { theme } = await this.core.getConfig({ withCache: false });
|
2023-11-18 05:13:36 +01:00
|
|
|
return theme.customCss;
|
|
|
|
}
|
2023-12-13 18:23:51 +01:00
|
|
|
|
2024-03-22 23:24:02 +01:00
|
|
|
@OnServerEvent(ServerEvent.CONFIG_UPDATE)
|
2024-06-27 21:54:20 +02:00
|
|
|
async onConfigUpdateEvent() {
|
2023-12-13 18:23:51 +01:00
|
|
|
await this.core.refreshConfig();
|
|
|
|
}
|
2023-12-14 17:55:40 +01:00
|
|
|
|
2024-03-05 23:23:06 +01:00
|
|
|
private setLogLevel({ logging }: SystemConfig) {
|
2023-12-14 17:55:40 +01:00
|
|
|
const envLevel = this.getEnvLogLevel();
|
|
|
|
const configLevel = logging.enabled ? logging.level : false;
|
2024-02-02 04:18:00 +01:00
|
|
|
const level = envLevel ?? configLevel;
|
2024-04-16 01:39:06 +02:00
|
|
|
this.logger.setLogLevel(level);
|
2024-05-17 17:44:22 +02:00
|
|
|
this.logger.log(`LogLevel=${level} ${envLevel ? '(set via IMMICH_LOG_LEVEL)' : '(set via system config)'}`);
|
2023-12-14 17:55:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private getEnvLogLevel() {
|
2024-05-17 17:44:22 +02:00
|
|
|
return process.env.IMMICH_LOG_LEVEL as LogLevel;
|
2023-12-14 17:55:40 +01:00
|
|
|
}
|
2023-01-21 17:11:55 +01:00
|
|
|
}
|