Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Bun: remove dependency 'async' #1112

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
"@node-rs/crc32": "1.10.3",
"7zip-min": "1.4.4",
"archiver": "7.0.1",
"async": "3.2.5",
"async-mutex": "0.5.0",
"chalk": "5.3.0",
"class-transformer": "0.5.1",
Expand Down
13 changes: 6 additions & 7 deletions src/driveSemaphore.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import path from 'node:path';

import async, { AsyncResultCallback } from 'async';
import { Mutex, Semaphore } from 'async-mutex';

import Constants from './constants.js';
import async from './polyfill/async.js';
import FsPoly from './polyfill/fsPoly.js';
import File from './types/files/file.js';

Expand Down Expand Up @@ -38,17 +38,16 @@ export default class DriveSemaphore {
return async.mapLimit(
files,
Constants.MAX_FS_THREADS,
async (file, callback: AsyncResultCallback<V, Error>) => {
async (file) => {
try {
const val = await this.processFile(file, runnable, disks);
callback(undefined, val);
return await this.processFile(file, runnable, disks);
} catch (error) {
if (error instanceof Error) {
callback(error);
throw error;
} else if (typeof error === 'string') {
callback(new Error(error));
throw new Error(error);
} else {
callback(new Error('failed to execute runnable'));
throw new Error('failed to execute runnable');
}
}
},
Expand Down
5 changes: 2 additions & 3 deletions src/igir.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import async from 'async';
import chalk from 'chalk';
import isAdmin from 'is-admin';

Expand Down Expand Up @@ -30,6 +29,7 @@ import ROMIndexer from './modules/romIndexer.js';
import ROMScanner from './modules/romScanner.js';
import StatusGenerator from './modules/statusGenerator.js';
import ArrayPoly from './polyfill/arrayPoly.js';
import async from './polyfill/async.js';
import FsPoly from './polyfill/fsPoly.js';
import Timer from './timer.js';
import DAT from './types/dats/dat.js';
Expand Down Expand Up @@ -101,7 +101,7 @@ export default class Igir {

// Process every DAT
datProcessProgressBar.logTrace(`processing ${dats.length.toLocaleString()} DAT${dats.length !== 1 ? 's' : ''}`);
await async.eachLimit(dats, this.options.getDatThreads(), async (dat, callback) => {
await async.eachLimit(dats, this.options.getDatThreads(), async (dat) => {
await datProcessProgressBar.incrementProgress();

const progressBar = await this.logger.addProgressBar(
Expand Down Expand Up @@ -173,7 +173,6 @@ export default class Igir {
}

await datProcessProgressBar.incrementDone();
callback();
});
datProcessProgressBar.logTrace(`done processing ${dats.length.toLocaleString()} DAT${dats.length !== 1 ? 's' : ''}`);

Expand Down
25 changes: 25 additions & 0 deletions src/polyfill/async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Semaphore } from 'async-mutex';

export default {
async eachLimit<T>(
arr: T[],
limit: number,
iterator: (val: T) => void | Promise<void>,
): Promise<void> {
const semaphore = new Semaphore(limit);
await Promise.all(
arr.map(async (val) => semaphore.runExclusive(async () => iterator(val))),
);
},

async mapLimit<T, R>(
arr: T[],
limit: number,
iterator: (val: T) => R | Promise<R>,
): Promise<R[]> {
const semaphore = new Semaphore(limit);
return Promise.all(
arr.map(async (val) => semaphore.runExclusive(async () => iterator(val))),
);
},
};
19 changes: 8 additions & 11 deletions src/types/files/archives/rar.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import path from 'node:path';

import async, { AsyncResultCallback } from 'async';
import { Mutex } from 'async-mutex';
import unrar from 'node-unrar-js';

import Constants from '../../../constants.js';
import async from '../../../polyfill/async.js';
import Archive from './archive.js';
import ArchiveEntry from './archiveEntry.js';

Expand All @@ -25,16 +25,13 @@ export default class Rar extends Archive {
return async.mapLimit(
[...rar.getFileList().fileHeaders].filter((fileHeader) => !fileHeader.flags.directory),
Constants.ARCHIVE_ENTRY_SCANNER_THREADS_PER_ARCHIVE,
async (fileHeader, callback: AsyncResultCallback<ArchiveEntry<this>, Error>) => {
const archiveEntry = await ArchiveEntry.entryOf({
archive: this,
entryPath: fileHeader.name,
size: fileHeader.unpSize,
crc32: fileHeader.crc.toString(16),
// If MD5, SHA1, or SHA256 is desired, this file will need to be extracted to calculate
}, checksumBitmask);
callback(undefined, archiveEntry);
},
async (fileHeader) => ArchiveEntry.entryOf({
archive: this,
entryPath: fileHeader.name,
size: fileHeader.unpSize,
crc32: fileHeader.crc.toString(16),
// If MD5, SHA1, or SHA256 is desired, this file will need to be extracted to calculate
}, checksumBitmask),
);
}

Expand Down
19 changes: 8 additions & 11 deletions src/types/files/archives/sevenZip.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import path from 'node:path';

import _7z, { Result } from '7zip-min';
import async, { AsyncResultCallback } from 'async';
import { Mutex } from 'async-mutex';

import Constants from '../../../constants.js';
import async from '../../../polyfill/async.js';
import fsPoly from '../../../polyfill/fsPoly.js';
import Archive from './archive.js';
import ArchiveEntry from './archiveEntry.js';
Expand Down Expand Up @@ -86,16 +86,13 @@ export default class SevenZip extends Archive {
return async.mapLimit(
filesIn7z.filter((result) => !result.attr?.startsWith('D')),
Constants.ARCHIVE_ENTRY_SCANNER_THREADS_PER_ARCHIVE,
async (result, callback: AsyncResultCallback<ArchiveEntry<this>, Error>) => {
const archiveEntry = await ArchiveEntry.entryOf({
archive: this,
entryPath: result.name,
size: Number.parseInt(result.size, 10),
crc32: result.crc,
// If MD5, SHA1, or SHA256 is desired, this file will need to be extracted to calculate
}, checksumBitmask);
callback(undefined, archiveEntry);
},
async (result) => ArchiveEntry.entryOf({
archive: this,
entryPath: result.name,
size: Number.parseInt(result.size, 10),
crc32: result.crc,
// If MD5, SHA1, or SHA256 is desired, this file will need to be extracted to calculate
}, checksumBitmask),
);
}

Expand Down
13 changes: 5 additions & 8 deletions src/types/files/archives/zip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { Readable } from 'node:stream';
import { clearInterval } from 'node:timers';

import archiver, { Archiver } from 'archiver';
import async, { AsyncResultCallback } from 'async';
import unzipper, { Entry } from 'unzipper';

import Constants from '../../../constants.js';
import async from '../../../polyfill/async.js';
import fsPoly from '../../../polyfill/fsPoly.js';
import StreamPoly from '../../../polyfill/streamPoly.js';
import File from '../file.js';
Expand All @@ -33,7 +33,7 @@ export default class Zip extends Archive {
return async.mapLimit(
archive.files.filter((entryFile) => entryFile.type === 'File'),
Constants.ARCHIVE_ENTRY_SCANNER_THREADS_PER_ARCHIVE,
async (entryFile, callback: AsyncResultCallback<ArchiveEntry<this>, Error>) => {
async (entryFile) => {
let checksums: ChecksumProps = {};
if (checksumBitmask & ~ChecksumBitmask.CRC32) {
const entryStream = entryFile.stream()
Expand All @@ -54,14 +54,13 @@ export default class Zip extends Archive {
}
const { crc32, ...checksumsWithoutCrc } = checksums;

const archiveEntry = await ArchiveEntry.entryOf({
return ArchiveEntry.entryOf({
archive: this,
entryPath: entryFile.path,
size: entryFile.uncompressedSize,
crc32: crc32 ?? entryFile.crc32.toString(16),
...checksumsWithoutCrc,
}, checksumBitmask);
callback(undefined, archiveEntry);
},
);
}
Expand Down Expand Up @@ -193,9 +192,7 @@ export default class Zip extends Archive {
* also want to make sure the queue processing stays busy. Use 3 as a middle-ground.
*/
3,
async.asyncify(async (
[inputFile, outputArchiveEntry]: [File, ArchiveEntry<Zip>],
): Promise<void> => {
async ([inputFile, outputArchiveEntry]) => {
const streamProcessor = async (stream: Readable): Promise<void> => {
// Catch stream errors such as `ENOENT: no such file or directory`
stream.on('error', catchError);
Expand Down Expand Up @@ -228,7 +225,7 @@ export default class Zip extends Archive {
catchError(new Error(`failed to write '${inputFile.toString()}' to '${outputArchiveEntry.toString()}'`));
}
}
}),
},
);

if (zipFileError) {
Expand Down
11 changes: 5 additions & 6 deletions src/types/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'reflect-metadata';
import os from 'node:os';
import path from 'node:path';

import async, { AsyncResultCallback } from 'async';
import {
Expose, instanceToPlain, plainToInstance, Transform,
} from 'class-transformer';
Expand All @@ -12,6 +11,7 @@ import { isNotJunk } from 'junk';
import micromatch from 'micromatch';
import moment from 'moment';

import async from '../../src/polyfill/async.js';
import LogLevel from '../console/logLevel.js';
import Constants from '../constants.js';
import ArrayPoly from '../polyfill/arrayPoly.js';
Expand Down Expand Up @@ -633,17 +633,16 @@ export default class Options implements OptionsProps {
const isNonDirectory = await async.mapLimit(
globbedPaths,
Constants.MAX_FS_THREADS,
async (file, callback: AsyncResultCallback<boolean, Error>) => {
async (file) => {
if (!await fsPoly.exists(file) && URLPoly.canParse(file)) {
callback(undefined, true);
return;
return true;
}

try {
callback(undefined, !(await fsPoly.isDirectory(file)));
return !(await fsPoly.isDirectory(file));
} catch {
// Assume errors mean the path doesn't exist
callback(undefined, false);
return false;
}
},
);
Expand Down
2 changes: 1 addition & 1 deletion test/igir.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ describe('with explicit DATs', () => {
});

it('should throw on all invalid dats', async () => {
await expect(async () => new Igir(new Options({
await expect(new Igir(new Options({
dat: ['src/*'],
}), new Logger(LogLevel.NEVER)).main()).rejects.toThrow(/no valid dat files/i);
});
Expand Down
Loading