后端迁移会话存储模块

This commit is contained in:
yml
2026-05-21 15:28:32 +08:00
parent b86d7e8974
commit 3176880b2e
2 changed files with 68 additions and 15 deletions
@@ -1,5 +1,3 @@
// @ts-check
import crypto from 'node:crypto' import crypto from 'node:crypto'
import fs from 'node:fs/promises' import fs from 'node:fs/promises'
import path from 'node:path' import path from 'node:path'
@@ -14,9 +12,53 @@ import {
SESSION_TTL_MS, SESSION_TTL_MS,
} from './session-state.js' } from './session-state.js'
const sessions = new Map() type BrowserContextLike = {
close?: () => Promise<void>
}
export async function registerTencentBrowserSession({ loginType, browserContext, page }) { export type TencentBrowserSession = Record<string, any> & {
sessionId: string
loginType: string
status: string
notice: string
createdAt: string
updatedAt: string
expiresAt: number
autoCloseAt: number
autoCloseTimer: ReturnType<typeof setTimeout> | null
sessionDir: string
browserContext?: BrowserContextLike | null
page?: unknown
browserContextClosed?: boolean
}
type RegisterSessionInput = {
loginType: string
browserContext: BrowserContextLike
page: unknown
}
type CloseSessionDependency = {
closeSession: (session: TencentBrowserSession, options: { markClosed: boolean }) => Promise<void>
}
type CloseSessionOptions = {
markClosed: boolean
persistSessionState: (session: TencentBrowserSession) => Promise<unknown>
closeBrowserIfIdle: () => Promise<unknown>
}
type PersistSessionStateOptions = {
buildSessionPayload: (session: TencentBrowserSession) => unknown
}
const sessions = new Map<string, TencentBrowserSession>()
export async function registerTencentBrowserSession({
loginType,
browserContext,
page,
}: RegisterSessionInput): Promise<TencentBrowserSession> {
const sessionId = createSessionId() const sessionId = createSessionId()
const sessionDir = path.join(DATA_ROOT, sessionId) const sessionDir = path.join(DATA_ROOT, sessionId)
await fs.mkdir(sessionDir, { recursive: true }) await fs.mkdir(sessionDir, { recursive: true })
@@ -49,11 +91,11 @@ export async function registerTencentBrowserSession({ loginType, browserContext,
return session return session
} }
export function listActiveTencentBrowserSessions() { export function listActiveTencentBrowserSessions(): TencentBrowserSession[] {
return [...sessions.values()] return [...sessions.values()]
} }
export async function getRequiredSession(sessionId) { export async function getRequiredSession(sessionId: unknown): Promise<TencentBrowserSession> {
const key = String(sessionId || '').trim() const key = String(sessionId || '').trim()
if (!key) { if (!key) {
@@ -75,12 +117,12 @@ export async function getRequiredSession(sessionId) {
return session return session
} }
export function applyInitialQrSessionState(session) { export function applyInitialQrSessionState(session: TencentBrowserSession): void {
resetTencentSessionAutoClose(session) resetTencentSessionAutoClose(session)
Object.assign(session, resolveInitialQrSessionState(session.loginType)) Object.assign(session, resolveInitialQrSessionState(session.loginType))
} }
export function armRedeemedSessionAutoClose(session, { closeSession }) { export function armRedeemedSessionAutoClose(session: TencentBrowserSession, { closeSession }: CloseSessionDependency): void {
resetTencentSessionAutoClose(session) resetTencentSessionAutoClose(session)
const autoCloseAt = Date.now() + REDEEM_SUCCESS_AUTO_CLOSE_MS const autoCloseAt = Date.now() + REDEEM_SUCCESS_AUTO_CLOSE_MS
@@ -93,7 +135,7 @@ export function armRedeemedSessionAutoClose(session, { closeSession }) {
}, REDEEM_SUCCESS_AUTO_CLOSE_MS) }, REDEEM_SUCCESS_AUTO_CLOSE_MS)
} }
export function resetTencentSessionAutoClose(session) { export function resetTencentSessionAutoClose(session?: TencentBrowserSession | null): void {
if (session?.autoCloseTimer) { if (session?.autoCloseTimer) {
clearTimeout(session.autoCloseTimer) clearTimeout(session.autoCloseTimer)
session.autoCloseTimer = null session.autoCloseTimer = null
@@ -104,20 +146,20 @@ export function resetTencentSessionAutoClose(session) {
} }
} }
export async function cleanupExpiredTencentBrowserSessions({ closeSession }) { export async function cleanupExpiredTencentBrowserSessions({ closeSession }: CloseSessionDependency): Promise<void> {
const expired = listActiveTencentBrowserSessions().filter((session) => session.expiresAt <= Date.now()) const expired = listActiveTencentBrowserSessions().filter((session) => session.expiresAt <= Date.now())
await Promise.all(expired.map((session) => closeSession(session, { markClosed: false }))) await Promise.all(expired.map((session) => closeSession(session, { markClosed: false })))
} }
export async function closeSession( export async function closeSession(
session, session: TencentBrowserSession,
{ {
markClosed, markClosed,
persistSessionState, persistSessionState,
closeBrowserIfIdle, closeBrowserIfIdle,
}, }: CloseSessionOptions,
) { ): Promise<void> {
resetTencentSessionAutoClose(session) resetTencentSessionAutoClose(session)
sessions.delete(session.sessionId) sessions.delete(session.sessionId)
@@ -139,7 +181,10 @@ export async function closeSession(
await closeBrowserIfIdle() await closeBrowserIfIdle()
} }
export async function persistSessionState(session, { buildSessionPayload }) { export async function persistSessionState(
session: TencentBrowserSession,
{ buildSessionPayload }: PersistSessionStateOptions,
): Promise<void> {
await fs.mkdir(session.sessionDir, { recursive: true }) await fs.mkdir(session.sessionDir, { recursive: true })
await fs.writeFile( await fs.writeFile(
path.join(session.sessionDir, 'session.json'), path.join(session.sessionDir, 'session.json'),
@@ -148,7 +193,7 @@ export async function persistSessionState(session, { buildSessionPayload }) {
) )
} }
function createSessionId() { function createSessionId(): string {
let sessionId = '' let sessionId = ''
do { do {
@@ -456,6 +456,14 @@
- `npm run typecheck` - `npm run typecheck`
- `npm run build` - `npm run build`
- `npm test` 共 139 个用例通过 - `npm test` 共 139 个用例通过
92. 腾讯浏览器会话内存 store 模块迁移到 `.ts`
- `src/services/session/session-service-store.ts`
93. 浏览器会话对象、注册入参、关闭依赖、自动关闭 timer、session 状态持久化 payload 已显式类型化
94. Docker 内验证通过:
- `src/services/session/session.test.js` 共 14 个用例通过
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
## 下一步建议 ## 下一步建议