#849 以及导出中媒体相关问题修复

This commit is contained in:
cc
2026-04-26 18:46:56 +08:00
parent 1976edc483
commit a86a51c30c
10 changed files with 761 additions and 188 deletions

View File

@@ -1,14 +1,18 @@
import { parentPort, workerData } from 'worker_threads'
import type { ExportOptions } from './services/exportService'
interface ExportWorkerConfig {
sessionIds: string[]
outputDir: string
options: ExportOptions
mode?: 'sessions' | 'single' | 'contacts'
sessionIds?: string[]
sessionId?: string
outputDir?: string
outputPath?: string
options?: any
taskId?: string
dbPath?: string
decryptKey?: string
myWxid?: string
imageXorKey?: unknown
imageAesKey?: string
resourcesPath?: string
userDataPath?: string
logEnabled?: boolean
@@ -20,6 +24,93 @@ const controlState = {
stopRequested: false
}
const CREATED_PATH_FLUSH_INTERVAL_MS = 200
const CREATED_PATH_BATCH_LIMIT = 256
const PROGRESS_POST_INTERVAL_MS = 180
let queuedCreatedFiles: string[] = []
let queuedCreatedDirs: string[] = []
let createdPathFlushTimer: ReturnType<typeof setTimeout> | null = null
let pendingProgress: any = null
let progressPostTimer: ReturnType<typeof setTimeout> | null = null
let lastProgressPostedAt = 0
function flushCreatedPaths() {
if (createdPathFlushTimer) {
clearTimeout(createdPathFlushTimer)
createdPathFlushTimer = null
}
const filePaths = queuedCreatedFiles
const dirPaths = queuedCreatedDirs
queuedCreatedFiles = []
queuedCreatedDirs = []
if (!parentPort) return
if (filePaths.length > 0) {
parentPort.postMessage({ type: 'export:createdFiles', filePaths })
}
if (dirPaths.length > 0) {
parentPort.postMessage({ type: 'export:createdDirs', dirPaths })
}
}
function scheduleCreatedPathFlush() {
if (createdPathFlushTimer) return
createdPathFlushTimer = setTimeout(flushCreatedPaths, CREATED_PATH_FLUSH_INTERVAL_MS)
}
function queueCreatedFile(filePath: string) {
const normalized = String(filePath || '').trim()
if (!normalized) return
queuedCreatedFiles.push(normalized)
if (queuedCreatedFiles.length + queuedCreatedDirs.length >= CREATED_PATH_BATCH_LIMIT) {
flushCreatedPaths()
} else {
scheduleCreatedPathFlush()
}
}
function queueCreatedDir(dirPath: string) {
const normalized = String(dirPath || '').trim()
if (!normalized) return
queuedCreatedDirs.push(normalized)
if (queuedCreatedFiles.length + queuedCreatedDirs.length >= CREATED_PATH_BATCH_LIMIT) {
flushCreatedPaths()
} else {
scheduleCreatedPathFlush()
}
}
function flushProgress() {
if (!pendingProgress) return
if (progressPostTimer) {
clearTimeout(progressPostTimer)
progressPostTimer = null
}
parentPort?.postMessage({
type: 'export:progress',
data: pendingProgress
})
pendingProgress = null
lastProgressPostedAt = Date.now()
}
function queueProgress(progress: any) {
pendingProgress = progress
if (progress?.phase === 'complete') {
flushProgress()
return
}
const now = Date.now()
const elapsed = now - lastProgressPostedAt
if (elapsed >= PROGRESS_POST_INTERVAL_MS) {
flushProgress()
return
}
if (progressPostTimer) return
progressPostTimer = setTimeout(flushProgress, PROGRESS_POST_INTERVAL_MS - elapsed)
}
parentPort?.on('message', (message: any) => {
if (!message || typeof message.type !== 'string') return
if (message.type === 'export:pause') {
@@ -57,32 +148,49 @@ async function run() {
exportService.setRuntimeConfig({
dbPath: config.dbPath,
decryptKey: config.decryptKey,
myWxid: config.myWxid
myWxid: config.myWxid,
imageXorKey: config.imageXorKey,
imageAesKey: config.imageAesKey
})
const result = await exportService.exportSessions(
Array.isArray(config.sessionIds) ? config.sessionIds : [],
String(config.outputDir || ''),
config.options || { format: 'json' },
(progress) => {
parentPort?.postMessage({
type: 'export:progress',
data: progress
})
},
config.taskId
? {
shouldPause: () => controlState.pauseRequested,
shouldStop: () => controlState.stopRequested,
recordCreatedFile: (filePath: string) => {
parentPort?.postMessage({ type: 'export:createdFile', filePath })
},
recordCreatedDir: (dirPath: string) => {
parentPort?.postMessage({ type: 'export:createdDir', dirPath })
}
}
: undefined
)
const onProgress = (progress: any) => queueProgress(progress)
const taskControl = config.taskId
? {
shouldPause: () => controlState.pauseRequested,
shouldStop: () => controlState.stopRequested,
recordCreatedFile: queueCreatedFile,
recordCreatedDir: queueCreatedDir
}
: undefined
let result: any
if (config.mode === 'contacts') {
const { contactExportService } = await import('./services/contactExportService')
result = await contactExportService.exportContacts(
String(config.outputDir || ''),
config.options || {}
)
} else if (config.mode === 'single') {
result = await exportService.exportSessionToChatLab(
String(config.sessionId || '').trim(),
String(config.outputPath || '').trim(),
config.options || { format: 'chatlab' },
onProgress,
taskControl
)
} else {
result = await exportService.exportSessions(
Array.isArray(config.sessionIds) ? config.sessionIds : [],
String(config.outputDir || ''),
config.options || { format: 'json' },
onProgress,
taskControl
)
}
flushProgress()
flushCreatedPaths()
parentPort?.postMessage({
type: 'export:result',
@@ -91,6 +199,8 @@ async function run() {
}
run().catch((error) => {
flushProgress()
flushCreatedPaths()
parentPort?.postMessage({
type: 'export:error',
error: String(error)