From b86d7e8974bf1decf16f2bc6712e17eb8ec36896 Mon Sep 17 00:00:00 2001 From: yml Date: Thu, 21 May 2026 15:26:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E8=BF=81=E7=A7=BB=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E8=BF=90=E8=A1=8C=E6=97=B6=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/services/session/{ocr.js => ocr.ts} | 36 ++++++++++++------- ...-runtime.js => session-service-runtime.ts} | 28 ++++++++++----- docs/backend-typescript-migration-plan.md | 9 +++++ 3 files changed, 53 insertions(+), 20 deletions(-) rename apps/backend/src/services/session/{ocr.js => ocr.ts} (69%) rename apps/backend/src/services/session/{session-service-runtime.js => session-service-runtime.ts} (69%) diff --git a/apps/backend/src/services/session/ocr.js b/apps/backend/src/services/session/ocr.ts similarity index 69% rename from apps/backend/src/services/session/ocr.js rename to apps/backend/src/services/session/ocr.ts index 48c485f3..10768f5e 100644 --- a/apps/backend/src/services/session/ocr.js +++ b/apps/backend/src/services/session/ocr.ts @@ -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 + +type OcrHttpResult = Record & { + code: number + msg?: string +} + +export async function recognizeTencentCaptcha(payload: OcrRequestPayload): Promise { return callOcrViaHttp('recognize', payload) } -export async function recognizeImageCaptcha(payload) { +export async function recognizeImageCaptcha(payload: OcrRequestPayload): Promise { return callOcrViaHttp('recognize', payload) } -export async function batchRecognizeTencentCaptcha(payload) { +export async function batchRecognizeTencentCaptcha(payload: OcrRequestPayload): Promise { return callOcrViaHttp('batch', payload, { timeoutMs: 180_000 }) } -export async function warmupLocalOcrWorker() { +export async function warmupLocalOcrWorker(): Promise { await warmupOcrViaHttp() } -export async function closeLocalOcrWorker() { +export async function closeLocalOcrWorker(): Promise { // 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 { 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 { const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '') if (!baseUrl) { diff --git a/apps/backend/src/services/session/session-service-runtime.js b/apps/backend/src/services/session/session-service-runtime.ts similarity index 69% rename from apps/backend/src/services/session/session-service-runtime.js rename to apps/backend/src/services/session/session-service-runtime.ts index 8cdba2e0..22e6ab17 100644 --- a/apps/backend/src/services/session/session-service-runtime.js +++ b/apps/backend/src/services/session/session-service-runtime.ts @@ -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 + newContext: (options?: Record) => Promise +} + +type SessionServiceErrorOptions = { + statusCode?: number + errorCode?: string +} + +let browserPromise: Promise | 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 { if (!browserPromise) { const launchOptions = resolveBrowserLaunchOptions() - browserPromise = chromium.launch(buildChromiumLaunchOptions(launchOptions)) + browserPromise = (chromium.launch(buildChromiumLaunchOptions(launchOptions)) as Promise) .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 { if (activeSessionCount > 0 || !browserPromise) { return } @@ -85,6 +97,6 @@ export async function closeBrowserIfIdle({ activeSessionCount = 0 } = {}) { } } -function buildChromiumLaunchOptions(launchOptions) { +function buildChromiumLaunchOptions(launchOptions: ReturnType) { return buildChromiumLaunchOptionsBase(launchOptions, { chromePath: CHROME_PATH }) } diff --git a/docs/backend-typescript-migration-plan.md b/docs/backend-typescript-migration-plan.md index 9c385db8..a2aea982 100644 --- a/docs/backend-typescript-migration-plan.md +++ b/docs/backend-typescript-migration-plan.md @@ -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 个用例通过 ## 下一步建议