feat(server): server-side events (#5669)
This commit is contained in:
@@ -11,14 +11,9 @@ import {
|
||||
VideoCodec,
|
||||
} from '@app/infra/entities';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { newCommunicationRepositoryMock, newJobRepositoryMock, newSystemConfigRepositoryMock } from '@test';
|
||||
import { JobName, QueueName } from '../job';
|
||||
import {
|
||||
ICommunicationRepository,
|
||||
IJobRepository,
|
||||
ISmartInfoRepository,
|
||||
ISystemConfigRepository,
|
||||
} from '../repositories';
|
||||
import { newCommunicationRepositoryMock, newSystemConfigRepositoryMock } from '@test';
|
||||
import { QueueName } from '../job';
|
||||
import { ICommunicationRepository, ISmartInfoRepository, ISystemConfigRepository, ServerEvent } from '../repositories';
|
||||
import { defaults, SystemConfigValidator } from './system-config.core';
|
||||
import { SystemConfigService } from './system-config.service';
|
||||
|
||||
@@ -137,15 +132,13 @@ describe(SystemConfigService.name, () => {
|
||||
let sut: SystemConfigService;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let communicationMock: jest.Mocked<ICommunicationRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let smartInfoMock: jest.Mocked<ISmartInfoRepository>;
|
||||
|
||||
beforeEach(async () => {
|
||||
delete process.env.IMMICH_CONFIG_FILE;
|
||||
configMock = newSystemConfigRepositoryMock();
|
||||
communicationMock = newCommunicationRepositoryMock();
|
||||
jobMock = newJobRepositoryMock();
|
||||
sut = new SystemConfigService(configMock, communicationMock, jobMock, smartInfoMock);
|
||||
sut = new SystemConfigService(configMock, communicationMock, smartInfoMock);
|
||||
});
|
||||
|
||||
it('should work', () => {
|
||||
@@ -269,13 +262,14 @@ describe(SystemConfigService.name, () => {
|
||||
});
|
||||
|
||||
describe('updateConfig', () => {
|
||||
it('should notify the microservices process', async () => {
|
||||
it('should update the config and emit client and server events', async () => {
|
||||
configMock.load.mockResolvedValue(updates);
|
||||
|
||||
await expect(sut.updateConfig(updatedConfig)).resolves.toEqual(updatedConfig);
|
||||
|
||||
expect(communicationMock.broadcast).toHaveBeenCalled();
|
||||
expect(communicationMock.sendServerEvent).toHaveBeenCalledWith(ServerEvent.CONFIG_UPDATE);
|
||||
expect(configMock.saveAll).toHaveBeenCalledWith(updates);
|
||||
expect(jobMock.queue).toHaveBeenCalledWith({ name: JobName.SYSTEM_CONFIG_CHANGE });
|
||||
});
|
||||
|
||||
it('should throw an error if the config is not valid', async () => {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { JobName } from '../job';
|
||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import {
|
||||
CommunicationEvent,
|
||||
ClientEvent,
|
||||
ICommunicationRepository,
|
||||
IJobRepository,
|
||||
ISmartInfoRepository,
|
||||
ISystemConfigRepository,
|
||||
ServerEvent,
|
||||
} from '../repositories';
|
||||
import { SystemConfigDto, mapConfig } from './dto/system-config.dto';
|
||||
import { SystemConfigTemplateStorageOptionDto } from './response-dto/system-config-template-storage-option.dto';
|
||||
@@ -23,14 +22,16 @@ import { SystemConfigCore, SystemConfigValidator } from './system-config.core';
|
||||
|
||||
@Injectable()
|
||||
export class SystemConfigService {
|
||||
private logger = new Logger(SystemConfigService.name);
|
||||
private core: SystemConfigCore;
|
||||
|
||||
constructor(
|
||||
@Inject(ISystemConfigRepository) private repository: ISystemConfigRepository,
|
||||
@Inject(ICommunicationRepository) private communicationRepository: ICommunicationRepository,
|
||||
@Inject(IJobRepository) private jobRepository: IJobRepository,
|
||||
@Inject(ISmartInfoRepository) private smartInfoRepository: ISmartInfoRepository,
|
||||
) {
|
||||
this.core = SystemConfigCore.create(repository);
|
||||
this.communicationRepository.on(ServerEvent.CONFIG_UPDATE, () => this.handleConfigUpdate());
|
||||
}
|
||||
|
||||
get config$() {
|
||||
@@ -50,15 +51,19 @@ export class SystemConfigService {
|
||||
async updateConfig(dto: SystemConfigDto): Promise<SystemConfigDto> {
|
||||
const oldConfig = await this.core.getConfig();
|
||||
const newConfig = await this.core.updateConfig(dto);
|
||||
await this.jobRepository.queue({ name: JobName.SYSTEM_CONFIG_CHANGE });
|
||||
this.communicationRepository.broadcast(CommunicationEvent.CONFIG_UPDATE, {});
|
||||
|
||||
this.communicationRepository.broadcast(ClientEvent.CONFIG_UPDATE, {});
|
||||
this.communicationRepository.sendServerEvent(ServerEvent.CONFIG_UPDATE);
|
||||
|
||||
if (oldConfig.machineLearning.clip.modelName !== newConfig.machineLearning.clip.modelName) {
|
||||
await this.smartInfoRepository.init(newConfig.machineLearning.clip.modelName);
|
||||
}
|
||||
return mapConfig(newConfig);
|
||||
}
|
||||
|
||||
// this is only used by the cli on config change, and it's not actually needed anymore
|
||||
async refreshConfig() {
|
||||
this.communicationRepository.sendServerEvent(ServerEvent.CONFIG_UPDATE);
|
||||
await this.core.refreshConfig();
|
||||
return true;
|
||||
}
|
||||
@@ -97,4 +102,8 @@ export class SystemConfigService {
|
||||
const { theme } = await this.core.getConfig();
|
||||
return theme.customCss;
|
||||
}
|
||||
|
||||
private async handleConfigUpdate() {
|
||||
await this.core.refreshConfig();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user