后端迁移会话运行时模块

This commit is contained in:
yml
2026-05-21 15:26:35 +08:00
parent 4453f17678
commit b86d7e8974
3 changed files with 53 additions and 20 deletions
+101
View File
@@ -0,0 +1,101 @@
import { runtimeConfig } from '../../config/runtime.js'
const DEFAULT_TIMEOUT_MS = 60_000
type OcrAction = 'recognize' | 'batch'
type OcrRequestPayload = Record<string, unknown>
type OcrHttpResult = Record<string, any> & {
code: number
msg?: string
}
export async function recognizeTencentCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
return callOcrViaHttp('recognize', payload)
}
export async function recognizeImageCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
return callOcrViaHttp('recognize', payload)
}
export async function batchRecognizeTencentCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
return callOcrViaHttp('batch', payload, { timeoutMs: 180_000 })
}
export async function warmupLocalOcrWorker(): Promise<void> {
await warmupOcrViaHttp()
}
export async function closeLocalOcrWorker(): Promise<void> {
// HTTP 模式无持久连接,无需关闭。
}
// ── HTTP Call ───────────────────────────────────────────────────────────────
async function callOcrViaHttp(
action: OcrAction,
payload: OcrRequestPayload,
{ timeoutMs = DEFAULT_TIMEOUT_MS }: { timeoutMs?: number } = {},
): Promise<OcrHttpResult> {
const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '')
if (!baseUrl) {
throw new Error('OCR_BASE_URL 未配置,无法调用 OCR 服务')
}
const url = `${baseUrl}/ocr/${action}`
let response
try {
response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
signal: AbortSignal.timeout(timeoutMs),
})
} catch (err) {
if (err instanceof Error && err.name === 'TimeoutError') {
throw new Error(`OCR 请求超时(${timeoutMs}ms),请检查 OCR 服务状态`)
}
throw new Error(`OCR 服务不可用(${baseUrl}),请检查 ocr-worker 容器是否正常运行`)
}
if (!response.ok) {
throw new Error(`OCR 服务返回错误:HTTP ${response.status}`)
}
const result = await response.json()
if (!result || typeof result !== 'object' || Array.isArray(result)) {
throw new Error('OCR 服务返回了无效响应')
}
const ocrResult = result as OcrHttpResult
if (ocrResult.code !== 0) {
throw new Error(`OCR 服务返回错误:${ocrResult.msg || '未知错误'}`)
}
return ocrResult
}
async function warmupOcrViaHttp(): Promise<void> {
const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '')
if (!baseUrl) {
throw new Error('OCR_BASE_URL 未配置,无法启动 OCR 健康检查')
}
let response
try {
response = await fetch(`${baseUrl}/health`, {
signal: AbortSignal.timeout(30_000),
})
} catch (err) {
if (err instanceof Error && err.name === 'TimeoutError') {
throw new Error(`OCR 服务健康检查超时,请检查 ${baseUrl} 是否可访问`)
}
throw new Error(`OCR 服务不可用(${baseUrl}),请检查 ocr-worker 容器是否正常运行`)
}
if (!response.ok) {
throw new Error(`OCR 服务健康检查失败:HTTP ${response.status}`)
}
}