后端迁移会话运行时模块

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
@@ -1,32 +1,43 @@
// @ts-nocheck
import { runtimeConfig } from '../../config/runtime.js'
const DEFAULT_TIMEOUT_MS = 60_000
export async function recognizeTencentCaptcha(payload) {
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) {
export async function recognizeImageCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
return callOcrViaHttp('recognize', payload)
}
export async function batchRecognizeTencentCaptcha(payload) {
export async function batchRecognizeTencentCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
return callOcrViaHttp('batch', payload, { timeoutMs: 180_000 })
}
export async function warmupLocalOcrWorker() {
export async function warmupLocalOcrWorker(): Promise<void> {
await warmupOcrViaHttp()
}
export async function closeLocalOcrWorker() {
export async function closeLocalOcrWorker(): Promise<void> {
// HTTP 模式无持久连接,无需关闭。
}
// ── HTTP Call ───────────────────────────────────────────────────────────────
async function callOcrViaHttp(action, payload, { timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
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) {
@@ -58,14 +69,15 @@ async function callOcrViaHttp(action, payload, { timeoutMs = DEFAULT_TIMEOUT_MS
if (!result || typeof result !== 'object' || Array.isArray(result)) {
throw new Error('OCR 服务返回了无效响应')
}
if (result.code !== 0) {
throw new Error(`OCR 服务返回错误:${result.msg || '未知错误'}`)
const ocrResult = result as OcrHttpResult
if (ocrResult.code !== 0) {
throw new Error(`OCR 服务返回错误:${ocrResult.msg || '未知错误'}`)
}
return result
return ocrResult
}
async function warmupOcrViaHttp() {
async function warmupOcrViaHttp(): Promise<void> {
const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '')
if (!baseUrl) {
@@ -1,5 +1,3 @@
// @ts-check
import { chromium } from 'playwright'
import { runtimeConfig } from '../../config/runtime.js'
@@ -9,10 +7,24 @@ import {
} from './session-browser-config.js'
import { CHROME_PATH } from './session-service-config.js'
let browserPromise = null
type BrowserLike = {
on: (event: 'disconnected', listener: () => void) => void
close: () => Promise<void>
newContext: (options?: Record<string, unknown>) => Promise<any>
}
type SessionServiceErrorOptions = {
statusCode?: number
errorCode?: string
}
let browserPromise: Promise<BrowserLike> | null = null
export class SessionServiceError extends Error {
constructor(message, { statusCode = 500, errorCode = 'session_error' } = {}) {
statusCode: number
errorCode: string
constructor(message: string, { statusCode = 500, errorCode = 'session_error' }: SessionServiceErrorOptions = {}) {
super(message)
this.name = 'SessionServiceError'
this.statusCode = statusCode
@@ -40,10 +52,10 @@ export async function warmupTencentBrowser() {
}
}
export async function ensureBrowser() {
export async function ensureBrowser(): Promise<BrowserLike> {
if (!browserPromise) {
const launchOptions = resolveBrowserLaunchOptions()
browserPromise = chromium.launch(buildChromiumLaunchOptions(launchOptions))
browserPromise = (chromium.launch(buildChromiumLaunchOptions(launchOptions)) as Promise<BrowserLike>)
.then((browser) => {
browser.on('disconnected', () => {
browserPromise = null
@@ -66,7 +78,7 @@ export function resolveBrowserLaunchOptions() {
})
}
export async function closeBrowserIfIdle({ activeSessionCount = 0 } = {}) {
export async function closeBrowserIfIdle({ activeSessionCount = 0 }: { activeSessionCount?: number } = {}): Promise<void> {
if (activeSessionCount > 0 || !browserPromise) {
return
}
@@ -85,6 +97,6 @@ export async function closeBrowserIfIdle({ activeSessionCount = 0 } = {}) {
}
}
function buildChromiumLaunchOptions(launchOptions) {
function buildChromiumLaunchOptions(launchOptions: ReturnType<typeof resolveBrowserLaunchOptionsBase>) {
return buildChromiumLaunchOptionsBase(launchOptions, { chromePath: CHROME_PATH })
}
@@ -447,6 +447,15 @@
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
89. 腾讯浏览器会话 OCR / browser runtime 模块迁移到 `.ts`
- `src/services/session/ocr.ts`
- `src/services/session/session-service-runtime.ts`
90. OCR HTTP payload / 响应、OCR 超时、浏览器预热、Playwright browser promise 生命周期、SessionServiceError 已显式类型化
91. Docker 内验证通过:
- `src/services/session/session.test.js``src/services/session/session-redeem.test.js` 共 20 个用例通过
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
## 下一步建议