mirror of
https://github.com/immich-app/immich.git
synced 2025-12-18 01:11:07 +03:00
refactor: asset v1, app.utils (#8152)
This commit is contained in:
@@ -1,4 +1,11 @@
|
||||
import { basename, extname } from 'node:path';
|
||||
import { HttpException, StreamableFile } from '@nestjs/common';
|
||||
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 { ImmichReadStream } from 'src/interfaces/storage.interface';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
import { isConnectionAborted } from 'src/utils/misc';
|
||||
|
||||
export function getFileNameWithoutExtension(path: string): string {
|
||||
return basename(path, extname(path));
|
||||
@@ -23,3 +30,59 @@ export class ImmichFileResponse {
|
||||
Object.assign(this, response);
|
||||
}
|
||||
}
|
||||
type SendFile = Parameters<Response['sendFile']>;
|
||||
type SendFileOptions = SendFile[1];
|
||||
|
||||
const logger = new ImmichLogger('SendFile');
|
||||
|
||||
export const sendFile = async (
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
handler: () => Promise<ImmichFileResponse>,
|
||||
): Promise<void> => {
|
||||
const _sendFile = (path: string, options: SendFileOptions) =>
|
||||
promisify<string, SendFileOptions>(res.sendFile).bind(res)(path, options);
|
||||
|
||||
try {
|
||||
const file = await handler();
|
||||
switch (file.cacheControl) {
|
||||
case CacheControl.PRIVATE_WITH_CACHE: {
|
||||
res.set('Cache-Control', 'private, max-age=86400, no-transform');
|
||||
break;
|
||||
}
|
||||
|
||||
case CacheControl.PRIVATE_WITHOUT_CACHE: {
|
||||
res.set('Cache-Control', 'private, no-cache, no-transform');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res.header('Content-Type', file.contentType);
|
||||
|
||||
const options: SendFileOptions = { dotfiles: 'allow' };
|
||||
if (!isAbsolute(file.path)) {
|
||||
options.root = process.cwd();
|
||||
}
|
||||
|
||||
await access(file.path, constants.R_OK);
|
||||
|
||||
return _sendFile(file.path, options);
|
||||
} catch (error: Error | any) {
|
||||
// ignore client-closed connection
|
||||
if (isConnectionAborted(error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// log non-http errors
|
||||
if (error instanceof HttpException === false) {
|
||||
logger.error(`Unable to send file: ${error.name}`, error.stack);
|
||||
}
|
||||
|
||||
res.header('Cache-Control', 'none');
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const asStreamableFile = ({ stream, type, length }: ImmichReadStream) => {
|
||||
return new StreamableFile(stream, { type, length });
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user