Skip to content

Commit

Permalink
Refactor: eliminate some File & ArchiveEntry promises (#612)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmercm authored Aug 25, 2023
1 parent 3668793 commit 5072263
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 144 deletions.
2 changes: 1 addition & 1 deletion src/modules/candidateCombiner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default class CandidateCombiner extends Module {
}

// Combine all output ArchiveEntry to a single archive of the DAT name
let outputEntry = await outputFile.withFilePath(dat.getNameShort());
let outputEntry = outputFile.withFilePath(dat.getNameShort());

// If the game has multiple ROMs, then group them in a folder in the archive
if (releaseCandidate.getGame().getRoms().length > 1) {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/candidatePatchGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export default class CandidatePatchGenerator extends Module {
// Apply the patch to the appropriate file
if (patch.getCrcBefore() === romWithFiles.getRom().getCrc32()) {
// Attach the patch to the input file
inputFile = await inputFile.withPatch(patch);
inputFile = inputFile.withPatch(patch);

// Build a new output file
const extMatch = romWithFiles.getRom().getName().match(/[^.]+((\.[a-zA-Z0-9]+)+)$/);
Expand Down
77 changes: 36 additions & 41 deletions src/modules/candidatePostProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default class CandidatePostProcessor extends Module {
await this.progressBar.setSymbol(ProgressBarSymbol.GENERATING);
await this.progressBar.reset(parentsToCandidates.size);

// Get the output basename of every ROM
const outputFileBasenames = [...parentsToCandidates.values()]
.flatMap((releaseCandidates) => releaseCandidates)
.flatMap((releaseCandidate) => releaseCandidate.getRomsWithFiles()
Expand All @@ -50,30 +51,27 @@ export default class CandidatePostProcessor extends Module {
return outputPathParsed.name + outputPathParsed.ext;
}));

const processedCandidates = new Map(await Promise.all(
[...parentsToCandidates.entries()]
.map(async ([parent, releaseCandidates]): Promise<[Parent, ReleaseCandidate[]]> => {
const newReleaseCandidates = await Promise.all(
releaseCandidates.map(async (releaseCandidate) => this.mapReleaseCandidate(
dat,
releaseCandidate,
outputFileBasenames,
)),
);
return [parent, newReleaseCandidates];
}),
));
const processedCandidates = new Map([...parentsToCandidates.entries()]
.map(([parent, releaseCandidates]): [Parent, ReleaseCandidate[]] => {
const newReleaseCandidates = releaseCandidates
.map((releaseCandidate) => this.mapReleaseCandidate(
dat,
releaseCandidate,
outputFileBasenames,
));
return [parent, newReleaseCandidates];
}));

this.progressBar.logInfo(`${dat.getNameShort()}: done processing candidates`);
return processedCandidates;
}

private async mapReleaseCandidate(
private mapReleaseCandidate(
dat: DAT,
releaseCandidate: ReleaseCandidate,
outputFileBasenames: string[],
): Promise<ReleaseCandidate> {
const newRomsWithFiles = await this.mapRomsWithFiles(
): ReleaseCandidate {
const newRomsWithFiles = this.mapRomsWithFiles(
dat,
releaseCandidate,
releaseCandidate.getRomsWithFiles(),
Expand All @@ -87,35 +85,32 @@ export default class CandidatePostProcessor extends Module {
);
}

private async mapRomsWithFiles(
private mapRomsWithFiles(
dat: DAT,
releaseCandidate: ReleaseCandidate,
romsWithFiles: ROMWithFiles[],
outputFileBasenames: string[],
): Promise<ROMWithFiles[]> {
return Promise.all(
romsWithFiles.map(async (romWithFiles) => {
const newOutputPath = OutputFactory.getPath(
this.options,
dat,
releaseCandidate.getGame(),
releaseCandidate.getRelease(),
romWithFiles.getRom(),
romWithFiles.getInputFile(),
outputFileBasenames,
).format();
if (newOutputPath === romWithFiles.getOutputFile().getFilePath()) {
return romWithFiles;
}
): ROMWithFiles[] {
return romsWithFiles.map((romWithFiles) => {
const newOutputPath = OutputFactory.getPath(
this.options,
dat,
releaseCandidate.getGame(),
releaseCandidate.getRelease(),
romWithFiles.getRom(),
romWithFiles.getInputFile(),
outputFileBasenames,
).format();
if (newOutputPath === romWithFiles.getOutputFile().getFilePath()) {
return romWithFiles;
}

const newOutputFile = await romWithFiles.getOutputFile()
.withFilePath(newOutputPath);
return new ROMWithFiles(
romWithFiles.getRom(),
romWithFiles.getInputFile(),
newOutputFile,
);
}),
);
const newOutputFile = romWithFiles.getOutputFile().withFilePath(newOutputPath);
return new ROMWithFiles(
romWithFiles.getRom(),
romWithFiles.getInputFile(),
newOutputFile,
);
});
}
}
80 changes: 29 additions & 51 deletions src/types/files/archives/archiveEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,24 @@ import { Readable } from 'stream';
import Constants from '../../../constants.js';
import fsPoly from '../../../polyfill/fsPoly.js';
import Patch from '../../patches/patch.js';
import File from '../file.js';
import File, { FileProps } from '../file.js';
import ROMHeader from '../romHeader.js';
import Archive from './archive.js';

export default class ArchiveEntry<A extends Archive> extends File {
private readonly archive: A;
interface ArchiveEntryProps<A> extends FileProps {
readonly archive: A;
readonly entryPath: string;
}

private readonly entryPath: string;
export default class ArchiveEntry<A extends Archive> extends File implements ArchiveEntryProps<A> {
readonly archive: A;

protected constructor(
/** {@link File} */
filePath: string,
size: number,
crc: string,
crc32WithoutHeader: string,
symlinkSource: string | undefined,
fileHeader: ROMHeader | undefined,
patch: Patch | undefined,
/** {@link ArchiveEntry} */
archive: A,
entryPath: string,
) {
super(
filePath,
size,
crc,
crc32WithoutHeader,
symlinkSource,
fileHeader,
patch,
);
this.archive = archive;
this.entryPath = path.normalize(entryPath);
readonly entryPath: string;

protected constructor(archiveEntryProps: ArchiveEntryProps<A>) {
super(archiveEntryProps);
this.archive = archiveEntryProps.archive;
this.entryPath = path.normalize(archiveEntryProps.entryPath);
}

static async entryOf<A extends Archive>(
Expand All @@ -63,17 +48,17 @@ export default class ArchiveEntry<A extends Archive> extends File {
}
finalCrcWithoutHeader = finalCrcWithoutHeader ?? crc;

return new ArchiveEntry<A>(
archive.getFilePath(),
return new ArchiveEntry<A>({
filePath: archive.getFilePath(),
size,
crc,
finalCrcWithoutHeader,
finalSymlinkSource,
crc32: crc,
crc32WithoutHeader: finalCrcWithoutHeader,
symlinkSource: finalSymlinkSource,
fileHeader,
patch,
archive,
entryPath,
);
});
}

getArchive(): A {
Expand Down Expand Up @@ -135,15 +120,11 @@ export default class ArchiveEntry<A extends Archive> extends File {
return this.archive.extractEntryToStream(this.getEntryPath(), callback);
}

async withFilePath(filePath: string): Promise<ArchiveEntry<Archive>> {
return ArchiveEntry.entryOf(
this.getArchive().withFilePath(filePath),
this.getEntryPath(),
this.getSize(),
this.getCrc32(),
this.getFileHeader(),
this.getPatch(),
);
withFilePath(filePath: string): ArchiveEntry<Archive> {
return new ArchiveEntry({
...this,
archive: this.getArchive().withFilePath(filePath),
});
}

async withEntryPath(entryPath: string): Promise<ArchiveEntry<A>> {
Expand Down Expand Up @@ -176,19 +157,16 @@ export default class ArchiveEntry<A extends Archive> extends File {
);
}

async withPatch(patch: Patch): Promise<ArchiveEntry<A>> {
withPatch(patch: Patch): ArchiveEntry<A> {
if (patch.getCrcBefore() !== this.getCrc32()) {
return this;
}

return ArchiveEntry.entryOf(
this.getArchive(),
this.getEntryPath(),
this.getSize(),
this.getCrc32(),
undefined, // don't allow a file header
return new ArchiveEntry({
...this,
fileHeader: undefined, // don't allow a file header
patch,
);
});
}

toString(): string {
Expand Down
85 changes: 41 additions & 44 deletions src/types/files/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,43 @@ import Cache from '../cache.js';
import Patch from '../patches/patch.js';
import ROMHeader from './romHeader.js';

export default class File {
export interface FileProps {
readonly filePath: string;
readonly size: number;
readonly crc32: string;
readonly crc32WithoutHeader: string;
readonly symlinkSource?: string;
readonly fileHeader?: ROMHeader;
readonly patch?: Patch;
}

export default class File implements FileProps {
private static readonly crc32Cache = new Cache<string, string>(
Constants.FILE_CHECKSUM_CACHE_SIZE,
);

private readonly filePath: string;
readonly filePath: string;

private readonly size: number;
readonly size: number;

private readonly crc32: string;
readonly crc32: string;

private readonly crc32WithoutHeader: string;
readonly crc32WithoutHeader: string;

private readonly symlinkSource?: string;
readonly symlinkSource?: string;

private readonly fileHeader?: ROMHeader;
readonly fileHeader?: ROMHeader;

private readonly patch?: Patch;
readonly patch?: Patch;

protected constructor(
filePath: string,
size: number,
crc: string,
crc32WithoutHeader: string,
symlinkSource?: string,
fileHeader?: ROMHeader,
patch?: Patch,
) {
this.filePath = path.normalize(filePath);
this.size = size;
this.crc32 = crc.toLowerCase().padStart(8, '0');
this.crc32WithoutHeader = crc32WithoutHeader.toLowerCase().padStart(8, '0');
this.symlinkSource = symlinkSource;
this.fileHeader = fileHeader;
this.patch = patch;
protected constructor(fileProps: FileProps) {
this.filePath = path.normalize(fileProps.filePath);
this.size = fileProps.size;
this.crc32 = fileProps.crc32.toLowerCase().padStart(8, '0');
this.crc32WithoutHeader = fileProps.crc32WithoutHeader.toLowerCase().padStart(8, '0');
this.symlinkSource = fileProps.symlinkSource;
this.fileHeader = fileProps.fileHeader;
this.patch = fileProps.patch;
}

static async fileOf(
Expand Down Expand Up @@ -79,15 +81,15 @@ export default class File {
}
finalCrcWithoutHeader = finalCrcWithoutHeader ?? finalCrc;

return new File(
return new File({
filePath,
finalSize,
finalCrc,
finalCrcWithoutHeader,
finalSymlinkSource,
size: finalSize,
crc32: finalCrc,
crc32WithoutHeader: finalCrcWithoutHeader,
symlinkSource: finalSymlinkSource,
fileHeader,
patch,
);
});
}

// Property getters
Expand Down Expand Up @@ -335,14 +337,11 @@ export default class File {
return this.downloadToPath(filePath);
}

async withFilePath(filePath: string): Promise<File> {
return File.fileOf(
withFilePath(filePath: string): File {
return new File({
...this,
filePath,
this.getSize(),
this.getCrc32(),
this.getFileHeader(),
this.getPatch(),
);
});
}

async withFileHeader(fileHeader: ROMHeader): Promise<File> {
Expand All @@ -363,18 +362,16 @@ export default class File {
);
}

async withPatch(patch: Patch): Promise<File> {
withPatch(patch: Patch): File {
if (patch.getCrcBefore() !== this.getCrc32()) {
return this;
}

return File.fileOf(
this.getFilePath(),
this.getSize(),
this.getCrc32(),
undefined, // don't allow a file header
return new File({
...this,
fileHeader: undefined,
patch,
);
});
}

/** *************************
Expand Down
Loading

0 comments on commit 5072263

Please sign in to comment.