fix(server): Server freezes when getting statistic (#994)

* fix(server): Server freezes when getting statistic
* remove dead code
This commit is contained in:
Alex 2022-11-20 13:09:31 -06:00 committed by GitHub
parent b3e51cc849
commit 41ffa0c015
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 187 additions and 259 deletions

View file

@ -5,7 +5,6 @@ export class ServerStatsResponseDto {
constructor() {
this.photos = 0;
this.videos = 0;
this.objects = 0;
this.usageByUser = [];
this.usageRaw = 0;
this.usage = '';
@ -34,7 +33,6 @@ export class ServerStatsResponseDto {
{
photos: 1,
videos: 1,
objects: 1,
diskUsageRaw: 1,
},
],

View file

@ -3,16 +3,15 @@ import { ApiProperty } from '@nestjs/swagger';
export class UsageByUserDto {
constructor(userId: string) {
this.userId = userId;
this.objects = 0;
this.videos = 0;
this.photos = 0;
this.usageRaw = 0;
this.usage = '0B';
}
@ApiProperty({ type: 'string' })
userId: string;
@ApiProperty({ type: 'integer' })
objects: number;
@ApiProperty({ type: 'integer' })
videos: number;
@ApiProperty({ type: 'integer' })
photos: number;

View file

@ -7,8 +7,6 @@ import { UsageByUserDto } from './response-dto/usage-by-user-response.dto';
import { AssetEntity } from '@app/database/entities/asset.entity';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import path from 'path';
import { readdirSync, statSync } from 'fs';
import { asHumanReadable } from '../../utils/human-readable.util';
@Injectable()
@ -35,59 +33,46 @@ export class ServerInfoService {
}
async getStats(): Promise<ServerStatsResponseDto> {
const res = await this.assetRepository
.createQueryBuilder('asset')
.select(`COUNT(asset.id)`, 'count')
.addSelect(`asset.type`, 'type')
.addSelect(`asset.userId`, 'userId')
.groupBy('asset.type, asset.userId')
.addGroupBy('asset.type')
const serverStats = new ServerStatsResponseDto();
type UserStatsQueryResponse = {
assetType: string;
assetCount: string;
totalSizeInBytes: string;
userId: string;
};
const userStatsQueryResponse: UserStatsQueryResponse[] = await this.assetRepository
.createQueryBuilder('a')
.select('COUNT(a.id)', 'assetCount')
.addSelect('SUM(ei.fileSizeInByte)', 'totalSizeInBytes')
.addSelect('a."userId"')
.addSelect('a.type', 'assetType')
.where('a.isVisible = true')
.leftJoin('a.exifInfo', 'ei')
.groupBy('a."userId"')
.addGroupBy('a.type')
.getRawMany();
const serverStats = new ServerStatsResponseDto();
const tmpMap = new Map<string, UsageByUserDto>();
const getUsageByUser = (id: string) => tmpMap.get(id) || new UsageByUserDto(id);
res.map((item) => {
const usage: UsageByUserDto = getUsageByUser(item.userId);
if (item.type === 'IMAGE') {
usage.photos = parseInt(item.count);
serverStats.photos += usage.photos;
} else if (item.type === 'VIDEO') {
usage.videos = parseInt(item.count);
serverStats.videos += usage.videos;
}
tmpMap.set(item.userId, usage);
userStatsQueryResponse.forEach((r) => {
const usageByUser = getUsageByUser(r.userId);
usageByUser.photos += r.assetType === 'IMAGE' ? parseInt(r.assetCount) : 0;
usageByUser.videos += r.assetType === 'VIDEO' ? parseInt(r.assetCount) : 0;
usageByUser.usageRaw += parseInt(r.totalSizeInBytes);
usageByUser.usage = asHumanReadable(usageByUser.usageRaw);
serverStats.photos += r.assetType === 'IMAGE' ? parseInt(r.assetCount) : 0;
serverStats.videos += r.assetType === 'VIDEO' ? parseInt(r.assetCount) : 0;
serverStats.usageRaw += parseInt(r.totalSizeInBytes);
serverStats.usage = asHumanReadable(serverStats.usageRaw);
tmpMap.set(r.userId, usageByUser);
});
for (const userId of tmpMap.keys()) {
const usage = getUsageByUser(userId);
const userDiskUsage = await ServerInfoService.getDirectoryStats(path.join(APP_UPLOAD_LOCATION, userId));
usage.usageRaw = userDiskUsage.size;
usage.objects = userDiskUsage.fileCount;
usage.usage = asHumanReadable(usage.usageRaw);
serverStats.usageRaw += usage.usageRaw;
serverStats.objects += usage.objects;
}
serverStats.usage = asHumanReadable(serverStats.usageRaw);
serverStats.usageByUser = Array.from(tmpMap.values());
return serverStats;
}
private static async getDirectoryStats(dirPath: string) {
let size = 0;
let fileCount = 0;
for (const filename of readdirSync(dirPath)) {
const absFilename = path.join(dirPath, filename);
const fileStat = statSync(absFilename);
if (fileStat.isFile()) {
size += fileStat.size;
fileCount += 1;
} else if (fileStat.isDirectory()) {
const subDirStat = await ServerInfoService.getDirectoryStats(absFilename);
size += subDirStat.size;
fileCount += subDirStat.fileCount;
}
}
return { size, fileCount };
}
}