1 line
31 KiB
Plaintext
1 line
31 KiB
Plaintext
{"version":3,"sources":["../src/lib/file-id/FileIDComputerWorker.ts","../src/lib/hash-compute/HashComputerWorker.ts","../src/lib/hash-compute/HashIndexManager.ts","../src/lib/utils/ExistsAsync.ts","../src/lib/hash-compute/HashComputerIndexCache.ts","../src/lib/folder-watcher/FolderWatcher.ts"],"names":["stat","path","dirname"],"mappings":"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","sourcesContent":["import {Piscina} from \"piscina\";\nimport {CID_ALGORITHM_NAMES} from \"../hash-compute/MultiHashData\";\nimport {FileIDComputerInterface} from \"@root/file-id/FileIDComputerInterface\";\n\n// Construct the URL for the current module\nlet distFolder = import.meta.dirname;\ndistFolder = distFolder.replace('src', 'dist');\ndistFolder = distFolder + \"/worker.js\";\nconst workerUrl = new URL(distFolder).href;\nconsole.log(\"Worker URL: \", workerUrl);\n\nexport class FileIDComputerWorker{\n private piscina: Piscina;\n\n constructor(workerPath?:string) {\n this.piscina = new Piscina({\n maxThreads: 4,\n //filename: new URL('./ShaComputeWorker.ts', import.meta.url).href\n filename: workerPath || process.env.WORKER_URL || workerUrl\n });\n }\n\n /**\n * Compute the CIDs of a file using specific algorithms\n * @param filePath The path to the file\n * @param algorithms Array of algorithms ('sha256', 'sha1')\n * @returns Array of CIDs (in the order of the algorithms)\n */\n public async computeCIDs(filePath: string, algorithms: CID_ALGORITHM_NAMES[]): Promise<string[]> {\n return this.piscina.run({filePath, algorithms});\n }\n}\n","import {FileIDComputerWorker} from \"../file-id/FileIDComputerWorker\";\nimport {CID_ALGORITHM_NAMES, ComputeInterface, MultiHashData} from \"./MultiHashData\";\n\nexport class HashComputerWorker implements ComputeInterface {\n private fileIDComputer: FileIDComputerWorker;\n\n constructor(private targetHash: CID_ALGORITHM_NAMES[], workerPath?: string) {\n this.fileIDComputer = new FileIDComputerWorker(workerPath);\n }\n\n async computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void> {\n // Dynamically determine which hashes are needed\n const neededHashes = this.targetHash.filter(hashName => !metadata[hashName]);\n\n // If all hashes are already computed, skip the processing\n if (neededHashes.length === 0) {\n return;\n }\n\n // Compute only the needed CIDs\n const cids = await this.fileIDComputer.computeCIDs(filePath, neededHashes);\n\n // Map the computed CIDs back to their respective metadata properties\n for (const [index, cid] of cids.entries()) {\n const hashType = neededHashes[index];\n metadata[hashType] = cid;\n }\n }\n}\n","import {createReadStream, promises as fs} from 'fs';\nimport {parse} from 'csv-parse';\nimport {parse as parseSync} from 'csv-parse/sync';\nimport {stringify} from 'csv-stringify/sync';\nimport {existsAsync} from \"../utils/ExistsAsync\";\nimport path from \"path\";\nimport {clearInterval} from \"node:timers\";\nimport {CID_ALGORITHM_NAMES} from \"./MultiHashData\";\nimport {stat} from \"fs/promises\";\n\ninterface IndexLine extends Partial<Record<CID_ALGORITHM_NAMES, string>> {\n path: string;\n size: string;\n mtime: string;\n}\n\nexport const INDEX_HEADERS = ['path', 'size', 'mtime'];\n\nexport class HashIndexManager {\n private cache: Map<string, IndexLine> = new Map<string, IndexLine>();\n private intervalId: NodeJS.Timeout;\n private intervalTime: number = 30000;\n private lastIndexFileSize: number = 0; //size of the index file last time it was read\n private lastCacheFile: IndexLine[]; //state of the file last time it was read\n private indexOpsInProgress: boolean = false;\n private hasChanged: boolean = false;\n private initialLoad: Promise<void>;\n private filePaths: { [key in CID_ALGORITHM_NAMES]?: string } = {};\n\n constructor(filePath: string, private targetHash: CID_ALGORITHM_NAMES[] = [CID_ALGORITHM_NAMES.sha1, CID_ALGORITHM_NAMES.sha256]) {\n filePath = filePath.replace(\".csv\", \"\");\n for (const hash of this.targetHash) {\n this.filePaths[hash] = `${filePath}-${hash}.csv`;\n if (!this.filePaths[hash]) {\n throw new Error(`Invalid index file path for ${hash}`);\n }\n }\n }\n\n public getCache(): Map<string, IndexLine> {\n return new Map(this.cache);\n }\n\n /**\n * After init consseutively calls to this method will not reload the index\n * @param autosave\n */\n public async init(autosave = true) {\n if (!this.initialLoad) {\n this.initialLoad = new Promise<void>(async (resolve, reject) => {\n try {\n for (const hash of this.targetHash) {\n if (!this.checkCSVHeaders(this.filePaths[hash], hash)) {\n throw new Error(`Invalid index file headers for ${hash}`);\n }\n await this.loadIndex(hash);\n }\n if (autosave) {\n this.start();\n }\n resolve();\n } catch (e) {\n reject(e);\n }\n });\n }\n return this.initialLoad;\n }\n\n // Function to check CSV headers\n private checkCSVHeaders(csvContent: string, hash: CID_ALGORITHM_NAMES): boolean {\n const records = parseSync(csvContent, {\n bom: true,\n columns: true,\n skip_empty_lines: true,\n });\n\n if (records.length === 0) {\n //we will write the headers\n return true;\n }\n\n // Extract headers\n const headers = Object.keys(records[0]);\n\n // Define required headers\n //from the IndexLine interface\n const requiredHeaders = [...INDEX_HEADERS, hash];\n\n // Check if all required headers are present\n return requiredHeaders.every(header => headers.includes(header));\n };\n\n public start() {\n this.startAutoSave(this.intervalTime);\n }\n\n public stopAutoSave() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n private startAutoSave(time: number) {\n this.stopAutoSave();\n this.intervalTime = time;\n this.intervalId = setInterval(() => this.saveCacheToFile(), time);\n }\n\n public async loadIndex(hash: CID_ALGORITHM_NAMES): Promise<IndexLine[]> {\n if (await existsAsync(this.filePaths[hash])) {\n // check the file size and if it did not change, do not read the file\n const stats = await fs.stat(this.filePaths[hash]);\n if (this.lastIndexFileSize !== stats.size) {\n // Read existing file content and parse it\n const records: IndexLine[] = await this.readCsv(hash);\n for (const record of records) {\n let indexLine = this.cache.get(record.path);\n if (!indexLine) {\n this.cache.set(record.path, record);\n } else {\n //update the cache with the latest data\n indexLine[hash] = record[hash];\n }\n }\n this.lastIndexFileSize = stats.size;\n this.lastCacheFile = records;\n return records;\n } else {\n return this.lastCacheFile;\n }\n }\n return [];\n }\n\n private loadIndexFromCache(): IndexLine[] {\n return Array.from(this.cache.values());\n }\n\n private async readCsv(hash: CID_ALGORITHM_NAMES): Promise<IndexLine[]> {\n if (!(await existsAsync(this.filePaths[hash]))) {\n return [];\n }\n const start = performance.now();\n\n const parser = parse({\n columns: true,\n skip_empty_lines: true,\n });\n\n const records: IndexLine[] = [];\n\n return new Promise((resolve, reject) => {\n createReadStream(this.filePaths[hash])\n .pipe(parser)\n .on('data', (record) => {\n records.push(record);\n }).on('end', () => {\n resolve(records);\n console.log(`Index read ${hash} time ${performance.now() - start}ms`);\n }).on('error', (err) => {\n reject(err);\n });\n });\n }\n\n public async saveCacheToFile(): Promise<void> {\n if (this.indexOpsInProgress || !this.hasChanged) {\n return;\n }\n this.hasChanged = false;\n this.indexOpsInProgress = true;\n const start = performance.now();\n\n let cacheRows: IndexLine[];\n if (this.cache.size !== 0) {\n cacheRows = this.loadIndexFromCache();\n }\n\n for (const hash of this.targetHash) {\n let existingRows: IndexLine[] = await this.loadIndex(hash);\n let existingRowsAsMap: Map<string, IndexLine> = new Map(existingRows.map(row => [row.path, row]));\n if (this.cache.size !== 0) {\n // Filter out cacheRows that are already in the file\n const newRows = cacheRows.filter(row => {\n //to be added a row must not exist in the file and must exist in the cache (with a hash)\n const newRow = !existingRowsAsMap.has(row.path);\n return newRow && !!row[hash];\n });\n\n if (newRows.length !== 0) {\n // Serialize new cacheRows to CSV string\n const csvString = stringify(newRows, {\n header: existingRows.length === 0, // Only add header if the file was empty\n columns: [\n {key: 'path', header: 'path'},\n {key: 'size', header: 'size'},\n {key: 'mtime', header: 'mtime'},\n {key: hash, header: hash},\n ],\n });\n\n // Append new cacheRows to the file\n await fs.appendFile(this.filePaths[hash], csvString);\n }\n }\n }\n\n const totalTime = performance.now() - start;\n console.log(`Index saved in ${totalTime}ms`);\n // Check if the time to save the index is greater than the interval time. increase the interval time if needed\n if (totalTime * 10 > this.intervalTime) {\n this.startAutoSave(totalTime * 10);\n console.log(`Index save interval increased to ${totalTime * 10}ms`);\n }\n this.indexOpsInProgress = false;\n }\n\n public async getCidForFileAsync(filePath: string): Promise<IndexLine> {\n const fileName = path.basename(filePath);\n const stats = await stat(filePath);\n return this.getCidForFile(fileName, stats.size, stats.mtime.toISOString());\n }\n\n public getCidForFile(filePath: string, fileSize: number, mtime: string): IndexLine {\n const fileName = path.basename(filePath);\n let fileNameIndex = this.cache.get(fileName);\n for (const hash of this.targetHash) {\n if (!fileNameIndex[hash]) {\n delete fileNameIndex[hash];\n }\n }\n if (fileNameIndex) {\n if (fileNameIndex.mtime) {\n //if we have a mtime, we need to check it\n if (fileNameIndex.size === (fileSize + \"\") && fileNameIndex.mtime === mtime) {\n return fileNameIndex;\n }\n } else {\n //mtime is optional\n if (fileNameIndex.size === (fileSize + \"\")) {\n return fileNameIndex;\n }\n }\n }\n\n // 3 - if not found, delete the entry (keeps the index clean)\n /*if (fileNameIndex && fileNameIndex.size !== (fileSize + \"\") && pathIndex && pathIndex.size !== (fileSize + \"\")) {\n this.cache.delete(fileName);\n this.cache.delete(filePath);\n }*/\n\n return null;\n }\n\n public addFileCid(filePath: string, fileSize: number, mtime: string, hashs: Partial<Record<CID_ALGORITHM_NAMES, string>>): void {\n if (!filePath || !fileSize || !mtime || !hashs) {\n throw new Error('Invalid parameters');\n }\n for (const hash of this.targetHash) {\n if (!hashs[hash]) {\n throw new Error(`Missing hash ${hash}`);\n }\n }\n const size = fileSize + \"\";\n const baseName = path.basename(filePath);\n let indexLine = this.cache.get(baseName);\n if (!indexLine) {\n //filter only the hashes we need\n let filteredHash = {};\n for (const hash of this.targetHash) {\n filteredHash[hash] = hashs[hash];\n }\n const data = {path: baseName, size: size, mtime: mtime, ...filteredHash};\n this.cache.set(baseName, data);\n } else {\n //update the cache with the latest data\n for (const hash of this.targetHash) {\n indexLine[hash] = hashs[hash];\n }\n }\n this.hasChanged = true;\n }\n\n}","// Example of checking if a file exists asynchronously\n// Note: `existsSync` does not have a direct async equivalent, so we use `access` instead.\nimport {access,constants} from \"fs/promises\";\n\nexport async function existsAsync(filePath: string): Promise<boolean> {\n try {\n await access(filePath, constants.F_OK);\n return true; // File exists\n } catch {\n return false; // File does not exist\n }\n}","import {HashComputerWorker} from \"./HashComputerWorker\";\nimport {CID_ALGORITHM_NAMES, ComputeInterface, MultiHashData} from \"./MultiHashData\";\nimport {HashIndexManager} from \"./HashIndexManager\";\nimport {stat} from \"fs/promises\";\nimport path from \"path\";\n\nexport class HashComputerIndexCache implements ComputeInterface {\n private hashIndexManager: HashIndexManager;\n private hashComputer: HashComputerWorker;\n\n constructor(indexFilePath: string,private targetHash: CID_ALGORITHM_NAMES[] = [CID_ALGORITHM_NAMES.sha1, CID_ALGORITHM_NAMES.sha256],workerPath?:string) {\n this.hashComputer = new HashComputerWorker(targetHash,workerPath);\n this.hashIndexManager = new HashIndexManager(indexFilePath,targetHash);\n }\n\n public async computeMissingHash(filePath: string, metadata: MultiHashData): Promise<void> {\n await this.hashIndexManager.init();\n let stats = await stat(filePath);\n if (this.hashIndexManager.getCache().has(path.basename(filePath))) {\n const indexLine = this.hashIndexManager.getCidForFile(filePath, stats.size, stats.mtime.toISOString());\n if(indexLine) {\n for (const hash of this.targetHash) {\n if (!metadata[hash] && indexLine[hash]) {\n metadata[hash] = indexLine[hash];\n }\n }\n }\n }\n await this.hashComputer.computeMissingHash(filePath, metadata);\n this.hashIndexManager.addFileCid(filePath, stats.size, stats.mtime.toISOString(), metadata);\n }\n\n async getHashIndexManager(): Promise<HashIndexManager> {\n await this.hashIndexManager.init();\n return this.hashIndexManager;\n }\n}","import * as path from 'path';\nimport chokidar from 'chokidar';\nimport {readdir} from \"fs/promises\";\nimport PQueue from \"p-queue\";\nimport {FileProcessorInterface} from \"./FileProcessorInterface.js\";\n\nexport class FolderWatcher {\n initialized = false;\n queue = new PQueue({concurrency: 100, autoStart: true});\n fileProcessor: FileProcessorInterface;\n queueSize = -1;\n current = 0;\n processing = new Set<string>();\n\n constructor(fileProcessor:FileProcessorInterface,private WATCH_FOLDER_LIST: string, private config:{\n interval?: number,\n stabilityThreshold?: number,\n pollInterval?: number,\n }) {\n this.fileProcessor = fileProcessor;\n }\n\n /**\n * Process the directory and its subdirectories\n * @param directory\n * @param promises\n * @private\n */\n private async processDirectory(directory: string, promises: Promise<any>[]) {\n const entries = await readdir(directory, {withFileTypes: true});\n for (const entry of entries) {\n const fullPath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n await this.processDirectory(fullPath, promises);\n } else {\n const promise = this.processFile(fullPath);\n promises.push(promise);\n }\n }\n }\n\n private async countFile(directory: string): Promise<number> {\n const entries = await readdir(directory, {withFileTypes: true});\n const countPromises: Promise<any>[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n // Push the promise without waiting for it here\n countPromises.push(this.countFile(fullPath));\n } else {\n // Use an IIFE (Immediately Invoked Function Expression) to handle asynchronous condition\n countPromises.push(this.queue.add(\n async () => (await this.fileProcessor.canProcessFile(fullPath)) ? 1 : 0\n ));\n }\n }\n\n // Wait for all promises to resolve and then sum up their results\n const counts = await Promise.all(countPromises);\n return counts.reduce((acc, current) => acc + current, 0);\n }\n\n private async processFile(filePath: string):Promise<void> {\n if(await this.fileProcessor.canProcessFile(filePath)) {\n if(!this.processing.has(filePath)) {\n this.processing.add(filePath);//avoid double processing in the queue\n const current = ++this.current;\n await this.queue.add(() => this.fileProcessor.processFile(current, this.queueSize, filePath));\n this.processing.delete(filePath);\n }\n }\n }\n\n /**\n * Process the file and its sibling file included other folder it is a recursive function\n * @param filePath\n * @private\n */\n private async processFileExtended(filePath: string):Promise<void> {\n let dirname = path.dirname(filePath);\n await this.processDirectory(dirname, []);\n }\n\n private chokidarWatch(folderList: string[]){\n const chokidarconfig = {\n ignoreInitial: true,//ignore the initial scan we have our own function\n persistent: true,\n depth: Infinity,\n awaitWriteFinish: {\n stabilityThreshold: this.config.stabilityThreshold || 30000,\n pollInterval: this.config.pollInterval || 5000\n }\n };\n\n let watcher: chokidar.FSWatcher;\n if ((this.config.interval || 0) <= 0) {\n watcher = chokidar.watch(folderList, chokidarconfig);\n } else {\n watcher = chokidar.watch(folderList, {\n ...chokidarconfig,\n usePolling: true,\n interval: this.config.interval || 0\n });\n }\n\n watcher\n .on('add', async (filePath) => {\n try {\n await this.processFileExtended(filePath);\n } catch (error) {\n console.error(`Error processing file ${filePath}:`, error);\n }\n })\n .on('change', async (filePath) => {\n try {\n await this.processFileExtended(filePath);\n } catch (e) {\n console.error(`Error processing file ${filePath}:`, e);\n }\n })\n .on('unlink', async (filePath) => {\n try {\n await this.fileProcessor.deleteFile(filePath);\n await this.processFileExtended(filePath);\n } catch (e) {\n console.error(`Error processing file deletion:`, e);\n }\n })\n .on('error', (error) => console.error(`Watcher error: ${error}`))\n .on('ready', () => {\n console.log(`Watching for file changes on ${folderList}`);\n });\n }\n\n async watch() {\n let folders = this.WATCH_FOLDER_LIST;\n if (!folders) {\n throw new Error(`No folder to watch`);\n }\n let folderList = folders.split(',');\n\n this.chokidarWatch(folderList);\n\n //start the initial scan\n let countPromises = [];\n for (let i = 0; i < folderList.length; i++) {\n folderList[i] = path.normalize(folderList[i]);\n countPromises.push(this.countFile(folderList[i]));\n }\n const count = (await Promise.all(countPromises)).reduce((acc, current) => acc + current, 0);\n console.log(`Found ${count} files to process`);\n this.queueSize = count;\n let promises: Promise<any>[] = [];\n for (let i = 0; i < folderList.length; i++) {\n folderList[i] = path.normalize(folderList[i]);\n await this.processDirectory(folderList[i], promises);\n }\n await Promise.all(promises);\n this.initialized = true;\n\n console.log(`Watcher ready`);\n }\n}\n"]} |