import WebSocket from 'ws'; import { appendFileSync } from 'fs'; const CDP_PORT = 18800; const COOKIE_VALUE = '3cfeb30b562daec31ba63bf64fdb3838'; const TARGET_URL = 'https://www.nodeseek.com'; const LOG_FILE = '/Users/jianzhang/.openclaw/workspace/scripts/checkin.log'; let msgId = 1; let pendingCallbacks = new Map(); let loadEventResolve = null; function log(message) { const timestamp = new Date().toISOString(); const logLine = `[${timestamp}] [VP404] ${message}\n`; console.log(logLine.trim()); try { appendFileSync(LOG_FILE, logLine); } catch (e) { console.error('Failed to write log:', e.message); } } async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function send(ws, method, params = {}) { return new Promise((resolve, reject) => { const id = msgId++; const msg = JSON.stringify({ id, method, params }); pendingCallbacks.set(id, { resolve, reject }); ws.send(msg); setTimeout(() => { if (pendingCallbacks.has(id)) { pendingCallbacks.delete(id); reject(new Error(`Timeout for ${method}`)); } }, 30000); }); } async function main() { log('开始 NodeSeek VP404 签到任务'); let ws; let targetId = null; try { // Step 1: Get browser WebSocket URL log('获取 CDP 连接信息...'); const resp = await fetch(`http://127.0.0.1:${CDP_PORT}/json/version`); const version = await resp.json(); const browserWsUrl = version.webSocketDebuggerUrl; log(`Browser WS: ${browserWsUrl}`); // Step 2: Connect to browser ws = new WebSocket(browserWsUrl); ws.on('message', (data) => { try { const msg = JSON.parse(data.toString()); if (msg.id && pendingCallbacks.has(msg.id)) { const { resolve, reject } = pendingCallbacks.get(msg.id); pendingCallbacks.delete(msg.id); if (msg.error) { reject(new Error(msg.error.message || JSON.stringify(msg.error))); } else { resolve(msg.result); } } if (msg.method === 'Page.loadEventFired' && loadEventResolve) { loadEventResolve(); loadEventResolve = null; } } catch (e) {} }); await new Promise((resolve, reject) => { ws.on('open', resolve); ws.on('error', reject); }); log('CDP 连接成功'); // Step 3: Create new target log('创建新标签页...'); const targetResult = await send(ws, 'Target.createTarget', { url: 'about:blank' }); targetId = targetResult.targetId; log(`Target ID: ${targetId}`); // Step 4: Get target's WebSocket URL via HTTP const targetsResp = await fetch(`http://127.0.0.1:${CDP_PORT}/json`); const targets = await targetsResp.json(); const pageTarget = targets.find(t => t.id === targetId); if (!pageTarget) { throw new Error('找不到创建的标签页'); } const pageWsUrl = pageTarget.webSocketDebuggerUrl; log(`Page WS: ${pageWsUrl}`); // Step 5: Close browser connection and connect to page ws.close(); await sleep(500); ws = new WebSocket(pageWsUrl); ws.on('message', (data) => { try { const msg = JSON.parse(data.toString()); if (msg.id && pendingCallbacks.has(msg.id)) { const { resolve, reject } = pendingCallbacks.get(msg.id); pendingCallbacks.delete(msg.id); if (msg.error) { reject(new Error(msg.error.message || JSON.stringify(msg.error))); } else { resolve(msg.result); } } if (msg.method === 'Page.loadEventFired' && loadEventResolve) { loadEventResolve(); loadEventResolve = null; } } catch (e) {} }); await new Promise((resolve, reject) => { ws.on('open', resolve); ws.on('error', reject); }); log('已连接到页面'); // Step 6: Enable domains await send(ws, 'Page.enable'); await send(ws, 'Network.enable'); // Step 7: Set cookie log('设置 Cookie...'); await send(ws, 'Network.setCookie', { name: '_nk', value: COOKIE_VALUE, domain: '.nodeseek.com', path: '/' }); log('Cookie 设置成功'); // Step 8: Navigate log('导航到 NodeSeek...'); const loadPromise = new Promise(resolve => { loadEventResolve = resolve; }); await send(ws, 'Page.navigate', { url: TARGET_URL }); log('等待页面加载...'); await loadPromise; log('页面加载完成'); // Step 9: Wait for stability log('等待 5 秒...'); await sleep(5000); // Step 10: Call attendance API log('调用签到 API...'); const evalResult = await send(ws, 'Runtime.evaluate', { expression: `fetch('/api/attendance',{ method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({random:true}) }).then(r => r.json()).catch(e => ({error: e.message}))`, returnByValue: true, awaitPromise: true }); const result = evalResult.result.value; log(`签到结果: ${JSON.stringify(result)}`); // Step 11: Close page log('关闭标签页...'); await send(ws, 'Page.close'); ws.close(); log('签到任务完成 ✓'); } catch (error) { log(`错误: ${error.message}`); if (ws && ws.readyState === WebSocket.OPEN) { try { ws.close(); } catch (e) {} } process.exit(1); } } main();