后端迁移会话存储模块
This commit is contained in:
+60
-15
@@ -1,5 +1,3 @@
|
||||
// @ts-check
|
||||
|
||||
import crypto from 'node:crypto'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
@@ -14,9 +12,53 @@ import {
|
||||
SESSION_TTL_MS,
|
||||
} 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 sessionDir = path.join(DATA_ROOT, sessionId)
|
||||
await fs.mkdir(sessionDir, { recursive: true })
|
||||
@@ -49,11 +91,11 @@ export async function registerTencentBrowserSession({ loginType, browserContext,
|
||||
return session
|
||||
}
|
||||
|
||||
export function listActiveTencentBrowserSessions() {
|
||||
export function listActiveTencentBrowserSessions(): TencentBrowserSession[] {
|
||||
return [...sessions.values()]
|
||||
}
|
||||
|
||||
export async function getRequiredSession(sessionId) {
|
||||
export async function getRequiredSession(sessionId: unknown): Promise<TencentBrowserSession> {
|
||||
const key = String(sessionId || '').trim()
|
||||
|
||||
if (!key) {
|
||||
@@ -75,12 +117,12 @@ export async function getRequiredSession(sessionId) {
|
||||
return session
|
||||
}
|
||||
|
||||
export function applyInitialQrSessionState(session) {
|
||||
export function applyInitialQrSessionState(session: TencentBrowserSession): void {
|
||||
resetTencentSessionAutoClose(session)
|
||||
Object.assign(session, resolveInitialQrSessionState(session.loginType))
|
||||
}
|
||||
|
||||
export function armRedeemedSessionAutoClose(session, { closeSession }) {
|
||||
export function armRedeemedSessionAutoClose(session: TencentBrowserSession, { closeSession }: CloseSessionDependency): void {
|
||||
resetTencentSessionAutoClose(session)
|
||||
|
||||
const autoCloseAt = Date.now() + REDEEM_SUCCESS_AUTO_CLOSE_MS
|
||||
@@ -93,7 +135,7 @@ export function armRedeemedSessionAutoClose(session, { closeSession }) {
|
||||
}, REDEEM_SUCCESS_AUTO_CLOSE_MS)
|
||||
}
|
||||
|
||||
export function resetTencentSessionAutoClose(session) {
|
||||
export function resetTencentSessionAutoClose(session?: TencentBrowserSession | null): void {
|
||||
if (session?.autoCloseTimer) {
|
||||
clearTimeout(session.autoCloseTimer)
|
||||
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())
|
||||
|
||||
await Promise.all(expired.map((session) => closeSession(session, { markClosed: false })))
|
||||
}
|
||||
|
||||
export async function closeSession(
|
||||
session,
|
||||
session: TencentBrowserSession,
|
||||
{
|
||||
markClosed,
|
||||
persistSessionState,
|
||||
closeBrowserIfIdle,
|
||||
},
|
||||
) {
|
||||
}: CloseSessionOptions,
|
||||
): Promise<void> {
|
||||
resetTencentSessionAutoClose(session)
|
||||
sessions.delete(session.sessionId)
|
||||
|
||||
@@ -139,7 +181,10 @@ export async function closeSession(
|
||||
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.writeFile(
|
||||
path.join(session.sessionDir, 'session.json'),
|
||||
@@ -148,7 +193,7 @@ export async function persistSessionState(session, { buildSessionPayload }) {
|
||||
)
|
||||
}
|
||||
|
||||
function createSessionId() {
|
||||
function createSessionId(): string {
|
||||
let sessionId = ''
|
||||
|
||||
do {
|
||||
@@ -456,6 +456,14 @@
|
||||
- `npm run typecheck`
|
||||
- `npm run build`
|
||||
- `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 个用例通过
|
||||
|
||||
## 下一步建议
|
||||
|
||||
|
||||
Reference in New Issue
Block a user