#!/usr/bin/env node /** * 好友轮询兜底 Worker * * 独立运行,定期检查已加好友但尚未建群的客户,触发自动建群。 * * 启动方式: * node scripts/friend-polling-worker.js * INTERVAL_MS=300000 node scripts/friend-polling-worker.js */ const fs = require('fs'); const path = require('path'); const { outputsRoot } = require('../mcp/src/core/output-paths'); const { readCustomerById, writeCustomer } = require('../mcp/src/core/customer-broker-store'); const { readConfirmedMapping } = require('../mcp/src/core/webhook-processor'); const { triggerAutoCreateGroup } = require('../mcp/src/core/webhook-processor'); const INTERVAL_MS = Number(process.env.FRIEND_POLL_INTERVAL_MS || 300000); function customersDir() { return path.join(outputsRoot(), 'customers'); } function safeReadJson(filePath) { try { if (!fs.existsSync(filePath)) return null; return JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch { return null; } } function listCustomerFiles() { const dir = customersDir(); if (!fs.existsSync(dir)) return []; return fs.readdirSync(dir) .filter(f => f.endsWith('.json') && !f.startsWith('index-')) .map(f => path.join(dir, f)); } function hasActiveGroupForCustomer(customerId) { const mapping = readConfirmedMapping(); for (const entry of Object.values(mapping)) { if (entry.customerId === customerId && entry.status === 'ACTIVE') return true; } return false; } async function runOnce() { const files = listCustomerFiles(); let checked = 0; let created = 0; let ignored = 0; let errors = 0; for (const file of files) { const customer = safeReadJson(file); if (!customer || !customer.customerId) continue; // 只处理有 brokerId 且标记为已通过好友但尚未建群的客户 if (!customer.brokerId) continue; if (customer.friendRequestStatus !== 'ACCEPTED' && customer.friendRequestStatus !== 'PENDING') continue; if (hasActiveGroupForCustomer(customer.customerId)) continue; checked++; const event = { parsedType: 'CONTACT_ADDED_OR_CHANGED', msgType: 2131, externalUserId: customer.externalUserId, guid: undefined, timestamp: Math.floor(Date.now() / 1000), eventId: `poll-${customer.customerId}-${Date.now()}`, raw: {} }; const result = await triggerAutoCreateGroup(event); if (result.success) { created++; customer.friendRequestStatus = 'ACCEPTED'; writeCustomer(customer); } else if (result.ignored) { ignored++; } else { errors++; } } console.log(`[FriendPolling] 本轮完成: 检查 ${checked}, 建群 ${created}, 忽略 ${ignored}, 错误 ${errors}`); return { checked, created, ignored, errors }; } async function main() { console.log(`[FriendPolling] 启动,轮询间隔 ${INTERVAL_MS}ms`); while (true) { try { await runOnce(); } catch (err) { console.error('[FriendPolling] 本轮异常:', err.message); } await new Promise(resolve => setTimeout(resolve, INTERVAL_MS)); } } main().catch(err => { console.error('[FriendPolling] 致命错误:', err); process.exit(1); });