You've already forked immich
							
							
				mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 00:18:28 +02:00 
			
		
		
		
	feat: specify server home
This commit is contained in:
		| @@ -1,5 +1,6 @@ | ||||
| import { Duration } from 'luxon'; | ||||
| import { readFileSync } from 'node:fs'; | ||||
| import { resolve } from 'node:path'; | ||||
| import { SemVer } from 'semver'; | ||||
| import { DatabaseExtension, ExifOrientation, VectorIndex } from 'src/enum'; | ||||
|  | ||||
| @@ -40,8 +41,13 @@ export const VECTORCHORD_LIST_SLACK_FACTOR = 1.2; | ||||
| export const SALT_ROUNDS = 10; | ||||
|  | ||||
| export const IWorker = 'IWorker'; | ||||
|  | ||||
| const { version } = JSON.parse(readFileSync('./package.json', 'utf8')); | ||||
| // This is where server is install to, should always be absolute. | ||||
| export const SERVER_HOME = process.env.SERVER_HOME || '.'; | ||||
| // This is what APP_MEDIA_LOCATION is resolved against. (Only matters if APP_MEDIA_LOCATION is relative). | ||||
| // Defaults to SERVER_HOME. | ||||
| export const BASE_FOLDER = process.env.BASE_FOLDER || SERVER_HOME; | ||||
| const packageFile = 'TESTING' in globalThis ? resolve('./package.json') : resolve(SERVER_HOME, './package.json'); | ||||
| const { version } = JSON.parse(readFileSync(packageFile, 'utf8')); | ||||
| export const serverVersion = new SemVer(version); | ||||
|  | ||||
| export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 }); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { randomUUID } from 'node:crypto'; | ||||
| import { dirname, join, resolve } from 'node:path'; | ||||
| import { APP_MEDIA_LOCATION } from 'src/constants'; | ||||
| import { APP_MEDIA_LOCATION, BASE_FOLDER } from 'src/constants'; | ||||
| import { StorageAsset } from 'src/database'; | ||||
| import { AssetFileType, AssetPathType, ImageFormat, PathType, PersonPathType, StorageFolder } from 'src/enum'; | ||||
| import { AssetRepository } from 'src/repositories/asset.repository'; | ||||
| @@ -83,7 +83,11 @@ export class StorageCore { | ||||
|   } | ||||
|  | ||||
|   static getBaseFolder(folder: StorageFolder) { | ||||
|     return join(APP_MEDIA_LOCATION, folder); | ||||
|     if ('TESTING' in globalThis) { | ||||
|       // this is a special case for testing, since it expects the spys to be called with relative paths | ||||
|       return join(APP_MEDIA_LOCATION, folder); | ||||
|     } | ||||
|     return resolve(BASE_FOLDER, join(APP_MEDIA_LOCATION, folder)); | ||||
|   } | ||||
|  | ||||
|   static getPersonThumbnailPath(person: ThumbnailPathEntity) { | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| import { CommandFactory } from 'nest-commander'; | ||||
| import { ChildProcess, fork } from 'node:child_process'; | ||||
| import { resolve } from 'node:path'; | ||||
| import { Worker } from 'node:worker_threads'; | ||||
| import { ImmichAdminModule } from 'src/app.module'; | ||||
| import { SERVER_HOME } from 'src/constants'; | ||||
| import { ImmichWorker, LogLevel } from 'src/enum'; | ||||
| import { ConfigRepository } from 'src/repositories/config.repository'; | ||||
|  | ||||
| @@ -35,12 +37,12 @@ function bootstrapWorker(name: ImmichWorker) { | ||||
|  | ||||
|   let worker: Worker | ChildProcess; | ||||
|   if (name === ImmichWorker.API) { | ||||
|     worker = fork(`./dist/workers/${name}.js`, [], { | ||||
|     worker = fork(resolve(SERVER_HOME, `./dist/workers/${name}.js`), [], { | ||||
|       execArgv: process.execArgv.map((arg) => (arg.startsWith('--inspect') ? '--inspect=0.0.0.0:9231' : arg)), | ||||
|     }); | ||||
|     apiProcess = worker; | ||||
|   } else { | ||||
|     worker = new Worker(`./dist/workers/${name}.js`); | ||||
|     worker = new Worker(resolve(SERVER_HOME, `./dist/workers/${name}.js`)); | ||||
|   } | ||||
|  | ||||
|   worker.on('error', (error) => onError(name, error)); | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { Injectable } from '@nestjs/common'; | ||||
| import { join, resolve } from 'node:path'; | ||||
| import { BASE_FOLDER } from 'src/constants'; | ||||
| import { StorageCore } from 'src/cores/storage.core'; | ||||
| import { OnEvent, OnJob } from 'src/decorators'; | ||||
| import { DatabaseLock, JobName, JobStatus, QueueName, StorageFolder, SystemMetadataKey } from 'src/enum'; | ||||
| @@ -87,7 +88,7 @@ export class StorageService extends BaseService { | ||||
|     try { | ||||
|       await this.storageRepository.readFile(internalPath); | ||||
|     } catch (error) { | ||||
|       const fullyQualifiedPath = resolve(process.cwd(), internalPath); | ||||
|       const fullyQualifiedPath = resolve(BASE_FOLDER, internalPath); | ||||
|       this.logger.error(`Failed to read ${fullyQualifiedPath} (${internalPath}): ${error}`); | ||||
|       throw new ImmichStartupError(`Failed to read: "${externalPath} (${fullyQualifiedPath}) - ${docsMessage}"`); | ||||
|     } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import { NextFunction, Response } from 'express'; | ||||
| import { access, constants } from 'node:fs/promises'; | ||||
| import { basename, extname, isAbsolute } from 'node:path'; | ||||
| import { promisify } from 'node:util'; | ||||
| import { BASE_FOLDER } from 'src/constants'; | ||||
| import { CacheControl } from 'src/enum'; | ||||
| import { LoggingRepository } from 'src/repositories/logging.repository'; | ||||
| import { ImmichReadStream } from 'src/repositories/storage.repository'; | ||||
| @@ -65,7 +66,7 @@ export const sendFile = async ( | ||||
|     // configure options for serving | ||||
|     const options: SendFileOptions = { dotfiles: 'allow' }; | ||||
|     if (!isAbsolute(file.path)) { | ||||
|       options.root = process.cwd(); | ||||
|       options.root = BASE_FOLDER; | ||||
|     } | ||||
|  | ||||
|     await access(file.path, constants.R_OK); | ||||
|   | ||||
| @@ -5,13 +5,15 @@ echo "Initializing Immich $IMMICH_SOURCE_REF" | ||||
| lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.2" | ||||
| export LD_PRELOAD="$lib_path" | ||||
| export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/jellyfin-ffmpeg/lib" | ||||
| export SERVER_HOME=/usr/src/app | ||||
| export BASE_FOLDER=/usr/src/app | ||||
|  | ||||
| read_file_and_export() { | ||||
| 	if [ -n "${!1}" ]; then | ||||
| 		content="$(cat "${!1}")" | ||||
| 		export "$2"="${content}" | ||||
| 		unset "$1" | ||||
| 	fi | ||||
|   if [ -n "${!1}" ]; then | ||||
|     content="$(cat "${!1}")" | ||||
|     export "$2"="${content}" | ||||
|     unset "$1" | ||||
|   fi | ||||
| } | ||||
| read_file_and_export "DB_URL_FILE" "DB_URL" | ||||
| read_file_and_export "DB_HOSTNAME_FILE" "DB_HOSTNAME" | ||||
| @@ -26,4 +28,4 @@ if [ "$CPU_CORES" -gt 4 ]; then | ||||
|   export UV_THREADPOOL_SIZE=$CPU_CORES | ||||
| fi | ||||
|  | ||||
| exec node /usr/src/app/dist/main "$@" | ||||
| exec node "${SERVER_HOME}/dist/main" "$@" | ||||
|   | ||||
							
								
								
									
										1
									
								
								server/test/vitest-setup.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								server/test/vitest-setup.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| (globalThis as any).TESTING = true; | ||||
| @@ -10,6 +10,7 @@ export default defineConfig({ | ||||
|     root: './', | ||||
|     globals: true, | ||||
|     include: ['src/**/*.spec.ts'], | ||||
|     setupFiles: ['./test/vitest-setup.ts'], | ||||
|     coverage: { | ||||
|       provider: 'v8', | ||||
|       include: ['src/cores/**', 'src/services/**', 'src/utils/**', 'src/sql-tools/**'], | ||||
|   | ||||
		Reference in New Issue
	
	Block a user