1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-04 02:46:47 +01:00

hotfix(server): skip exif extraction on duplicate file (#590)

* fix(server): skip exif extraction on duplicate file

* fix(server): typo

* chore(server): remvoe un-use code
This commit is contained in:
Thanh Pham 2022-09-06 08:02:50 +07:00 committed by GitHub
parent a467936e73
commit 7f6837c751
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 29 deletions

View file

@ -47,6 +47,7 @@ import { GetAssetThumbnailDto } from './dto/get-asset-thumbnail.dto';
import { AssetCountByTimeBucketResponseDto } from './response-dto/asset-count-by-time-group-response.dto'; import { AssetCountByTimeBucketResponseDto } from './response-dto/asset-count-by-time-group-response.dto';
import { GetAssetCountByTimeBucketDto } from './dto/get-asset-count-by-time-bucket.dto'; import { GetAssetCountByTimeBucketDto } from './dto/get-asset-count-by-time-bucket.dto';
import { GetAssetByTimeBucketDto } from './dto/get-asset-by-time-bucket.dto'; import { GetAssetByTimeBucketDto } from './dto/get-asset-by-time-bucket.dto';
import { QueryFailedError } from 'typeorm';
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@ -74,8 +75,11 @@ export class AssetController {
@UploadedFile() file: Express.Multer.File, @UploadedFile() file: Express.Multer.File,
@Body(ValidationPipe) assetInfo: CreateAssetDto, @Body(ValidationPipe) assetInfo: CreateAssetDto,
): Promise<AssetFileUploadResponseDto> { ): Promise<AssetFileUploadResponseDto> {
const checksum = await this.assetService.calculateChecksum(file.path);
try { try {
const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype); const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype, checksum);
if (!savedAsset) { if (!savedAsset) {
await this.backgroundTaskService.deleteFileOnDisk([ await this.backgroundTaskService.deleteFileOnDisk([
{ {
@ -92,14 +96,20 @@ export class AssetController {
); );
return new AssetFileUploadResponseDto(savedAsset.id); return new AssetFileUploadResponseDto(savedAsset.id);
} catch (e) { } catch (err) {
Logger.error(`Error uploading file ${e}`);
await this.backgroundTaskService.deleteFileOnDisk([ await this.backgroundTaskService.deleteFileOnDisk([
{ {
originalPath: file.path, originalPath: file.path,
} as any, } as any,
]); // simulate asset to make use of delete queue (or use fs.unlink instead) ]); // simulate asset to make use of delete queue (or use fs.unlink instead)
throw new BadRequestException(`Error uploading file`, `${e}`);
if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
const existedAsset = await this.assetService.getAssetByChecksum(authUser.id, checksum)
return new AssetFileUploadResponseDto(existedAsset.id);
}
Logger.error(`Error uploading file ${err}`);
throw new BadRequestException(`Error uploading file`, `${err}`);
} }
} }

View file

@ -10,7 +10,7 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { createHash } from 'node:crypto'; import { createHash } from 'node:crypto';
import { QueryFailedError, Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { AuthUserDto } from '../../decorators/auth-user.decorator'; import { AuthUserDto } from '../../decorators/auth-user.decorator';
import { AssetEntity, AssetType } from '@app/database/entities/asset.entity'; import { AssetEntity, AssetType } from '@app/database/entities/asset.entity';
import { constants, createReadStream, ReadStream, stat } from 'fs'; import { constants, createReadStream, ReadStream, stat } from 'fs';
@ -53,10 +53,8 @@ export class AssetService {
createAssetDto: CreateAssetDto, createAssetDto: CreateAssetDto,
originalPath: string, originalPath: string,
mimeType: string, mimeType: string,
checksum: Buffer,
): Promise<AssetEntity> { ): Promise<AssetEntity> {
const checksum = await this.calculateChecksum(originalPath);
try {
const assetEntity = await this._assetRepository.create( const assetEntity = await this._assetRepository.create(
createAssetDto, createAssetDto,
authUser.id, authUser.id,
@ -66,18 +64,6 @@ export class AssetService {
); );
return assetEntity; return assetEntity;
} catch (err) {
if (err instanceof QueryFailedError && (err as any).constraint === 'UQ_userid_checksum') {
const [assetEntity, _] = await Promise.all([
this._assetRepository.getAssetByChecksum(authUser.id, checksum),
fs.unlink(originalPath)
]);
return assetEntity;
}
throw err;
}
} }
public async getUserAssetsByDeviceId(authUser: AuthUserDto, deviceId: string) { public async getUserAssetsByDeviceId(authUser: AuthUserDto, deviceId: string) {
@ -478,7 +464,11 @@ export class AssetService {
return mapAssetCountByTimeBucket(result); return mapAssetCountByTimeBucket(result);
} }
private calculateChecksum(filePath: string): Promise<Buffer> { getAssetByChecksum(userId: string, checksum: Buffer) {
return this._assetRepository.getAssetByChecksum(userId, checksum);
}
calculateChecksum(filePath: string): Promise<Buffer> {
const fileReadStream = createReadStream(filePath); const fileReadStream = createReadStream(filePath);
const sha1Hash = createHash('sha1'); const sha1Hash = createHash('sha1');
const deferred = new Promise<Buffer>((resolve, reject) => { const deferred = new Promise<Buffer>((resolve, reject) => {