igir
Version:
🕹 A zero-setup ROM collection manager that sorts, filters, extracts or archives, patches, and reports on collections of any size on any OS.
90 lines • 4.98 kB
JavaScript
import { ProgressBarSymbol } from '../../console/progressBar.js';
import DriveSemaphore from '../../driveSemaphore.js';
import ArchiveFile from '../../types/files/archives/archiveFile.js';
import Module from '../module.js';
/**
* Calculate checksums for {@link ArchiveFile}s (which were skipped in {@link CandidateGenerator}).
* This deferral is done to prevent calculating checksums for files that are filtered out by a
* candidate filtering module.
*/
class CandidateArchiveFileHasher extends Module {
constructor(options, progressBar, fileFactory) {
super(progressBar, CandidateArchiveFileHasher.name);
this.options = options;
this.fileFactory = fileFactory;
// This will be the same value globally, but we can't know the value at file import time
if (options.getReaderThreads() < CandidateArchiveFileHasher.DRIVE_SEMAPHORE.getValue()) {
CandidateArchiveFileHasher.DRIVE_SEMAPHORE.setValue(options.getReaderThreads());
}
}
/**
* Hash the {@link ArchiveFile}s.
*/
async hash(dat, candidates) {
if (candidates.length === 0) {
this.progressBar.logTrace(`${dat.getName()}: no candidates to hash ArchiveFiles for`);
return candidates;
}
if (!this.options.shouldTest() && !this.options.getOverwriteInvalid()) {
this.progressBar.logTrace(`${dat.getName()}: not testing or overwriting invalid files, no need`);
return candidates;
}
const archiveFileCount = candidates
.flatMap((candidate) => candidate.getRomsWithFiles())
.filter((romWithFiles) => romWithFiles.getInputFile() instanceof ArchiveFile).length;
if (archiveFileCount === 0) {
this.progressBar.logTrace(`${dat.getName()}: no ArchiveFiles to hash`);
return candidates;
}
this.progressBar.logTrace(`${dat.getName()}: generating ${archiveFileCount.toLocaleString()} hashed ArchiveFile candidate${archiveFileCount === 1 ? '' : 's'}`);
this.progressBar.setSymbol(ProgressBarSymbol.CANDIDATE_HASHING);
this.progressBar.reset(archiveFileCount);
const hashedCandidates = this.hashArchiveFiles(dat, candidates);
this.progressBar.logTrace(`${dat.getName()}: done generating hashed ArchiveFile candidates`);
return hashedCandidates;
}
async hashArchiveFiles(dat, candidates) {
return Promise.all(candidates.map(async (candidate) => {
const hashedRomsWithFiles = await Promise.all(candidate.getRomsWithFiles().map(async (romWithFiles) => {
const inputFile = romWithFiles.getInputFile();
if (!(inputFile instanceof ArchiveFile)) {
return romWithFiles;
}
const outputFile = romWithFiles.getOutputFile();
if (inputFile.equals(outputFile)) {
/**
* There's no need to calculate the checksum, {@link CandidateWriter} will skip
* writing over itself
*/
return romWithFiles;
}
return CandidateArchiveFileHasher.DRIVE_SEMAPHORE.runExclusive(inputFile, async () => {
this.progressBar.incrementProgress();
const waitingMessage = `${inputFile.toString()} ...`;
this.progressBar.addWaitingMessage(waitingMessage);
this.progressBar.logTrace(`${dat.getName()}: ${candidate.getName()}: calculating checksums for: ${inputFile.toString()}`);
const hashedInputFile = await this.fileFactory.archiveFileFrom(inputFile.getArchive(), inputFile.getChecksumBitmask());
// {@link CandidateGenerator} would have copied undefined values from the input
// file, so we need to modify the expected output file as well for testing
const hashedOutputFile = outputFile.withProps({
size: hashedInputFile.getSize(),
crc32: hashedInputFile.getCrc32(),
md5: hashedInputFile.getMd5(),
sha1: hashedInputFile.getSha1(),
sha256: hashedInputFile.getSha256(),
});
const hashedRomWithFiles = romWithFiles
.withInputFile(hashedInputFile)
.withOutputFile(hashedOutputFile);
this.progressBar.removeWaitingMessage(waitingMessage);
this.progressBar.incrementDone();
return hashedRomWithFiles;
});
}));
return candidate.withRomsWithFiles(hashedRomsWithFiles);
}));
}
}
CandidateArchiveFileHasher.DRIVE_SEMAPHORE = new DriveSemaphore(Number.MAX_SAFE_INTEGER);
export default CandidateArchiveFileHasher;
//# sourceMappingURL=candidateArchiveFileHasher.js.map