make event strings an enum

This commit is contained in:
Jonathan Jogenfors
2024-02-29 22:58:49 +01:00
parent a2ab2fd6f6
commit 967b30cfa5
6 changed files with 38 additions and 27 deletions
@@ -1,4 +1,4 @@
import { LibraryResponseDto, LibraryService, LoginResponseDto } from '@app/domain'; import { LibraryResponseDto, LibraryService, LoginResponseDto, StorageEvent } from '@app/domain';
import { AssetType, LibraryType } from '@app/infra/entities'; import { AssetType, LibraryType } from '@app/infra/entities';
import fs from 'node:fs/promises'; import fs from 'node:fs/promises';
import path from 'node:path'; import path from 'node:path';
@@ -57,7 +57,7 @@ describe(`Library watcher (e2e)`, () => {
`${IMMICH_TEST_ASSET_TEMP_PATH}/file.jpg`, `${IMMICH_TEST_ASSET_TEMP_PATH}/file.jpg`,
); );
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken); const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken);
expect(afterAssets.length).toEqual(1); expect(afterAssets.length).toEqual(1);
@@ -84,10 +84,10 @@ describe(`Library watcher (e2e)`, () => {
`${IMMICH_TEST_ASSET_TEMP_PATH}/file5.jPg`, `${IMMICH_TEST_ASSET_TEMP_PATH}/file5.jPg`,
); );
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken); const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken);
expect(afterAssets.length).toEqual(4); expect(afterAssets.length).toEqual(4);
@@ -99,7 +99,7 @@ describe(`Library watcher (e2e)`, () => {
`${IMMICH_TEST_ASSET_TEMP_PATH}/file.jpg`, `${IMMICH_TEST_ASSET_TEMP_PATH}/file.jpg`,
); );
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
const originalAssets = await api.assetApi.getAllAssets(server, admin.accessToken); const originalAssets = await api.assetApi.getAllAssets(server, admin.accessToken);
expect(originalAssets.length).toEqual(1); expect(originalAssets.length).toEqual(1);
@@ -109,7 +109,7 @@ describe(`Library watcher (e2e)`, () => {
`${IMMICH_TEST_ASSET_TEMP_PATH}/file.jpg`, `${IMMICH_TEST_ASSET_TEMP_PATH}/file.jpg`,
); );
await waitForEvent(libraryService, 'change'); await waitForEvent(libraryService, StorageEvent.CHANGE);
const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken); const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken);
expect(afterAssets).toEqual([ expect(afterAssets).toEqual([
@@ -161,9 +161,9 @@ describe(`Library watcher (e2e)`, () => {
`${IMMICH_TEST_ASSET_TEMP_PATH}/dir3/file4.jpg`, `${IMMICH_TEST_ASSET_TEMP_PATH}/dir3/file4.jpg`,
); );
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
const assets = await api.assetApi.getAllAssets(server, admin.accessToken); const assets = await api.assetApi.getAllAssets(server, admin.accessToken);
expect(assets.length).toEqual(3); expect(assets.length).toEqual(3);
@@ -175,14 +175,14 @@ describe(`Library watcher (e2e)`, () => {
`${IMMICH_TEST_ASSET_TEMP_PATH}/dir1/file.jpg`, `${IMMICH_TEST_ASSET_TEMP_PATH}/dir1/file.jpg`,
); );
await waitForEvent(libraryService, 'add'); await waitForEvent(libraryService, StorageEvent.ADD);
const addedAssets = await api.assetApi.getAllAssets(server, admin.accessToken); const addedAssets = await api.assetApi.getAllAssets(server, admin.accessToken);
expect(addedAssets.length).toEqual(1); expect(addedAssets.length).toEqual(1);
await fs.unlink(`${IMMICH_TEST_ASSET_TEMP_PATH}/dir1/file.jpg`); await fs.unlink(`${IMMICH_TEST_ASSET_TEMP_PATH}/dir1/file.jpg`);
await waitForEvent(libraryService, 'unlink'); await waitForEvent(libraryService, StorageEvent.UNLINK);
const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken); const afterAssets = await api.assetApi.getAllAssets(server, admin.accessToken);
expect(afterAssets[0].isOffline).toEqual(true); expect(afterAssets[0].isOffline).toEqual(true);
@@ -1312,7 +1312,7 @@ describe(LibraryService.name, () => {
storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose })); storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
await sut.init(); await sut.init();
await sut.tearDown(); await sut.teardown();
expect(mockClose).toHaveBeenCalledTimes(2); expect(mockClose).toHaveBeenCalledTimes(2);
}); });
+5 -3
View File
@@ -23,6 +23,7 @@ import {
IStorageRepository, IStorageRepository,
ISystemConfigRepository, ISystemConfigRepository,
IUserRepository, IUserRepository,
StorageEvent,
WithProperty, WithProperty,
} from '../repositories'; } from '../repositories';
import { SystemConfigCore } from '../system-config'; import { SystemConfigCore } from '../system-config';
@@ -141,7 +142,7 @@ export class LibraryService extends EventEmitter {
if (matcher(path)) { if (matcher(path)) {
await this.scanAssets(library.id, [path], library.ownerId, false); await this.scanAssets(library.id, [path], library.ownerId, false);
} }
this.emit('add', path); this.emit(StorageEvent.ADD, path);
}, },
onChange: async (path) => { onChange: async (path) => {
this.logger.debug(`Detected file change for ${path} in library ${library.id}`); this.logger.debug(`Detected file change for ${path} in library ${library.id}`);
@@ -149,7 +150,7 @@ export class LibraryService extends EventEmitter {
// Note: if the changed file was not previously imported, it will be imported now. // Note: if the changed file was not previously imported, it will be imported now.
await this.scanAssets(library.id, [path], library.ownerId, false); await this.scanAssets(library.id, [path], library.ownerId, false);
} }
this.emit('change', path); this.emit(StorageEvent.CHANGE, path);
}, },
onUnlink: async (path) => { onUnlink: async (path) => {
this.logger.debug(`Detected deleted file at ${path} in library ${library.id}`); this.logger.debug(`Detected deleted file at ${path} in library ${library.id}`);
@@ -157,11 +158,12 @@ export class LibraryService extends EventEmitter {
if (asset && matcher(path)) { if (asset && matcher(path)) {
await this.assetRepository.save({ id: asset.id, isOffline: true }); await this.assetRepository.save({ id: asset.id, isOffline: true });
} }
this.emit('unlink', path); this.emit(StorageEvent.UNLINK, path);
}, },
onError: (error) => { onError: (error) => {
// TODO: should we log, or throw an exception? // TODO: should we log, or throw an exception?
this.logger.error(`Library watcher for library ${library.id} encountered error: ${error}`); this.logger.error(`Library watcher for library ${library.id} encountered error: ${error}`);
this.emit(StorageEvent.ERROR, error);
}, },
}, },
); );
@@ -31,6 +31,14 @@ export interface WatchEvents {
onError(error: Error): void; onError(error: Error): void;
} }
export enum StorageEvent {
READY = 'ready',
ADD = 'add',
CHANGE = 'change',
UNLINK = 'unlink',
ERROR = 'error',
}
export interface IStorageRepository { export interface IStorageRepository {
createZipStream(): ImmichZipStream; createZipStream(): ImmichZipStream;
createReadStream(filepath: string, mimeType?: string | null): Promise<ImmichReadStream>; createReadStream(filepath: string, mimeType?: string | null): Promise<ImmichReadStream>;
@@ -1,11 +1,12 @@
import { import {
CrawlOptionsDto, CrawlOptionsDto,
DiskUsage, DiskUsage,
IStorageRepository,
ImmichReadStream, ImmichReadStream,
ImmichZipStream, ImmichZipStream,
IStorageRepository, StorageEvent,
mimeTypes,
WatchEvents, WatchEvents,
mimeTypes,
} from '@app/domain'; } from '@app/domain';
import { ImmichLogger } from '@app/infra/logger'; import { ImmichLogger } from '@app/infra/logger';
import archiver from 'archiver'; import archiver from 'archiver';
@@ -141,11 +142,11 @@ export class FilesystemProvider implements IStorageRepository {
watch(paths: string[], options: WatchOptions, events: Partial<WatchEvents>) { watch(paths: string[], options: WatchOptions, events: Partial<WatchEvents>) {
const watcher = chokidar.watch(paths, options); const watcher = chokidar.watch(paths, options);
watcher.on('ready', () => events.onReady?.()); watcher.on(StorageEvent.READY, () => events.onReady?.());
watcher.on('add', (path) => events.onAdd?.(path)); watcher.on(StorageEvent.ADD, (path) => events.onAdd?.(path));
watcher.on('change', (path) => events.onChange?.(path)); watcher.on(StorageEvent.CHANGE, (path) => events.onChange?.(path));
watcher.on('unlink', (path) => events.onUnlink?.(path)); watcher.on(StorageEvent.UNLINK, (path) => events.onUnlink?.(path));
watcher.on('error', (error) => events.onError?.(error)); watcher.on(StorageEvent.ERROR, (error) => events.onError?.(error));
return () => watcher.close(); return () => watcher.close();
} }
+3 -3
View File
@@ -1,4 +1,4 @@
import { IJobRepository, IMediaRepository, JobItem, JobItemHandler, QueueName } from '@app/domain'; import { IJobRepository, IMediaRepository, JobItem, JobItemHandler, QueueName, StorageEvent } from '@app/domain';
import { AppModule } from '@app/immich'; import { AppModule } from '@app/immich';
import { InfraModule, InfraTestModule, dataSource } from '@app/infra'; import { InfraModule, InfraTestModule, dataSource } from '@app/infra';
import { MediaRepository } from '@app/infra/repositories'; import { MediaRepository } from '@app/infra/repositories';
@@ -141,7 +141,7 @@ export const testApp = {
export function waitForEvent<T>(emitter: EventEmitter, event: string): Promise<T> { export function waitForEvent<T>(emitter: EventEmitter, event: string): Promise<T> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const success = (value: T) => { const success = (value: T) => {
emitter.off('error', fail); emitter.off(StorageEvent.ERROR, fail);
resolve(value); resolve(value);
}; };
const fail = (error: Error) => { const fail = (error: Error) => {
@@ -149,7 +149,7 @@ export function waitForEvent<T>(emitter: EventEmitter, event: string): Promise<T
reject(error); reject(error);
}; };
emitter.once(event, success); emitter.once(event, success);
emitter.once('error', fail); emitter.once(StorageEvent.ERROR, fail);
}); });
} }