架构优化

This commit is contained in:
cc committed 2026-07-07 14:11:02 +08:00
1 parent 147f3b7045
commit ccbd154668
67 files changed
+1726 -421

No files matched your search

+117
View File
@@ -1,5 +1,6 @@
import { existsSync } from 'fs'
import { join } from 'path'
import { Worker } from 'worker_threads'
type NativeDecryptResult = {
data: Buffer
@@ -152,3 +153,119 @@ export function encryptDatViaNative(
return null
}
}
// ─── Worker 化解密:原生解密是同步 CPU/IO 调用,滚动时批量触发会阻塞主线程 ───
type WorkerDecryptResult = { data: Buffer; ext: string; isWxgf: boolean; meta: NativeDatMeta } | null
type PendingJob = {
resolve: (value: WorkerDecryptResult) => void
}
let decryptWorker: Worker | null = null
let workerFailedPermanently = false
let workerJobSeq = 0
const pendingJobs = new Map<number, PendingJob>()
function resolveWorkerPath(): string | null {
const isDev = process.env.NODE_ENV === 'development'
const candidates = isDev
? [join(__dirname, '../dist-electron/imageDecryptWorker.js'), join(__dirname, 'imageDecryptWorker.js')]
: [join(__dirname, 'imageDecryptWorker.js')]
for (const candidate of candidates) {
if (existsSync(candidate)) return candidate
}
return null
}
function flushPendingJobs(): void {
for (const job of pendingJobs.values()) job.resolve(null)
pendingJobs.clear()
}
function ensureDecryptWorker(): Worker | null {
if (workerFailedPermanently) return null
if (decryptWorker) return decryptWorker
const workerPath = resolveWorkerPath()
if (!workerPath) {
workerFailedPermanently = true
return null
}
try {
const worker = new Worker(workerPath, {
workerData: { resourcesPath: process.resourcesPath || '' }
})
worker.on('message', (msg: { id: number; ok: boolean; addonMissing?: boolean; data?: ArrayBuffer; ext?: string; isWxgf?: boolean; meta?: NativeDatMeta }) => {
const job = pendingJobs.get(msg.id)
if (!job) return
pendingJobs.delete(msg.id)
if (msg.addonMissing) {
// worker 中找不到原生模块:停用 worker 路径,后续直接走主线程同步逻辑
workerFailedPermanently = true
terminateDecryptWorker()
job.resolve(null)
return
}
if (!msg.ok || !msg.data) {
job.resolve(null)
return
}
job.resolve({
data: Buffer.from(msg.data),
ext: msg.ext || '',
isWxgf: Boolean(msg.isWxgf),
meta: msg.meta || {}
})
})
const handleWorkerGone = () => {
flushPendingJobs()
decryptWorker = null
}
worker.on('error', handleWorkerGone)
worker.on('exit', handleWorkerGone)
worker.unref()
decryptWorker = worker
return worker
} catch {
workerFailedPermanently = true
return null
}
}
/**
* 在 worker 线程中执行原生 DAT 解密,不阻塞主线程。
* worker 不可用时回退为主线程同步解密(行为与旧版一致)。
*/
export async function decryptDatViaNativeAsync(
inputPath: string,
xorKey: number,
aesKey?: string
): Promise<WorkerDecryptResult> {
if (!shouldEnableNative()) return null
const worker = ensureDecryptWorker()
if (!worker) {
return decryptDatViaNative(inputPath, xorKey, aesKey)
}
const id = ++workerJobSeq
return new Promise<WorkerDecryptResult>((resolve) => {
pendingJobs.set(id, { resolve })
try {
worker.postMessage({ id, datPath: inputPath, xorKey, aesKey })
} catch {
pendingJobs.delete(id)
resolve(decryptDatViaNative(inputPath, xorKey, aesKey))
}
})
}
export function terminateDecryptWorker(): void {
if (decryptWorker) {
void decryptWorker.terminate()
decryptWorker = null
}
flushPendingJobs()
}