Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: more process.env references #13106

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion server/src/bin/sync-open-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useSwagger } from 'src/utils/misc';

const sync = async () => {
const app = await NestFactory.create<NestExpressApplication>(ApiModule, { preview: true });
useSwagger(app, true);
useSwagger(app, { write: true });
await app.close();
};

Expand Down
6 changes: 5 additions & 1 deletion server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Colorspace,
CQMode,
ImageFormat,
ImmichEnvironment,
LogLevel,
ToneMapping,
TranscodeHWAccel,
Expand Down Expand Up @@ -322,7 +323,10 @@ export const immichAppConfig: ConfigModuleOptions = {
envFilePath: '.env',
isGlobal: true,
validationSchema: Joi.object({
IMMICH_ENV: Joi.string().optional().valid('development', 'testing', 'production').default('production'),
IMMICH_ENV: Joi.string()
.optional()
.valid(...Object.values(ImmichEnvironment))
.default(ImmichEnvironment.PRODUCTION),
IMMICH_LOG_LEVEL: Joi.string()
.optional()
.valid(...Object.values(LogLevel)),
Expand Down
1 change: 0 additions & 1 deletion server/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 });
export const ONE_HOUR = Duration.fromObject({ hours: 1 });

export const envName = (process.env.IMMICH_ENV || 'production').toUpperCase();
export const isDev = () => process.env.IMMICH_ENV === 'development';
export const APP_MEDIA_LOCATION = process.env.IMMICH_MEDIA_LOCATION || './upload';
const HOST_SERVER_PORT = process.env.IMMICH_PORT || '2283';
export const DEFAULT_EXTERNAL_DOMAIN = 'http://localhost:' + HOST_SERVER_PORT;
Expand Down
6 changes: 6 additions & 0 deletions server/src/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,9 @@ export enum PaginationMode {
LIMIT_OFFSET = 'limit-offset',
SKIP_TAKE = 'skip-take',
}

export enum ImmichEnvironment {
DEVELOPMENT = 'development',
TESTING = 'testing',
PRODUCTION = 'production',
}
7 changes: 7 additions & 0 deletions server/src/interfaces/config.interface.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { ImmichEnvironment, LogLevel } from 'src/enum';
import { VectorExtension } from 'src/interfaces/database.interface';

export const IConfigRepository = 'IConfigRepository';

export interface EnvData {
environment: ImmichEnvironment;
configFile?: string;
logLevel?: LogLevel;

database: {
skipMigrations: boolean;
vectorExtension: VectorExtension;
};

storage: {
ignoreMountCheckErrors: boolean;
};

nodeVersion?: string;
}

export interface IConfigRepository {
Expand Down
2 changes: 1 addition & 1 deletion server/src/interfaces/logger.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const ILoggerRepository = 'ILoggerRepository';
export interface ILoggerRepository {
setAppName(name: string): void;
setContext(message: string): void;
setLogLevel(level: LogLevel): void;
setLogLevel(level: LogLevel | false): void;
isLevelEnabled(level: LogLevel): boolean;

verbose(message: any, ...args: any): void;
Expand Down
5 changes: 5 additions & 0 deletions server/src/repositories/config.repository.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Injectable } from '@nestjs/common';
import { getVectorExtension } from 'src/database.config';
import { ImmichEnvironment, LogLevel } from 'src/enum';
import { EnvData, IConfigRepository } from 'src/interfaces/config.interface';

// TODO replace src/config validation with class-validator, here

@Injectable()
export class ConfigRepository implements IConfigRepository {
getEnv(): EnvData {
return {
environment: process.env.IMMICH_ENV as ImmichEnvironment,
configFile: process.env.IMMICH_CONFIG_FILE,
logLevel: process.env.IMMICH_LOG_LEVEL as LogLevel,
database: {
skipMigrations: process.env.DB_SKIP_MIGRATIONS === 'true',
vectorExtension: getVectorExtension(),
Expand Down
4 changes: 2 additions & 2 deletions server/src/repositories/logger.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export class LoggerRepository extends ConsoleLogger implements ILoggerRepository
return isLogLevelEnabled(level, LoggerRepository.logLevels);
}

setLogLevel(level: LogLevel): void {
LoggerRepository.logLevels = LOG_LEVELS.slice(LOG_LEVELS.indexOf(level));
setLogLevel(level: LogLevel | false): void {
LoggerRepository.logLevels = level ? LOG_LEVELS.slice(LOG_LEVELS.indexOf(level)) : [];
}

protected formatContext(context: string): string {
Expand Down
10 changes: 8 additions & 2 deletions server/src/repositories/server-info.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { readFile } from 'node:fs/promises';
import { promisify } from 'node:util';
import sharp from 'sharp';
import { resourcePaths } from 'src/constants';
import { IConfigRepository } from 'src/interfaces/config.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { GitHubRelease, IServerInfoRepository, ServerBuildVersions } from 'src/interfaces/server-info.interface';
import { Instrumentation } from 'src/utils/instrumentation';
Expand Down Expand Up @@ -37,7 +38,10 @@ const getLockfileVersion = (name: string, lockfile?: BuildLockfile) => {
@Instrumentation()
@Injectable()
export class ServerInfoRepository implements IServerInfoRepository {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) {
constructor(
@Inject(IConfigRepository) private configRepository: IConfigRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.logger.setContext(ServerInfoRepository.name);
}

Expand All @@ -56,6 +60,8 @@ export class ServerInfoRepository implements IServerInfoRepository {
}

async getBuildVersions(): Promise<ServerBuildVersions> {
const { nodeVersion } = this.configRepository.getEnv();

const [nodejsOutput, ffmpegOutput, magickOutput] = await Promise.all([
maybeFirstLine('node --version'),
maybeFirstLine('ffmpeg -version'),
Expand All @@ -67,7 +73,7 @@ export class ServerInfoRepository implements IServerInfoRepository {
.catch(() => this.logger.warn(`Failed to read ${resourcePaths.lockFile}`));

return {
nodejs: nodejsOutput || process.env.NODE_VERSION || '',
nodejs: nodejsOutput || nodeVersion || '',
exiftool: await exiftool.version(),
ffmpeg: getLockfileVersion('ffmpeg', lockfile) || ffmpegOutput.replaceAll('ffmpeg version', '') || '',
libvips: getLockfileVersion('libvips', lockfile) || sharp.versions.vips,
Expand Down
10 changes: 3 additions & 7 deletions server/src/services/system-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from 'src/constants';
import { OnEvent } from 'src/decorators';
import { SystemConfigDto, SystemConfigTemplateStorageOptionDto, mapConfig } from 'src/dtos/system-config.dto';
import { LogLevel } from 'src/enum';
import { IConfigRepository } from 'src/interfaces/config.interface';
import { ArgOf, IEventRepository } from 'src/interfaces/event.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
Expand Down Expand Up @@ -52,7 +51,7 @@ export class SystemConfigService extends BaseService {

@OnEvent({ name: 'config.update', server: true })
onConfigUpdate({ newConfig: { logging } }: ArgOf<'config.update'>) {
const envLevel = this.getEnvLogLevel();
const { logLevel: envLevel } = this.configRepository.getEnv();
const configLevel = logging.enabled ? logging.level : false;
const level = envLevel ?? configLevel;
this.logger.setLogLevel(level);
Expand All @@ -63,7 +62,8 @@ export class SystemConfigService extends BaseService {

@OnEvent({ name: 'config.validate' })
onConfigValidate({ newConfig, oldConfig }: ArgOf<'config.validate'>) {
if (!_.isEqual(instanceToPlain(newConfig.logging), oldConfig.logging) && this.getEnvLogLevel()) {
const { logLevel } = this.configRepository.getEnv();
if (!_.isEqual(instanceToPlain(newConfig.logging), oldConfig.logging) && logLevel) {
throw new Error('Logging cannot be changed while the environment variable IMMICH_LOG_LEVEL is set.');
}
}
Expand Down Expand Up @@ -109,8 +109,4 @@ export class SystemConfigService extends BaseService {
const { theme } = await this.getConfig({ withCache: false });
return theme.customCss;
}

private getEnvLogLevel() {
return process.env.IMMICH_LOG_LEVEL as LogLevel;
}
}
8 changes: 4 additions & 4 deletions server/src/services/version.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DateTime } from 'luxon';
import { serverVersion } from 'src/constants';
import { SystemMetadataKey } from 'src/enum';
import { ImmichEnvironment, SystemMetadataKey } from 'src/enum';
import { IConfigRepository } from 'src/interfaces/config.interface';
import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { IEventRepository } from 'src/interfaces/event.interface';
Expand All @@ -10,7 +10,7 @@ import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
import { VersionService } from 'src/services/version.service';
import { newConfigRepositoryMock } from 'test/repositories/config.repository.mock';
import { mockEnvData, newConfigRepositoryMock } from 'test/repositories/config.repository.mock';
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
Expand Down Expand Up @@ -111,11 +111,11 @@ describe(VersionService.name, () => {

describe('handVersionCheck', () => {
beforeEach(() => {
process.env.IMMICH_ENV = 'production';
configMock.getEnv.mockReturnValue(mockEnvData({ environment: ImmichEnvironment.PRODUCTION }));
});

it('should not run in dev mode', async () => {
process.env.IMMICH_ENV = 'development';
configMock.getEnv.mockReturnValue(mockEnvData({ environment: ImmichEnvironment.DEVELOPMENT }));
await expect(sut.handleVersionCheck()).resolves.toEqual(JobStatus.SKIPPED);
});

Expand Down
7 changes: 4 additions & 3 deletions server/src/services/version.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Inject, Injectable } from '@nestjs/common';
import { DateTime } from 'luxon';
import semver, { SemVer } from 'semver';
import { isDev, serverVersion } from 'src/constants';
import { serverVersion } from 'src/constants';
import { OnEvent } from 'src/decorators';
import { ReleaseNotification, ServerVersionResponseDto } from 'src/dtos/server.dto';
import { VersionCheckMetadata } from 'src/entities/system-metadata.entity';
import { SystemMetadataKey } from 'src/enum';
import { ImmichEnvironment, SystemMetadataKey } from 'src/enum';
import { IConfigRepository } from 'src/interfaces/config.interface';
import { DatabaseLock, IDatabaseRepository } from 'src/interfaces/database.interface';
import { ArgOf, IEventRepository } from 'src/interfaces/event.interface';
Expand Down Expand Up @@ -71,7 +71,8 @@ export class VersionService extends BaseService {
try {
this.logger.debug('Running version check');

if (isDev()) {
const { environment } = this.configRepository.getEnv();
if (environment === ImmichEnvironment.DEVELOPMENT) {
return JobStatus.SKIPPED;
}

Expand Down
6 changes: 3 additions & 3 deletions server/src/utils/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import _ from 'lodash';
import { writeFileSync } from 'node:fs';
import path from 'node:path';
import { SystemConfig } from 'src/config';
import { CLIP_MODEL_INFO, isDev, serverVersion } from 'src/constants';
import { CLIP_MODEL_INFO, serverVersion } from 'src/constants';
import { ImmichCookie, ImmichHeader } from 'src/dtos/auth.dto';
import { MetadataKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
Expand Down Expand Up @@ -193,7 +193,7 @@ const patchOpenAPI = (document: OpenAPIObject) => {
return document;
};

export const useSwagger = (app: INestApplication, force = false) => {
export const useSwagger = (app: INestApplication, { write }: { write: boolean }) => {
const config = new DocumentBuilder()
.setTitle('Immich')
.setDescription('Immich API')
Expand Down Expand Up @@ -230,7 +230,7 @@ export const useSwagger = (app: INestApplication, force = false) => {

SwaggerModule.setup('doc', app, specification, customOptions);

if (isDev() || force) {
if (write) {
// Generate API Documentation only in development mode
const outputPath = path.resolve(process.cwd(), '../open-api/immich-openapi-specs.json');
writeFileSync(outputPath, JSON.stringify(patchOpenAPI(specification), null, 2), { encoding: 'utf8' });
Expand Down
12 changes: 9 additions & 3 deletions server/src/workers/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import cookieParser from 'cookie-parser';
import { existsSync } from 'node:fs';
import sirv from 'sirv';
import { ApiModule } from 'src/app.module';
import { envName, excludePaths, isDev, resourcePaths, serverVersion } from 'src/constants';
import { envName, excludePaths, resourcePaths, serverVersion } from 'src/constants';
import { ImmichEnvironment } from 'src/enum';
import { IConfigRepository } from 'src/interfaces/config.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { WebSocketAdapter } from 'src/middleware/websocket.adapter';
import { ApiService } from 'src/services/api.service';
Expand Down Expand Up @@ -33,6 +35,10 @@ async function bootstrap() {
const port = Number(process.env.IMMICH_PORT) || 3001;
const app = await NestFactory.create<NestExpressApplication>(ApiModule, { bufferLogs: true });
const logger = await app.resolve<ILoggerRepository>(ILoggerRepository);
const configRepository = app.get<IConfigRepository>(IConfigRepository);

const { environment } = configRepository.getEnv();
const isDev = environment === ImmichEnvironment.DEVELOPMENT;

logger.setAppName('Api');
logger.setContext('Bootstrap');
Expand All @@ -41,11 +47,11 @@ async function bootstrap() {
app.set('etag', 'strong');
app.use(cookieParser());
app.use(json({ limit: '10mb' }));
if (isDev()) {
if (isDev) {
app.enableCors();
}
app.useWebSocketAdapter(new WebSocketAdapter(app));
useSwagger(app);
useSwagger(app, { write: isDev });

app.setGlobalPrefix('api', { exclude: excludePaths });
if (existsSync(resourcePaths.web.root)) {
Expand Down
4 changes: 4 additions & 0 deletions server/test/repositories/config.repository.mock.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { ImmichEnvironment } from 'src/enum';
import { EnvData, IConfigRepository } from 'src/interfaces/config.interface';
import { DatabaseExtension } from 'src/interfaces/database.interface';
import { Mocked, vitest } from 'vitest';

const envData: EnvData = {
environment: ImmichEnvironment.PRODUCTION,

database: {
skipMigrations: false,
vectorExtension: DatabaseExtension.VECTORS,
},

storage: {
ignoreMountCheckErrors: false,
},
Expand Down
Loading