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.
374 lines (373 loc) • 12.8 kB
JavaScript
const RETRY_TIMEOUT_MS = 6e4;
const RETRY_BACKOFF_MULTIPLIER = 1.2;
const RETRY_MIN_BACKOFF_MS = 10;
const RETRY_MAX_BACKOFF_MS = 100;
const TRANSIENT_ERRNO_CODES = /* @__PURE__ */ new Set([
...process.platform === "win32" ? ["EACCES", "EPERM"] : [],
"EBUSY",
"EAGAIN",
"EMFILE",
"ENFILE",
// Everything below this did not exist in `graceful-fs` v4.2.11!
"EWOULDBLOCK",
"ETXTBSY"
]);
class RetryQueue {
entries = [];
timer;
/**
* Adds a new entry to the queue and schedules processing if not already scheduled.
*/
enqueue(entry) {
this.entries.push(entry);
this.scheduleProcess();
}
scheduleProcess() {
if (this.timer !== void 0) return;
const maxRetries = this.entries.reduce((max, e) => Math.max(max, e.retryCount), 0);
const delay = Math.min(
Math.max(maxRetries * RETRY_BACKOFF_MULTIPLIER, RETRY_MIN_BACKOFF_MS),
RETRY_MAX_BACKOFF_MS
);
this.timer = setTimeout(() => {
this.timer = void 0;
this.process();
}, delay);
this.timer.unref();
}
process() {
const entry = this.entries.shift();
if (entry === void 0) return;
entry.retryCount++;
if (Date.now() - entry.startTime >= RETRY_TIMEOUT_MS) {
entry.timeout();
} else {
entry.retry();
}
if (this.entries.length > 0) {
this.scheduleProcess();
}
}
}
const retryQueue = new RetryQueue();
function wrapCallbackMethod(originalFn, options) {
return function(...methodArgs) {
let attempts = 0;
let backoff = 0;
const startTime = Date.now();
const userCallback = methodArgs.pop();
const attempt = () => {
Reflect.apply(originalFn, this, [
...methodArgs,
(err, ...resultData) => {
attempts++;
if (!err) {
userCallback(err, ...resultData);
return;
}
const didExceedMaxAttempts = Date.now() - startTime >= RETRY_TIMEOUT_MS || options?.maxAttempts !== void 0 && attempts >= options.maxAttempts;
if (didExceedMaxAttempts || !TRANSIENT_ERRNO_CODES.has(err.code ?? "")) {
userCallback(err, ...resultData);
return;
}
if (options?.useQueue) {
retryQueue.enqueue({
retry: attempt,
timeout: () => {
userCallback(err);
},
startTime,
retryCount: attempts
});
} else if (options?.backoff) {
backoff = Math.min(
Math.max(backoff * RETRY_BACKOFF_MULTIPLIER, RETRY_MIN_BACKOFF_MS),
RETRY_MAX_BACKOFF_MS
);
setTimeout(attempt, backoff);
} else {
attempt();
}
}
]);
};
attempt();
};
}
function wrapSyncMethod(originalFn, options) {
return function(...args) {
let attempts = 0;
const startTime = Date.now();
for (; ; ) {
try {
return Reflect.apply(originalFn, this, args);
} catch (error) {
attempts++;
const didExceedMaxAttempts = Date.now() - startTime >= RETRY_TIMEOUT_MS || options?.maxAttempts !== void 0 && attempts >= options.maxAttempts;
if (didExceedMaxAttempts || !TRANSIENT_ERRNO_CODES.has(error.code ?? "")) {
throw error;
}
}
}
};
}
function wrapPromiseMethod(originalFn, options) {
return async function(...args) {
const startTime = Date.now();
return await new Promise((resolve, reject) => {
let attempts = 0;
let backoff = 0;
const attempt = () => {
let innerPromise;
try {
innerPromise = originalFn.apply(this, args);
} catch (error) {
reject(error instanceof Error ? error : new Error(String(error)));
return;
}
innerPromise.then(resolve).catch((error) => {
attempts++;
const didExceedMaxAttempts = Date.now() - startTime >= RETRY_TIMEOUT_MS || options?.maxAttempts !== void 0 && attempts >= options.maxAttempts;
if (didExceedMaxAttempts || !TRANSIENT_ERRNO_CODES.has(error.code ?? "")) {
reject(error instanceof Error ? error : new Error(String(error)));
return;
}
if (options?.useQueue) {
retryQueue.enqueue({
retry: attempt,
timeout: () => {
reject(error instanceof Error ? error : new Error(String(error)));
},
startTime,
retryCount: attempts
});
} else if (options?.backoff) {
backoff = Math.min(
Math.max(backoff * RETRY_BACKOFF_MULTIPLIER, RETRY_MIN_BACKOFF_MS),
RETRY_MAX_BACKOFF_MS
);
setTimeout(attempt, backoff);
} else {
attempt();
}
});
};
attempt();
});
};
}
var gracefulFs_default = {
gracefulify: (fsToPatch) => {
fsToPatch.readFile = wrapCallbackMethod(fsToPatch.readFile, {
useQueue: true
});
fsToPatch.readFileSync = wrapSyncMethod(
fsToPatch.readFileSync
);
fsToPatch.promises.readFile = wrapPromiseMethod(fsToPatch.promises.readFile, {
useQueue: true
});
fsToPatch.writeFile = wrapCallbackMethod(fsToPatch.writeFile, {
useQueue: true
});
fsToPatch.writeFileSync = wrapSyncMethod(fsToPatch.writeFileSync);
fsToPatch.promises.writeFile = wrapPromiseMethod(
fsToPatch.promises.writeFile,
{ useQueue: true }
);
fsToPatch.appendFile = wrapCallbackMethod(fsToPatch.appendFile, {
useQueue: true
});
fsToPatch.appendFileSync = wrapSyncMethod(fsToPatch.appendFileSync);
fsToPatch.promises.appendFile = wrapPromiseMethod(
fsToPatch.promises.appendFile,
{ useQueue: true }
);
fsToPatch.copyFile = wrapCallbackMethod(fsToPatch.copyFile, {
useQueue: true
});
fsToPatch.copyFileSync = wrapSyncMethod(fsToPatch.copyFileSync);
fsToPatch.promises.copyFile = wrapPromiseMethod(fsToPatch.promises.copyFile, {
useQueue: true
});
fsToPatch.readdir = wrapCallbackMethod(fsToPatch.readdir, {
useQueue: true
});
fsToPatch.readdirSync = wrapSyncMethod(
fsToPatch.readdirSync
);
fsToPatch.promises.readdir = wrapPromiseMethod(fsToPatch.promises.readdir, {
useQueue: true
});
fsToPatch.open = wrapCallbackMethod(fsToPatch.open, {
useQueue: true
});
fsToPatch.openSync = wrapSyncMethod(fsToPatch.openSync);
fsToPatch.promises.open = wrapPromiseMethod(fsToPatch.promises.open, {
useQueue: true
});
fsToPatch.chown = wrapCallbackMethod(fsToPatch.chown);
fsToPatch.chownSync = wrapSyncMethod(fsToPatch.chownSync);
fsToPatch.promises.chown = wrapPromiseMethod(
fsToPatch.promises.chown
);
fsToPatch.fchown = wrapCallbackMethod(fsToPatch.fchown);
fsToPatch.fchownSync = wrapSyncMethod(fsToPatch.fchownSync);
fsToPatch.lchown = wrapCallbackMethod(fsToPatch.lchown);
fsToPatch.lchownSync = wrapSyncMethod(fsToPatch.lchownSync);
fsToPatch.promises.lchown = wrapPromiseMethod(
fsToPatch.promises.lchown
);
fsToPatch.chmod = wrapCallbackMethod(fsToPatch.chmod);
fsToPatch.chmodSync = wrapSyncMethod(fsToPatch.chmodSync);
fsToPatch.promises.chmod = wrapPromiseMethod(
fsToPatch.promises.chmod
);
fsToPatch.fchmod = wrapCallbackMethod(fsToPatch.fchmod);
fsToPatch.fchmodSync = wrapSyncMethod(fsToPatch.fchmodSync);
fsToPatch.lchmod = wrapCallbackMethod(fsToPatch.lchmod);
fsToPatch.lchmodSync = wrapSyncMethod(fsToPatch.lchmodSync);
fsToPatch.promises.lchmod = wrapPromiseMethod(
fsToPatch.promises.lchmod
);
fsToPatch.stat = wrapCallbackMethod(fsToPatch.stat);
fsToPatch.statSync = wrapSyncMethod(fsToPatch.statSync);
fsToPatch.promises.stat = wrapPromiseMethod(
fsToPatch.promises.stat
);
fsToPatch.fstat = wrapCallbackMethod(fsToPatch.fstat);
fsToPatch.fstatSync = wrapSyncMethod(fsToPatch.fstatSync);
fsToPatch.lstat = wrapCallbackMethod(fsToPatch.lstat);
fsToPatch.lstatSync = wrapSyncMethod(fsToPatch.lstatSync);
fsToPatch.promises.lstat = wrapPromiseMethod(
fsToPatch.promises.lstat
);
fsToPatch.rename = wrapCallbackMethod(fsToPatch.rename, {
backoff: true
});
fsToPatch.promises.rename = wrapPromiseMethod(fsToPatch.promises.rename, {
backoff: true
});
fsToPatch.read = wrapCallbackMethod(fsToPatch.read, {
maxAttempts: 10
});
fsToPatch.readSync = wrapSyncMethod(fsToPatch.readSync, {
maxAttempts: 10
});
fsToPatch.write = wrapCallbackMethod(fsToPatch.write, {
maxAttempts: 10
});
fsToPatch.writeSync = wrapSyncMethod(fsToPatch.writeSync, {
maxAttempts: 10
});
fsToPatch.access = wrapCallbackMethod(fsToPatch.access);
fsToPatch.accessSync = wrapSyncMethod(fsToPatch.accessSync);
fsToPatch.promises.access = wrapPromiseMethod(
fsToPatch.promises.access
);
fsToPatch.fdatasync = wrapCallbackMethod(fsToPatch.fdatasync, {
maxAttempts: 10
});
fsToPatch.fdatasyncSync = wrapSyncMethod(fsToPatch.fdatasyncSync, {
maxAttempts: 10
});
fsToPatch.fsync = wrapCallbackMethod(fsToPatch.fsync, {
maxAttempts: 10
});
fsToPatch.fsyncSync = wrapSyncMethod(fsToPatch.fsyncSync, {
maxAttempts: 10
});
fsToPatch.ftruncate = wrapCallbackMethod(fsToPatch.ftruncate, {
maxAttempts: 10
});
fsToPatch.ftruncateSync = wrapSyncMethod(fsToPatch.ftruncateSync, {
maxAttempts: 10
});
fsToPatch.futimes = wrapCallbackMethod(fsToPatch.futimes, {
maxAttempts: 10
});
fsToPatch.futimesSync = wrapSyncMethod(fsToPatch.futimesSync, {
maxAttempts: 10
});
fsToPatch.link = wrapCallbackMethod(fsToPatch.link);
fsToPatch.linkSync = wrapSyncMethod(fsToPatch.linkSync);
fsToPatch.promises.link = wrapPromiseMethod(
fsToPatch.promises.link
);
fsToPatch.lutimes = wrapCallbackMethod(fsToPatch.lutimes);
fsToPatch.lutimesSync = wrapSyncMethod(fsToPatch.lutimesSync);
fsToPatch.promises.lutimes = wrapPromiseMethod(
fsToPatch.promises.lutimes
);
fsToPatch.mkdir = wrapCallbackMethod(fsToPatch.mkdir);
fsToPatch.mkdirSync = wrapSyncMethod(fsToPatch.mkdirSync);
fsToPatch.promises.mkdir = wrapPromiseMethod(
fsToPatch.promises.mkdir
);
fsToPatch.mkdtemp = wrapCallbackMethod(fsToPatch.mkdtemp);
fsToPatch.mkdtempSync = wrapSyncMethod(
fsToPatch.mkdtempSync
);
fsToPatch.promises.mkdtemp = wrapPromiseMethod(
fsToPatch.promises.mkdtemp
);
fsToPatch.opendir = wrapCallbackMethod(fsToPatch.opendir, {
useQueue: true
});
fsToPatch.opendirSync = wrapSyncMethod(
fsToPatch.opendirSync
);
fsToPatch.promises.opendir = wrapPromiseMethod(fsToPatch.promises.opendir, {
useQueue: true
});
fsToPatch.readlink = wrapCallbackMethod(fsToPatch.readlink);
fsToPatch.readlinkSync = wrapSyncMethod(
fsToPatch.readlinkSync
);
fsToPatch.promises.readlink = wrapPromiseMethod(
fsToPatch.promises.readlink
);
fsToPatch.realpath = wrapCallbackMethod(fsToPatch.realpath);
fsToPatch.realpathSync = wrapSyncMethod(
fsToPatch.realpathSync
);
fsToPatch.promises.realpath = wrapPromiseMethod(
fsToPatch.promises.realpath
);
fsToPatch.rm = wrapCallbackMethod(fsToPatch.rm);
fsToPatch.rmSync = wrapSyncMethod(fsToPatch.rmSync);
fsToPatch.promises.rm = wrapPromiseMethod(
fsToPatch.promises.rm
);
fsToPatch.rmdir = wrapCallbackMethod(fsToPatch.rmdir);
fsToPatch.rmdirSync = wrapSyncMethod(fsToPatch.rmdirSync);
fsToPatch.promises.rmdir = wrapPromiseMethod(
fsToPatch.promises.rmdir
);
fsToPatch.symlink = wrapCallbackMethod(fsToPatch.symlink);
fsToPatch.symlinkSync = wrapSyncMethod(fsToPatch.symlinkSync);
fsToPatch.promises.symlink = wrapPromiseMethod(
fsToPatch.promises.symlink
);
fsToPatch.truncate = wrapCallbackMethod(fsToPatch.truncate);
fsToPatch.truncateSync = wrapSyncMethod(fsToPatch.truncateSync);
fsToPatch.promises.truncate = wrapPromiseMethod(
fsToPatch.promises.truncate
);
fsToPatch.unlink = wrapCallbackMethod(fsToPatch.unlink);
fsToPatch.unlinkSync = wrapSyncMethod(fsToPatch.unlinkSync);
fsToPatch.promises.unlink = wrapPromiseMethod(
fsToPatch.promises.unlink
);
fsToPatch.utimes = wrapCallbackMethod(fsToPatch.utimes);
fsToPatch.utimesSync = wrapSyncMethod(fsToPatch.utimesSync);
fsToPatch.promises.utimes = wrapPromiseMethod(
fsToPatch.promises.utimes
);
return fsToPatch;
}
};
export {
gracefulFs_default as default
};
//# sourceMappingURL=gracefulFs.js.map