108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
//FIXME: after refactor, move to the correct path
|
|
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { createHash } from 'node:crypto';
|
|
import { txEnv } from '../../globalData';
|
|
|
|
//Hash test
|
|
const hashFile = async (filePath: string) => {
|
|
const rawFile = await fs.readFile(filePath, 'utf8')
|
|
const normalized = rawFile.normalize('NFKC')
|
|
.replace(/\r\n/g, '\n')
|
|
.replace(/^\uFEFF/, '');
|
|
return createHash('sha1').update(normalized).digest('hex');
|
|
}
|
|
|
|
// Limits
|
|
const MAX_FILES = 300;
|
|
const MAX_TOTAL_SIZE = 52_428_800; // 50MB
|
|
const MAX_FILE_SIZE = 20_971_520; // 20MB
|
|
const MAX_DEPTH = 10;
|
|
const MAX_EXECUTION_TIME = 30 * 1000;
|
|
const IGNORED_FOLDERS = [
|
|
'db',
|
|
'cache',
|
|
'dist',
|
|
'.reports',
|
|
'license_report',
|
|
'tmp_core_tsc',
|
|
'node_modules',
|
|
'txData',
|
|
];
|
|
|
|
|
|
type ContentFileType = {
|
|
path: string;
|
|
size: number;
|
|
hash: string;
|
|
}
|
|
|
|
export default async function scanMonitorFiles() {
|
|
const rootPath = txEnv.txaPath;
|
|
const allFiles: ContentFileType[] = [];
|
|
let totalFiles = 0;
|
|
let totalSize = 0;
|
|
|
|
try {
|
|
const tsStart = Date.now();
|
|
const scanDir = async (dir: string, depth: number = 0) => {
|
|
if (depth > MAX_DEPTH) {
|
|
throw new Error('MAX_DEPTH');
|
|
}
|
|
|
|
let filesFound = 0;
|
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
if (totalFiles >= MAX_FILES) {
|
|
throw new Error('MAX_FILES');
|
|
} else if (totalSize >= MAX_TOTAL_SIZE) {
|
|
throw new Error('MAX_TOTAL_SIZE');
|
|
} else if (Date.now() - tsStart > MAX_EXECUTION_TIME) {
|
|
throw new Error('MAX_EXECUTION_TIME');
|
|
}
|
|
|
|
const entryPath = path.join(dir, entry.name);
|
|
let relativeEntryPath = path.relative(rootPath, entryPath);
|
|
relativeEntryPath = './' + relativeEntryPath.split(path.sep).join(path.posix.sep);
|
|
|
|
if (entry.isDirectory()) {
|
|
if (IGNORED_FOLDERS.includes(entry.name)) {
|
|
continue;
|
|
}
|
|
await scanDir(entryPath, depth + 1);
|
|
} else if (entry.isFile()) {
|
|
const stats = await fs.stat(entryPath);
|
|
if (stats.size > MAX_FILE_SIZE) {
|
|
throw new Error('MAX_SIZE');
|
|
}
|
|
|
|
allFiles.push({
|
|
path: relativeEntryPath,
|
|
size: stats.size,
|
|
hash: await hashFile(entryPath),
|
|
});
|
|
filesFound++;
|
|
totalFiles++;
|
|
totalSize += stats.size;
|
|
}
|
|
}
|
|
return filesFound;
|
|
};
|
|
await scanDir(rootPath);
|
|
allFiles.sort((a, b) => a.path.localeCompare(b.path));
|
|
return {
|
|
totalFiles,
|
|
totalSize,
|
|
allFiles,
|
|
};
|
|
} catch (error) {
|
|
//At least saving the progress
|
|
return {
|
|
error: (error as any).message,
|
|
totalFiles,
|
|
totalSize,
|
|
allFiles,
|
|
};
|
|
}
|
|
}
|