UNPKG

@kazura/node-util

Version:
287 lines (276 loc) 8.14 kB
'use strict'; const path = require('node:path'); const fs = require('node:fs'); const node_crypto = require('node:crypto'); const ddddocrNode = require('ddddocr-node'); const zx = require('zx'); const time2fa = require('time2fa'); const os = require('os'); const worker_threads = require('worker_threads'); const uuid = require('uuid'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const path__default = /*#__PURE__*/_interopDefaultCompat(path); const fs__default = /*#__PURE__*/_interopDefaultCompat(fs); const os__default = /*#__PURE__*/_interopDefaultCompat(os); class Ocr extends ddddocrNode.DdddOcr { static MODEL_TYPE = ddddocrNode.MODEL_TYPE; static CHARSET_RANGE = ddddocrNode.CHARSET_RANGE; static create(logSeverityLevel) { return new Ocr(logSeverityLevel); } } class GitUtil { constructor(repositoryPath) { this.repositoryPath = repositoryPath; } changeDirectory() { zx.cd(this.repositoryPath); } async getBranchName() { this.changeDirectory(); const branch = await zx.$`git rev-parse --abbrev-ref HEAD`; return branch.toString().trim(); } async getShortCommitId() { this.changeDirectory(); const commitId = await zx.$`git rev-parse --short HEAD`; return commitId.toString().trim(); } async getCommitId() { this.changeDirectory(); const commitId = await zx.$`git rev-parse HEAD`; return commitId.toString().trim(); } async getUserName() { this.changeDirectory(); const username = await zx.$`git config user.name`; return username.toString().trim(); } async getUserEmail() { this.changeDirectory(); const email = await zx.$`git config user.email`; return email.toString().trim(); } async add(file) { this.changeDirectory(); await zx.$`git add ${file}`; } async addAll() { this.changeDirectory(); await zx.$`git add .`; } async commit(message) { this.changeDirectory(); await zx.$`git commit -m "${message}"`; } async commitAll(message) { this.changeDirectory(); await zx.$`git commit -a -m ${message}`; } async submodulesUpdateInit() { this.changeDirectory(); await zx.$`git submodule update --init`; } async pullRebaseOrigin() { this.changeDirectory(); await zx.$`git pull --progress -v --rebase "origin"`; } async pullNoRebaseOrigin() { this.changeDirectory(); await zx.$`git pull --progress -v --no-rebase "origin"`; } async checkout(branch) { this.changeDirectory(); await zx.$`git checkout ${branch}`; } async checkoutOrigin(branch) { this.changeDirectory(); await zx.$`git checkout -b ${branch} --track origin/${branch}`; } async pushOrigin(localBranch, remoteBranch) { this.changeDirectory(); remoteBranch = remoteBranch ?? localBranch; await zx.$`git push --progress -v "origin" ${localBranch}:${remoteBranch}`; } } class TotpBase { config; constructor(config) { this.config = time2fa.generateConfig(config); } generateSecret() { return time2fa.generateSecret(this.config.secretSize); } generatePasscodes(secret) { const backupCodes = time2fa.Totp.generatePasscodes({ secret }, this.config); return backupCodes[0]; } validate(passcode, secret) { return time2fa.Totp.validate({ passcode, secret }, this.config); } generateUrl(issuer, user, secret) { return time2fa.generateUrl({ issuer, user, secret }, this.config); } } const Totp = new TotpBase(); class NodeWorker extends worker_threads.Worker { WORKER_ID = uuid.v4(); currentResolve = null; currentReject = null; constructor(filename, options) { super(filename, options); } } class Worker { constructor(filename, options = {}) { this.filename = filename; this.options = options; this.options.max = this.options.max ?? Math.max(1, os__default.cpus().length - 1); if (this.options.max < 1) { throw new Error("options.max must be greater than 0"); } this.options.workerData = Object.assign({}, this.options.workerData, { WORKER_ID: uuid.v4() // Worker 标识 }); } /** * 工作线程池 */ pool = []; /** * 空闲的线程 */ idlePool = []; /** * 等待的任务 */ queue = []; async run(...args) { const worker = await this.getAvailableWorker(); return new Promise((resolve, reject) => { worker.currentResolve = resolve; worker.currentReject = reject; worker.postMessage(args); }); } /** * 停止所有工作线程 */ stop() { this.pool.forEach((w) => w.unref()); this.queue.forEach( ([_, reject]) => reject(new Error("Main worker pool stopped before a worker was available.")) ); this.pool = []; this.idlePool = []; this.queue = []; } /** * 获取可用的工作线程 * @returns */ async getAvailableWorker() { if (this.idlePool.length) { return this.idlePool.shift(); } if (this.pool.length < this.options.max) { const worker = new NodeWorker(this.filename, this.options); worker.on("message", (res) => { worker.currentResolve && worker.currentResolve(res); worker.currentResolve = null; this.assignDoneWorker(worker); }); worker.on("error", (err) => { worker.currentReject && worker.currentReject(err); worker.currentReject = null; }); worker.on("exit", (code) => { const i = this.pool.indexOf(worker); if (i > -1) this.pool.splice(i, 1); if (code !== 0 && worker.currentReject) { worker.currentReject(new Error(`Worker stopped with non-0 exit code ${code}`)); worker.currentReject = null; } }); this.pool.push(worker); return worker; } let resolve; let reject; const onWorkerAvailablePromise = new Promise((r, rj) => { resolve = r; reject = rj; }); this.queue.push([resolve, reject]); return onWorkerAvailablePromise; } /** * 分配完成的工作线程 * @param worker * @returns */ assignDoneWorker(worker) { if (this.queue.length) { const [resolve] = this.queue.shift(); resolve(worker); return; } this.idlePool.push(worker); } } class TaskWorker { workerData = worker_threads.workerData; constructor() { worker_threads.parentPort.on("message", async (args) => { const result = await this.doWork(...args); worker_threads.parentPort.postMessage(result); }); } } function lookupFile(dir, formats, options) { for (const format of formats) { const fullPath = path__default.join(dir, format); if (fs__default.existsSync(fullPath) && fs__default.statSync(fullPath).isFile()) { const result = options?.pathOnly ? fullPath : fs__default.readFileSync(fullPath, "utf-8"); if (!options?.predicate || options.predicate(result)) { return result; } } } const parentDir = path__default.dirname(dir); if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir))) { return lookupFile(parentDir, formats, options); } } function getPkgJson(root) { return JSON.parse(lookupFile(root, ["package.json"]) || `{}`); } function getPkgName(name) { return name?.startsWith("@") ? name.split("/")[1] : name; } function writeFile(filename, content) { const dir = path__default.dirname(filename); if (!fs__default.existsSync(dir)) { fs__default.mkdirSync(dir, { recursive: true }); } fs__default.writeFileSync(filename, content); } function md5(text) { return node_crypto.createHash("md5").update(text, "utf-8").digest("hex"); } function getHash(text) { return node_crypto.createHash("sha256").update(text, "utf-8").digest("hex").substring(0, 8); } exports.GitUtil = GitUtil; exports.Ocr = Ocr; exports.TaskWorker = TaskWorker; exports.Totp = Totp; exports.TotpBase = TotpBase; exports.Worker = Worker; exports.getHash = getHash; exports.getPkgJson = getPkgJson; exports.getPkgName = getPkgName; exports.lookupFile = lookupFile; exports.md5 = md5; exports.writeFile = writeFile;