From 6bbaba786665055c8ae4407a85fd2a8e153d3010 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Fri, 4 Oct 2024 17:09:02 -0400 Subject: [PATCH] refactor(server): resource paths (#13194) --- server/src/constants.ts | 23 ------------------- server/src/interfaces/config.interface.ts | 15 ++++++++++++ server/src/repositories/config.repository.ts | 22 ++++++++++++++++++ server/src/repositories/map.repository.ts | 9 +++++++- .../repositories/server-info.repository.ts | 3 +-- server/src/services/api.service.ts | 6 ++++- server/src/workers/api.ts | 4 ++-- .../repositories/config.repository.mock.ts | 15 ++++++++++++ 8 files changed, 68 insertions(+), 29 deletions(-) diff --git a/server/src/constants.ts b/server/src/constants.ts index 26c9ef5a98dac..5317d5e13c57a 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -1,6 +1,5 @@ import { Duration } from 'luxon'; import { readFileSync } from 'node:fs'; -import { join } from 'node:path'; import { SemVer } from 'semver'; export const POSTGRES_VERSION_RANGE = '>=14.0.0'; @@ -26,28 +25,6 @@ export const DEFAULT_EXTERNAL_DOMAIN = 'http://localhost:' + HOST_SERVER_PORT; export const citiesFile = 'cities500.txt'; -const buildFolder = process.env.IMMICH_BUILD_DATA || '/build'; - -const folders = { - geodata: join(buildFolder, 'geodata'), - web: join(buildFolder, 'www'), -}; - -export const resourcePaths = { - lockFile: join(buildFolder, 'build-lock.json'), - geodata: { - dateFile: join(folders.geodata, 'geodata-date.txt'), - admin1: join(folders.geodata, 'admin1CodesASCII.txt'), - admin2: join(folders.geodata, 'admin2Codes.txt'), - cities500: join(folders.geodata, citiesFile), - naturalEarthCountriesPath: join(folders.geodata, 'ne_10m_admin_0_countries.geojson'), - }, - web: { - root: folders.web, - indexHtml: join(folders.web, 'index.html'), - }, -}; - export const MOBILE_REDIRECT = 'app.immich:///oauth-callback'; export const LOGIN_URL = '/auth/login?autoLaunch=0'; diff --git a/server/src/interfaces/config.interface.ts b/server/src/interfaces/config.interface.ts index 23a3803284d08..d105e40cf90d5 100644 --- a/server/src/interfaces/config.interface.ts +++ b/server/src/interfaces/config.interface.ts @@ -41,6 +41,21 @@ export interface EnvData { server: string; }; + resourcePaths: { + lockFile: string; + geodata: { + dateFile: string; + admin1: string; + admin2: string; + cities500: string; + naturalEarthCountriesPath: string; + }; + web: { + root: string; + indexHtml: string; + }; + }; + storage: { ignoreMountCheckErrors: boolean; }; diff --git a/server/src/repositories/config.repository.ts b/server/src/repositories/config.repository.ts index ed9d80a980b60..a9f9ca0c1ddb5 100644 --- a/server/src/repositories/config.repository.ts +++ b/server/src/repositories/config.repository.ts @@ -1,4 +1,6 @@ import { Injectable } from '@nestjs/common'; +import { join } from 'node:path'; +import { citiesFile } from 'src/constants'; import { ImmichEnvironment, ImmichWorker, LogLevel } from 'src/enum'; import { EnvData, IConfigRepository } from 'src/interfaces/config.interface'; import { DatabaseExtension } from 'src/interfaces/database.interface'; @@ -41,6 +43,11 @@ export class ConfigRepository implements IConfigRepository { const environment = process.env.IMMICH_ENV as ImmichEnvironment; const isProd = environment === ImmichEnvironment.PRODUCTION; + const buildFolder = process.env.IMMICH_BUILD_DATA || '/build'; + const folders = { + geodata: join(buildFolder, 'geodata'), + web: join(buildFolder, 'www'), + }; return { port: Number(process.env.IMMICH_PORT) || 3001, @@ -79,6 +86,21 @@ export class ConfigRepository implements IConfigRepository { licensePublicKey: isProd ? productionKeys : stagingKeys, + resourcePaths: { + lockFile: join(buildFolder, 'build-lock.json'), + geodata: { + dateFile: join(folders.geodata, 'geodata-date.txt'), + admin1: join(folders.geodata, 'admin1CodesASCII.txt'), + admin2: join(folders.geodata, 'admin2Codes.txt'), + cities500: join(folders.geodata, citiesFile), + naturalEarthCountriesPath: join(folders.geodata, 'ne_10m_admin_0_countries.geojson'), + }, + web: { + root: folders.web, + indexHtml: join(folders.web, 'index.html'), + }, + }, + storage: { ignoreMountCheckErrors: process.env.IMMICH_IGNORE_MOUNT_CHECK_ERRORS === 'true', }, diff --git a/server/src/repositories/map.repository.ts b/server/src/repositories/map.repository.ts index 3508de720b2e1..8ba9b4cab8c65 100644 --- a/server/src/repositories/map.repository.ts +++ b/server/src/repositories/map.repository.ts @@ -4,11 +4,12 @@ import { getName } from 'i18n-iso-countries'; import { createReadStream, existsSync } from 'node:fs'; import { readFile } from 'node:fs/promises'; import readLine from 'node:readline'; -import { citiesFile, resourcePaths } from 'src/constants'; +import { citiesFile } from 'src/constants'; import { AssetEntity } from 'src/entities/asset.entity'; import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity'; import { NaturalEarthCountriesEntity } from 'src/entities/natural-earth-countries.entity'; import { SystemMetadataKey } from 'src/enum'; +import { IConfigRepository } from 'src/interfaces/config.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { GeoPoint, @@ -32,6 +33,7 @@ export class MapRepository implements IMapRepository { @InjectRepository(NaturalEarthCountriesEntity) private naturalEarthCountriesRepository: Repository, @InjectDataSource() private dataSource: DataSource, + @Inject(IConfigRepository) private configRepository: IConfigRepository, @Inject(ISystemMetadataRepository) private metadataRepository: ISystemMetadataRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { @@ -40,6 +42,7 @@ export class MapRepository implements IMapRepository { async init(): Promise { this.logger.log('Initializing metadata repository'); + const { resourcePaths } = this.configRepository.getEnv(); const geodataDate = await readFile(resourcePaths.geodata.dateFile, 'utf8'); // TODO move to service init @@ -181,6 +184,8 @@ export class MapRepository implements IMapRepository { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); + const { resourcePaths } = this.configRepository.getEnv(); + try { await queryRunner.startTransaction(); await queryRunner.manager.clear(NaturalEarthCountriesEntity); @@ -225,6 +230,7 @@ export class MapRepository implements IMapRepository { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); + const { resourcePaths } = this.configRepository.getEnv(); const admin1 = await this.loadAdmin(resourcePaths.geodata.admin1); const admin2 = await this.loadAdmin(resourcePaths.geodata.admin2); @@ -280,6 +286,7 @@ export class MapRepository implements IMapRepository { admin1Map: Map, admin2Map: Map, ) { + const { resourcePaths } = this.configRepository.getEnv(); await this.loadGeodataToTableFromFile( queryRunner, (lineSplit: string[]) => diff --git a/server/src/repositories/server-info.repository.ts b/server/src/repositories/server-info.repository.ts index ae04f600c07c6..1936ecdb61aba 100644 --- a/server/src/repositories/server-info.repository.ts +++ b/server/src/repositories/server-info.repository.ts @@ -4,7 +4,6 @@ import { exec as execCallback } from 'node:child_process'; 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'; @@ -60,7 +59,7 @@ export class ServerInfoRepository implements IServerInfoRepository { } async getBuildVersions(): Promise { - const { nodeVersion } = this.configRepository.getEnv(); + const { nodeVersion, resourcePaths } = this.configRepository.getEnv(); const [nodejsOutput, ffmpegOutput, magickOutput] = await Promise.all([ maybeFirstLine('node --version'), diff --git a/server/src/services/api.service.ts b/server/src/services/api.service.ts index 039dcb9aaeafd..66f8061d3c869 100644 --- a/server/src/services/api.service.ts +++ b/server/src/services/api.service.ts @@ -2,7 +2,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { Cron, CronExpression, Interval } from '@nestjs/schedule'; import { NextFunction, Request, Response } from 'express'; import { readFileSync } from 'node:fs'; -import { ONE_HOUR, resourcePaths } from 'src/constants'; +import { ONE_HOUR } from 'src/constants'; +import { IConfigRepository } from 'src/interfaces/config.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AuthService } from 'src/services/auth.service'; import { JobService } from 'src/services/job.service'; @@ -37,6 +38,7 @@ export class ApiService { private jobService: JobService, private sharedLinkService: SharedLinkService, private versionService: VersionService, + @Inject(IConfigRepository) private configRepository: IConfigRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(ApiService.name); @@ -53,6 +55,8 @@ export class ApiService { } ssr(excludePaths: string[]) { + const { resourcePaths } = this.configRepository.getEnv(); + let index = ''; try { index = readFileSync(resourcePaths.web.indexHtml).toString(); diff --git a/server/src/workers/api.ts b/server/src/workers/api.ts index e5ce37dbaba89..7535a902b80d6 100644 --- a/server/src/workers/api.ts +++ b/server/src/workers/api.ts @@ -5,7 +5,7 @@ import cookieParser from 'cookie-parser'; import { existsSync } from 'node:fs'; import sirv from 'sirv'; import { ApiModule } from 'src/app.module'; -import { excludePaths, resourcePaths, serverVersion } from 'src/constants'; +import { excludePaths, serverVersion } from 'src/constants'; import { ImmichEnvironment } from 'src/enum'; import { IConfigRepository } from 'src/interfaces/config.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; @@ -36,7 +36,7 @@ async function bootstrap() { const logger = await app.resolve(ILoggerRepository); const configRepository = app.get(IConfigRepository); - const { environment, port } = configRepository.getEnv(); + const { environment, port, resourcePaths } = configRepository.getEnv(); const isDev = environment === ImmichEnvironment.DEVELOPMENT; logger.setContext('Bootstrap'); diff --git a/server/test/repositories/config.repository.mock.ts b/server/test/repositories/config.repository.mock.ts index 960a7c1e83e25..d44d50524a28a 100644 --- a/server/test/repositories/config.repository.mock.ts +++ b/server/test/repositories/config.repository.mock.ts @@ -25,6 +25,21 @@ const envData: EnvData = { server: 'server-public-key', }, + resourcePaths: { + lockFile: 'build-lock.json', + geodata: { + dateFile: '/build/geodata/geodata-date.txt', + admin1: '/build/geodata/admin1CodesASCII.txt', + admin2: '/build/geodata/admin2Codes.txt', + cities500: '/build/geodata/cities500.txt', + naturalEarthCountriesPath: 'build/ne_10m_admin_0_countries.geojson', + }, + web: { + root: '/build/www', + indexHtml: '/build/www/index.html', + }, + }, + storage: { ignoreMountCheckErrors: false, },