拆分兑换凭证纯函数与结果写入

This commit is contained in:
yml
2026-05-04 13:19:05 +08:00
parent 58f25fad74
commit 37c9dfd119
7 changed files with 467 additions and 89 deletions
@@ -0,0 +1,9 @@
export const BAIDU_BEIJING_TIME_URL = 'https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%8C%97%E4%BA%AC%E6%97%B6%E9%97%B4&fenlei=256&rsv_pq=0xa7d529b30000a6eb&rsv_t=2d404COdLspTa8jnKQl%2FyCU%2BSCmRyb%2BvSqxxjk%2B7E1scokLYTuDbehaQ0Dvq&rqlang=en&rsv_enter=1&rsv_dl=ih_0&rsv_sug3=1&rsv_sug1=1&rsv_sug7=001&rsv_sug2=1&rsv_btype=i&rsp=0&rsv_sug9=es_2_1&rsv_sug=1'
export const BEIJING_TIME_PROOF_VIEWPORT = { width: 1440, height: 860 }
export const BEIJING_TIME_PROOF_CLIP = {
x: 0,
y: 0,
width: BEIJING_TIME_PROOF_VIEWPORT.width,
height: 620,
}
export const DEFAULT_REDEEM_PROOF_MODE = 'full'
@@ -0,0 +1,30 @@
// @ts-nocheck
import { runtimeConfig } from '../../config/runtime.js'
import { DEFAULT_REDEEM_PROOF_MODE } from './session-proof-constants.js'
export function resolveRedeemProofMode(rawMode = runtimeConfig.redeem.proofMode) {
const normalized = String(rawMode || '')
.trim()
.toLowerCase()
if (normalized === 'basic' || normalized === 'off') {
return normalized
}
return DEFAULT_REDEEM_PROOF_MODE
}
export function shouldCaptureBeijingTimeProof(finalResult) {
if (finalResult?.classification?.success === true) {
return true
}
if (finalResult?.classification?.success === false) {
return false
}
const retCode = Number(finalResult?.redeem?.iRet ?? finalResult?.redeem?.ret)
return Number.isFinite(retCode) && retCode === 0
}
@@ -0,0 +1,11 @@
import path from 'node:path'
export function buildArtifactPaths(outputDir) {
return {
redeemPageScreenshotPath: path.join(outputDir, 'redeem-page.png'),
beijingTimeScreenshotPath: path.join(outputDir, 'beijing-time.png'),
screenshotPath: path.join(outputDir, 'redeem-result.png'),
htmlPath: path.join(outputDir, 'page.html'),
resultPath: path.join(outputDir, 'result.json'),
}
}
@@ -0,0 +1,47 @@
// @ts-nocheck
import fs from 'node:fs/promises'
import { BAIDU_BEIJING_TIME_URL } from './session-proof-constants.js'
export async function writeRedeemResultFile(
resultPath,
{
proofMode,
sessionId,
activityUrl,
code,
finalResult,
attempts,
screenshotPath,
htmlPath = '',
redeemPageScreenshotPath = '',
beijingTimeScreenshotPath = '',
beijingTimePageUrl = BAIDU_BEIJING_TIME_URL,
beijingTimeError = '',
},
) {
await fs.writeFile(
resultPath,
JSON.stringify(
{
proofMode,
sessionId,
activityUrl,
code,
area: finalResult?.role?.area || '',
final: finalResult,
attempts,
redeemPageScreenshotPath,
beijingTimeScreenshotPath,
beijingTimePageUrl,
beijingTimeError,
screenshotPath,
htmlPath,
},
null,
2,
),
'utf8',
)
}
@@ -1,19 +1,16 @@
// @ts-nocheck
import fs from 'node:fs/promises'
import path from 'node:path'
import { runtimeConfig } from '../../config/runtime.js'
const BAIDU_BEIJING_TIME_URL = 'https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%8C%97%E4%BA%AC%E6%97%B6%E9%97%B4&fenlei=256&rsv_pq=0xa7d529b30000a6eb&rsv_t=2d404COdLspTa8jnKQl%2FyCU%2BSCmRyb%2BvSqxxjk%2B7E1scokLYTuDbehaQ0Dvq&rqlang=en&rsv_enter=1&rsv_dl=ih_0&rsv_sug3=1&rsv_sug1=1&rsv_sug7=001&rsv_sug2=1&rsv_btype=i&rsp=0&rsv_sug9=es_2_1&rsv_sug=1'
const BEIJING_TIME_PROOF_VIEWPORT = { width: 1440, height: 860 }
const BEIJING_TIME_PROOF_CLIP = {
x: 0,
y: 0,
width: BEIJING_TIME_PROOF_VIEWPORT.width,
height: 620,
}
const DEFAULT_REDEEM_PROOF_MODE = 'full'
import {
BAIDU_BEIJING_TIME_URL,
BEIJING_TIME_PROOF_CLIP,
BEIJING_TIME_PROOF_VIEWPORT,
DEFAULT_REDEEM_PROOF_MODE,
} from './session-proof-constants.js'
import { resolveRedeemProofMode, shouldCaptureBeijingTimeProof } from './session-proof-mode.js'
import { buildArtifactPaths } from './session-proof-paths.js'
import { writeRedeemResultFile } from './session-proof-result-writer.js'
export async function saveRedeemArtifacts({
browserContext,
@@ -145,82 +142,7 @@ export async function writeRedeemArtifactFiles({
}
}
export function resolveRedeemProofMode(rawMode = runtimeConfig.redeem.proofMode) {
const normalized = String(rawMode || '')
.trim()
.toLowerCase()
if (normalized === 'basic' || normalized === 'off') {
return normalized
}
return DEFAULT_REDEEM_PROOF_MODE
}
export function shouldCaptureBeijingTimeProof(finalResult) {
if (finalResult?.classification?.success === true) {
return true
}
if (finalResult?.classification?.success === false) {
return false
}
const retCode = Number(finalResult?.redeem?.iRet ?? finalResult?.redeem?.ret)
return Number.isFinite(retCode) && retCode === 0
}
function buildArtifactPaths(outputDir) {
return {
redeemPageScreenshotPath: path.join(outputDir, 'redeem-page.png'),
beijingTimeScreenshotPath: path.join(outputDir, 'beijing-time.png'),
screenshotPath: path.join(outputDir, 'redeem-result.png'),
htmlPath: path.join(outputDir, 'page.html'),
resultPath: path.join(outputDir, 'result.json'),
}
}
async function writeRedeemResultFile(
resultPath,
{
proofMode,
sessionId,
activityUrl,
code,
finalResult,
attempts,
screenshotPath,
htmlPath = '',
redeemPageScreenshotPath = '',
beijingTimeScreenshotPath = '',
beijingTimePageUrl = BAIDU_BEIJING_TIME_URL,
beijingTimeError = '',
},
) {
await fs.writeFile(
resultPath,
JSON.stringify(
{
proofMode,
sessionId,
activityUrl,
code,
area: finalResult?.role?.area || '',
final: finalResult,
attempts,
redeemPageScreenshotPath,
beijingTimeScreenshotPath,
beijingTimePageUrl,
beijingTimeError,
screenshotPath,
htmlPath,
},
null,
2,
),
'utf8',
)
}
export { resolveRedeemProofMode, shouldCaptureBeijingTimeProof }
async function showResultDialog(page, message) {
await page.evaluate((text) => {
@@ -1,7 +1,17 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import path from 'node:path'
import { shouldCaptureBeijingTimeProof } from './session-proof.js'
import { resolveRedeemProofMode, shouldCaptureBeijingTimeProof } from './session-proof.js'
import { buildArtifactPaths } from './session-proof-paths.js'
test('resolveRedeemProofMode normalizes configured modes and falls back to full', () => {
assert.equal(resolveRedeemProofMode('basic'), 'basic')
assert.equal(resolveRedeemProofMode(' OFF '), 'off')
assert.equal(resolveRedeemProofMode('full'), 'full')
assert.equal(resolveRedeemProofMode('unexpected'), 'full')
assert.equal(resolveRedeemProofMode(''), 'full')
})
test('shouldCaptureBeijingTimeProof only returns true for successful redeem results', () => {
assert.equal(
@@ -42,3 +52,13 @@ test('shouldCaptureBeijingTimeProof only returns true for successful redeem resu
assert.equal(shouldCaptureBeijingTimeProof(null), false)
})
test('buildArtifactPaths keeps redeem proof artifact filenames stable', () => {
const artifactPaths = buildArtifactPaths('/tmp/redeem-proof')
assert.equal(artifactPaths.redeemPageScreenshotPath, path.join('/tmp/redeem-proof', 'redeem-page.png'))
assert.equal(artifactPaths.beijingTimeScreenshotPath, path.join('/tmp/redeem-proof', 'beijing-time.png'))
assert.equal(artifactPaths.screenshotPath, path.join('/tmp/redeem-proof', 'redeem-result.png'))
assert.equal(artifactPaths.htmlPath, path.join('/tmp/redeem-proof', 'page.html'))
assert.equal(artifactPaths.resultPath, path.join('/tmp/redeem-proof', 'result.json'))
})