1
0
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:
midzelis
2025-07-12 15:08:56 +00:00
parent 04aab6ecce
commit be816ecf8a
8 changed files with 32 additions and 14 deletions

View File

@@ -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 });

View File

@@ -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) {

View File

@@ -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));

View File

@@ -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}"`);
}

View File

@@ -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);

View File

@@ -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" "$@"

View File

@@ -0,0 +1 @@
(globalThis as any).TESTING = true;

View File

@@ -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/**'],