mirror of
https://github.com/immich-app/immich.git
synced 2026-06-05 13:45:20 -04:00
feat: yucca integration
This commit is contained in:
@@ -46,6 +46,7 @@ import { UserService } from 'src/services/user.service';
|
||||
import { VersionService } from 'src/services/version.service';
|
||||
import { ViewService } from 'src/services/view.service';
|
||||
import { WorkflowService } from 'src/services/workflow.service';
|
||||
import { YuccaService } from 'src/services/yucca.service';
|
||||
|
||||
export const services = [
|
||||
ApiKeyService,
|
||||
@@ -96,4 +97,5 @@ export const services = [
|
||||
VersionService,
|
||||
ViewService,
|
||||
WorkflowService,
|
||||
YuccaService,
|
||||
];
|
||||
|
||||
@@ -242,6 +242,8 @@ export class LibraryService extends BaseService {
|
||||
'**/.stfolder/**',
|
||||
],
|
||||
});
|
||||
|
||||
await this.eventRepository.emit('LibraryCreate');
|
||||
return mapLibrary(library);
|
||||
}
|
||||
|
||||
@@ -343,6 +345,7 @@ export class LibraryService extends BaseService {
|
||||
}
|
||||
|
||||
const library = await this.libraryRepository.update(id, dto);
|
||||
await this.eventRepository.emit('LibraryUpdate');
|
||||
return mapLibrary(library);
|
||||
}
|
||||
|
||||
@@ -355,6 +358,8 @@ export class LibraryService extends BaseService {
|
||||
|
||||
await this.libraryRepository.softDelete(id);
|
||||
await this.jobRepository.queue({ name: JobName.LibraryDelete, data: { id } });
|
||||
|
||||
await this.eventRepository.emit('LibraryDelete');
|
||||
}
|
||||
|
||||
@OnJob({ name: JobName.LibraryDelete, queue: QueueName.Library })
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import { Injectable, OnModuleDestroy, OnModuleInit, Optional } from '@nestjs/common';
|
||||
import { EventsGateway, ModuleConfigRepository } from 'orchestration-api/dist';
|
||||
import { GatewayEvent } from 'orchestration-api/dist/events/events.gateway';
|
||||
import { SystemConfig } from 'src/config';
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { OnEvent } from 'src/decorators';
|
||||
import { DatabaseLock, ImmichWorker, StorageFolder } from 'src/enum';
|
||||
import { DatabaseRepository } from 'src/repositories/database.repository';
|
||||
import { ArgOf, EventRepository } from 'src/repositories/event.repository';
|
||||
import { LibraryRepository } from 'src/repositories/library.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { WebsocketRepository } from 'src/repositories/websocket.repository';
|
||||
import { AuthService } from 'src/services/auth.service';
|
||||
import { getExternalDomain } from 'src/utils/misc';
|
||||
|
||||
@Injectable()
|
||||
export class YuccaService implements OnModuleInit, OnModuleDestroy {
|
||||
private lock = false;
|
||||
|
||||
constructor(
|
||||
private readonly logger: LoggingRepository,
|
||||
private readonly databaseRepository: DatabaseRepository,
|
||||
private readonly libraryRepository: LibraryRepository,
|
||||
private readonly authService: AuthService,
|
||||
private readonly eventRepository: EventRepository,
|
||||
private readonly websocketRepository: WebsocketRepository,
|
||||
@Optional() private readonly moduleConfig: ModuleConfigRepository,
|
||||
@Optional() private readonly eventsGateway: EventsGateway,
|
||||
) {
|
||||
this.onInternalEvent = this.onInternalEvent.bind(this);
|
||||
}
|
||||
|
||||
onModuleInit() {
|
||||
if (this.eventsGateway) {
|
||||
this.eventsGateway.setAuthFn(async (client) =>
|
||||
this.authService.authenticate({
|
||||
headers: client.request.headers,
|
||||
queryParams: {},
|
||||
metadata: { adminRoute: true, sharedLinkRoute: false, uri: '/api/yucca/socket.io' },
|
||||
}),
|
||||
);
|
||||
|
||||
this.eventsGateway.on(this.onInternalEvent);
|
||||
}
|
||||
}
|
||||
|
||||
onModuleDestroy() {
|
||||
if (this.eventsGateway) {
|
||||
this.eventsGateway.off(this.onInternalEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private updateSystemConfig({ server }: SystemConfig) {
|
||||
this.moduleConfig.update({
|
||||
externalBaseUrl: getExternalDomain(server),
|
||||
});
|
||||
}
|
||||
|
||||
private async updateLibraryConfig() {
|
||||
const libraries = await this.libraryRepository.getAll();
|
||||
|
||||
this.moduleConfig.update({
|
||||
immichIntegration: {
|
||||
dataPath: StorageCore.getMediaLocation(),
|
||||
dataFolders: Object.values(StorageFolder),
|
||||
libraries: libraries
|
||||
.filter((library) => !library.deletedAt)
|
||||
.map(({ id, name, importPaths, exclusionPatterns }) => ({ id, name, importPaths, exclusionPatterns })),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'ConfigInit', workers: [ImmichWorker.Api] })
|
||||
async onConfigInit({ newConfig }: ArgOf<'ConfigInit'>) {
|
||||
this.updateSystemConfig(newConfig);
|
||||
void this.updateLibraryConfig();
|
||||
|
||||
this.lock = await this.databaseRepository.tryLock(DatabaseLock.YuccaModuleConfig);
|
||||
|
||||
if (this.lock) {
|
||||
this.moduleConfig.acquireLock();
|
||||
}
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'ConfigUpdate', workers: [ImmichWorker.Api], server: true })
|
||||
onConfigUpdate({ newConfig }: ArgOf<'ConfigUpdate'>) {
|
||||
void this.updateSystemConfig(newConfig);
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'LibraryCreate', workers: [ImmichWorker.Api], server: true })
|
||||
onLibraryCreate() {
|
||||
void this.updateLibraryConfig();
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'LibraryUpdate', workers: [ImmichWorker.Api], server: true })
|
||||
onLibraryUpdate() {
|
||||
void this.updateLibraryConfig();
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'LibraryDelete', workers: [ImmichWorker.Api], server: true })
|
||||
onLibraryDelete() {
|
||||
void this.updateLibraryConfig();
|
||||
}
|
||||
|
||||
@OnEvent({ name: 'YuccaEvent', workers: [ImmichWorker.Api], server: true })
|
||||
onYuccaEvent(event: GatewayEvent) {
|
||||
this.eventsGateway.emit(event);
|
||||
}
|
||||
|
||||
onInternalEvent(event: GatewayEvent) {
|
||||
this.websocketRepository.serverSend('YuccaEvent', event);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user