优化支付耗时和日志
This commit is contained in:
@@ -23,7 +23,7 @@ const htmlPath = getArg('--html');
|
||||
const goodsUrl = getArg('--goods-url');
|
||||
const cookiePath = getArg('--cookies');
|
||||
const outputPath = getArg('--output');
|
||||
const waitMs = Number.parseInt(getArg('--wait', '12000'), 10);
|
||||
const waitMs = Number.parseInt(getArg('--wait', '5000'), 10);
|
||||
const useArchivedAssets = argv.includes('--archived-assets');
|
||||
|
||||
function fail(message) {
|
||||
@@ -61,8 +61,18 @@ class GoodsLoader extends ResourceLoader {
|
||||
|
||||
const session = cookiePath ? JSON.parse(fs.readFileSync(cookiePath, 'utf8')) : {};
|
||||
const cookies = session.cookies || {};
|
||||
const captured = [];
|
||||
const resourceErrors = [];
|
||||
let capturedFp = null;
|
||||
let resolveFpCapture = null;
|
||||
const startedAt = Date.now();
|
||||
|
||||
function captureFp(url, body) {
|
||||
const values = Object.fromEntries(new URLSearchParams(body));
|
||||
if (!values.SessionID || !values.DeviceFP) return;
|
||||
capturedFp = { url, body };
|
||||
if (resolveFpCapture) resolveFpCapture();
|
||||
}
|
||||
|
||||
const dom = new JSDOM(fs.readFileSync(htmlPath, 'utf8'), {
|
||||
url: goodsUrl,
|
||||
referrer: 'https://z.iwan.yyb.qq.com/',
|
||||
@@ -88,7 +98,7 @@ const dom = new JSDOM(fs.readFileSync(htmlPath, 'utf8'), {
|
||||
send(body) {
|
||||
const requestBody = String(body || '');
|
||||
if (this.__yybUrl.includes('fp-behv.fcg')) {
|
||||
captured.push({ url: this.__yybUrl, body: requestBody });
|
||||
captureFp(this.__yybUrl, requestBody);
|
||||
}
|
||||
this.readyState = 4;
|
||||
this.status = 200;
|
||||
@@ -103,18 +113,23 @@ const dom = new JSDOM(fs.readFileSync(htmlPath, 'utf8'), {
|
||||
},
|
||||
});
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, Number.isFinite(waitMs) ? waitMs : 12000));
|
||||
const fp = captured.at(-1);
|
||||
if (!fp) {
|
||||
const timeoutMs = Number.isFinite(waitMs) && waitMs > 0 ? waitMs : 5000;
|
||||
let timeoutId;
|
||||
await Promise.race([
|
||||
new Promise(resolve => {
|
||||
resolveFpCapture = resolve;
|
||||
if (capturedFp) resolve();
|
||||
}),
|
||||
new Promise(resolve => { timeoutId = setTimeout(resolve, timeoutMs); }),
|
||||
]);
|
||||
clearTimeout(timeoutId);
|
||||
if (!capturedFp) {
|
||||
dom.window.close();
|
||||
fail(`未生成 fp-behv;加载错误: ${resourceErrors.slice(0, 3).join(' | ') || '无'}`);
|
||||
}
|
||||
|
||||
const fp = capturedFp;
|
||||
const values = Object.fromEntries(new URLSearchParams(fp.body));
|
||||
if (!values.SessionID || !values.DeviceFP) {
|
||||
dom.window.close();
|
||||
fail('fp-behv 缺少 SessionID 或 DeviceFP');
|
||||
}
|
||||
const result = {
|
||||
generated_at: new Date().toISOString(),
|
||||
goods_url: goodsUrl,
|
||||
@@ -130,3 +145,4 @@ dom.window.close();
|
||||
console.log(`DeviceFP 已保存: ${outputPath}`);
|
||||
console.log(`SessionID: ${result.session_id}`);
|
||||
console.log(`DeviceFP 长度: ${result.device_fp_length}`);
|
||||
console.log(`DeviceFP 捕获耗时: ${Date.now() - startedAt}ms`);
|
||||
|
||||
@@ -375,7 +375,7 @@ def main() -> int:
|
||||
parser.add_argument("--mall-response", default=str(ROOT / "config/mall-order-response.json"))
|
||||
parser.add_argument("--out-dir", default=None, help="运行证据目录;默认 config/jsdom-order-<timestamp>")
|
||||
parser.add_argument("--qr", default=None, help="付款二维码 PNG 路径")
|
||||
parser.add_argument("--wait", type=int, default=12, help="jsdom 等待 DeviceFP 的秒数")
|
||||
parser.add_argument("--wait", type=int, default=5, help="jsdom 等待 DeviceFP 的秒数")
|
||||
parser.add_argument("--zone-id", default="1", help="所选游戏区服 ID")
|
||||
parser.add_argument("--pf", default="", help="所选 Android/iOS 支付平台标识")
|
||||
parser.add_argument("--amount-fen", type=int, default=0, help="所选点券的价格,单位分(check-only 模式不需要)")
|
||||
|
||||
@@ -61,8 +61,9 @@ def _safe_log(job: dict, line: str) -> None:
|
||||
clean = re.sub(r"(?:token|openid|openkey|cookie)=\S+", "[敏感字段已隐藏]", clean, flags=re.I)
|
||||
clean = re.sub(r"(?:pay_token|web_token|anti_token|session_id|sessionid)\s*[:= ]\s*\S+",
|
||||
"[敏感字段已隐藏]", clean, flags=re.I)
|
||||
timestamp = time.strftime("%H:%M:%S")
|
||||
with _lock:
|
||||
job["logs"] = (job.get("logs", []) + [clean.strip()])[-100:]
|
||||
job["logs"] = (job.get("logs", []) + [f"[{timestamp}] {clean.strip()}"])[-100:]
|
||||
|
||||
|
||||
def _run_process(job_id: str, command: list[str], phase: str, mark_success: bool = True) -> int:
|
||||
@@ -79,6 +80,8 @@ def _run_process(job_id: str, command: list[str], phase: str, mark_success: bool
|
||||
with _lock:
|
||||
job["phase"] = phase
|
||||
job["status"] = "running"
|
||||
stage_started = time.monotonic()
|
||||
_safe_log(job, f"[{phase}] 开始执行")
|
||||
try:
|
||||
process = subprocess.Popen(command, cwd=ROOT, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, text=True,
|
||||
@@ -89,6 +92,7 @@ def _run_process(job_id: str, command: list[str], phase: str, mark_success: bool
|
||||
for line in process.stdout:
|
||||
_safe_log(job, line)
|
||||
code = process.wait()
|
||||
_safe_log(job, f"[{phase}] 执行结束,耗时 {time.monotonic() - stage_started:.1f} 秒")
|
||||
with _lock:
|
||||
job["process_pid"] = None
|
||||
if code != 0:
|
||||
@@ -109,6 +113,7 @@ def _run_process(job_id: str, command: list[str], phase: str, mark_success: bool
|
||||
job["message"] = "付款流程已完成"
|
||||
return code
|
||||
except Exception as exc: # noqa: BLE001
|
||||
_safe_log(job, f"[{phase}] 执行异常,耗时 {time.monotonic() - stage_started:.1f} 秒")
|
||||
with _lock:
|
||||
job["status"] = "failed"
|
||||
job["message"] = str(exc)
|
||||
@@ -189,10 +194,13 @@ def _check_payment_once(job_id: str) -> int:
|
||||
"--out-dir", str(directory / "jsdom-order")]
|
||||
environment = os.environ.copy()
|
||||
environment.pop("NODE_OPTIONS", None)
|
||||
check_started = time.monotonic()
|
||||
_safe_log(job, "[到账检测] 开始执行")
|
||||
try:
|
||||
result = subprocess.run(command, cwd=ROOT, capture_output=True, text=True,
|
||||
env=environment, timeout=90)
|
||||
except subprocess.TimeoutExpired:
|
||||
_safe_log(job, f"[到账检测] 执行超时,耗时 {time.monotonic() - check_started:.1f} 秒")
|
||||
with _lock:
|
||||
job["payment_last_checked_at"] = int(time.time())
|
||||
return 2
|
||||
@@ -200,6 +208,7 @@ def _check_payment_once(job_id: str) -> int:
|
||||
_safe_log(job, line)
|
||||
for line in (result.stderr or "").splitlines():
|
||||
_safe_log(job, line)
|
||||
_safe_log(job, f"[到账检测] 执行结束,耗时 {time.monotonic() - check_started:.1f} 秒")
|
||||
with _lock:
|
||||
job["payment_last_checked_at"] = int(time.time())
|
||||
return result.returncode
|
||||
|
||||
Reference in New Issue
Block a user