优化了qq微信切换

This commit is contained in:
yml2213
2026-04-13 21:48:23 +08:00
parent dc8a014601
commit bc0d6fc8aa
10 changed files with 453 additions and 67 deletions
@@ -1,8 +1,10 @@
import {
closeTencentBrowserSession,
createTencentBrowserSession,
getTencentBrowserSession,
getTencentBrowserSessionSummary,
getTencentBrowserSessionScreenshotPath,
reloadTencentBrowserSession,
redeemTencentBrowserSession,
} from '../session/session.js'
import { findClaimTokenByToken, getClaimTokenById, updateClaimToken } from '../../repositories/claim-token-repo.js'
@@ -24,8 +26,8 @@ const CLAIM_TERMINAL_STATUSES = new Set(['expired', 'closed'])
export async function getClaimDetail(token, { includeQrImage = true } = {}) {
const context = await getClaimContext(token)
const session = await loadTaskSession(context.task, { includeQrImage })
const syncedTask = session ? await syncTaskWithSession(context.task, session) : context.task
const { task, session } = await loadTaskSession(context.task, { includeQrImage })
const syncedTask = session ? await syncTaskWithSession(task, session) : task
return buildClaimDetailPayload({
claimToken: context.claimToken,
@@ -39,30 +41,54 @@ export async function getClaimDetail(token, { includeQrImage = true } = {}) {
export async function createClaimSession(token, payload = {}) {
const context = await getClaimContext(token)
assertTaskCanProceed(context.task)
const requestedLoginType = normalizeClaimLoginType(payload.loginType)
const forceRecreate = Boolean(payload.forceRecreate)
let task = context.task
if (context.task.browser_session_id) {
const existingSession = await getTencentBrowserSession(context.task.browser_session_id)
const syncedTask = await syncTaskWithSession(context.task, existingSession)
if (task.browser_session_id) {
const existing = await loadTaskSession(task, { includeQrImage: true })
task = existing.task
return buildClaimDetailPayload({
claimToken: context.claimToken,
task: syncedTask,
order: context.order,
orderItem: context.orderItem,
session: existingSession,
})
if (existing.session) {
const existingLoginType = normalizeClaimLoginType(existing.session.loginType || task.login_type)
if (!forceRecreate && existingLoginType === requestedLoginType) {
const syncedTask = await syncTaskWithSession(task, existing.session)
return buildClaimDetailPayload({
claimToken: context.claimToken,
task: syncedTask,
order: context.order,
orderItem: context.orderItem,
session: existing.session,
})
}
try {
await closeTencentBrowserSession(existing.session.sessionId)
} catch (error) {
if (!isRecoverableSessionError(error)) {
throw error
}
}
task = await clearTaskSession(task, {
lastError: '',
})
}
}
const session = await createTencentBrowserSession({
loginType: payload.loginType,
loginType: requestedLoginType,
})
const updatedTask = await updateTask(context.task.id, {
const updatedTask = await updateTask(task.id, {
task_status: 'claimed',
browser_session_id: session.sessionId,
login_type: session.loginType,
user_action_status: 'claimed',
claimed_at: context.task.claimed_at || nowIso(),
claimed_at: task.claimed_at || nowIso(),
updated_at: nowIso(),
last_error: '',
})
return buildClaimDetailPayload({
@@ -76,16 +102,21 @@ export async function createClaimSession(token, payload = {}) {
export async function getClaimSessionSummary(token) {
const context = await getClaimContext(token)
const { task, session } = await loadTaskSession(context.task, {
includeQrImage: false,
})
if (!context.task.browser_session_id) {
throw createHttpError('当前任务还没有创建浏览器会话', {
statusCode: 409,
errorCode: 'claim_session_not_created',
if (!session) {
return buildClaimDetailPayload({
claimToken: context.claimToken,
task,
order: context.order,
orderItem: context.orderItem,
session: null,
})
}
const session = await getTencentBrowserSession(context.task.browser_session_id)
const syncedTask = await syncTaskWithSession(context.task, session)
const syncedTask = await syncTaskWithSession(task, session)
return buildClaimDetailPayload({
claimToken: context.claimToken,
@@ -96,6 +127,72 @@ export async function getClaimSessionSummary(token) {
})
}
export async function reloadClaimSession(token) {
const context = await getClaimContext(token)
assertTaskCanProceed(context.task)
const active = await loadTaskSession(context.task, {
includeQrImage: true,
})
if (!active.session) {
return buildClaimDetailPayload({
claimToken: context.claimToken,
task: active.task,
order: context.order,
orderItem: context.orderItem,
session: null,
})
}
const session = await reloadTencentBrowserSession(active.session.sessionId)
const syncedTask = await syncTaskWithSession(active.task, session)
return buildClaimDetailPayload({
claimToken: context.claimToken,
task: syncedTask,
order: context.order,
orderItem: context.orderItem,
session,
})
}
export async function closeClaimSession(token) {
const context = await getClaimContext(token)
assertTaskCanProceed(context.task)
let task = context.task
if (!task.browser_session_id) {
return buildClaimDetailPayload({
claimToken: context.claimToken,
task,
order: context.order,
orderItem: context.orderItem,
session: null,
})
}
try {
await closeTencentBrowserSession(task.browser_session_id)
} catch (error) {
if (!isRecoverableSessionError(error)) {
throw error
}
}
task = await clearTaskSession(task, {
lastError: '',
})
return buildClaimDetailPayload({
claimToken: context.claimToken,
task,
order: context.order,
orderItem: context.orderItem,
session: null,
})
}
export async function confirmClaimRole(token) {
const context = await getClaimContext(token)
assertPublicClaimActionAllowed(context.task, 'confirm')
@@ -430,12 +527,35 @@ async function expireClaimContext(claimToken, task) {
async function loadTaskSession(task, { includeQrImage = false } = {}) {
if (!task.browser_session_id) {
return null
return {
task,
session: null,
}
}
return includeQrImage
? getTencentBrowserSession(task.browser_session_id)
: getTencentBrowserSessionSummary(task.browser_session_id)
try {
const session = includeQrImage
? await getTencentBrowserSession(task.browser_session_id)
: await getTencentBrowserSessionSummary(task.browser_session_id)
return {
task,
session,
}
} catch (error) {
if (!isRecoverableSessionError(error)) {
throw error
}
const nextTask = await clearTaskSession(task, {
lastError: '浏览器会话已失效,请重新初始化登录',
})
return {
task: nextTask,
session: null,
}
}
}
async function syncTaskWithSession(task, session) {
@@ -550,3 +670,36 @@ function parseTaskState(task) {
function isAssistedClaimTask(task) {
return String(task?.executor_key || '').trim() === 'tencent_claim_assisted'
}
async function clearTaskSession(task, { lastError = '' } = {}) {
const shouldResetClaimProgress = ['link_generated', 'claimed', 'role_confirmed'].includes(String(task.task_status || ''))
const nextTaskStatus = shouldResetClaimProgress ? 'link_generated' : task.task_status
const nextUserActionStatus = shouldResetClaimProgress ? 'pending_claim' : task.user_action_status
const patch = {
task_status: nextTaskStatus,
user_action_status: nextUserActionStatus,
browser_session_id: '',
login_type: '',
nickname: '',
role_id: '',
role_name: '',
area: '',
partition_name: '',
artifacts_json: '{}',
state_json: '{}',
role_confirmed_at: nextTaskStatus === 'link_generated' ? null : task.role_confirmed_at,
last_error: String(lastError || ''),
updated_at: nowIso(),
}
return updateTask(task.id, patch)
}
function normalizeClaimLoginType(loginType) {
return String(loginType || '').trim() === 'wx' ? 'wx' : 'qq'
}
function isRecoverableSessionError(error) {
const errorCode = String(error?.errorCode || error?.code || '').trim()
return errorCode === 'session_not_found' || errorCode === 'session_closed'
}