diff --git a/backend-integration/nginx-api-proxy.conf b/backend-integration/nginx-api-proxy.conf index 2527dd67..e24eeabe 100644 --- a/backend-integration/nginx-api-proxy.conf +++ b/backend-integration/nginx-api-proxy.conf @@ -22,6 +22,16 @@ location /api/ps/ { proxy_read_timeout 90s; } +# Webhook 路由 → 后端服务端口 3000(飞书事件回调、广播推送等) +location /webhook/ { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Content-Type $content_type; +} + # API 代理转发(通用 AI 聊天) location /api/ { proxy_pass http://127.0.0.1:3721; diff --git a/backend/routes/feishu-bot.js b/backend/routes/feishu-bot.js index 5936123a..ef5ecd34 100644 --- a/backend/routes/feishu-bot.js +++ b/backend/routes/feishu-bot.js @@ -410,6 +410,71 @@ router.post('/alert', async (req, res) => { } }); +// ══════════════════════════════════════════════════════════ +// 广播推送(Pipeline C 调用) +// ══════════════════════════════════════════════════════════ + +/** + * 接收 Pipeline C 的广播推送请求,转发到飞书聊天窗口 + * POST /push-broadcast (通过 server.js 映射到 /webhook/push-broadcast) + */ +router.post('/push-broadcast', async (req, res) => { + // 1. 验证 token + const token = req.headers['x-push-token']; + if (!process.env.PUSH_BROADCAST_TOKEN || token !== process.env.PUSH_BROADCAST_TOKEN) { + return res.status(401).json({ error: true, code: 'INVALID_TOKEN', message: 'Invalid push token' }); + } + + // 2. 解析请求体 + const { chat_id, sender_open_id, broadcast_title, broadcast_content, broadcast_url } = req.body; + + if (!broadcast_content && !broadcast_title) { + return res.status(400).json({ error: true, code: 'MISSING_CONTENT', message: 'Missing broadcast_title or broadcast_content' }); + } + + const receive_id = chat_id || sender_open_id; + if (!receive_id) { + return res.status(400).json({ error: true, code: 'MISSING_TARGET', message: 'Missing chat_id or sender_open_id' }); + } + + try { + // 3. 获取飞书 token + const feishuToken = await getFeishuToken(); + + // 4. 构造消息文本 + const urlLine = broadcast_url ? '\n🔗 ' + broadcast_url : ''; + const text = '📡 新广播 ' + (broadcast_title || '') + '\n\n' + (broadcast_content || '') + urlLine; + + // 5. 发送飞书消息(优先 chat_id,备选 open_id) + const receive_id_type = chat_id ? 'chat_id' : 'open_id'; + const msgResult = await httpsRequest({ + hostname: 'open.feishu.cn', + port: 443, + path: '/open-apis/im/v1/messages?receive_id_type=' + receive_id_type, + method: 'POST', + headers: { + 'Authorization': 'Bearer ' + feishuToken, + 'Content-Type': 'application/json', + }, + }, { + receive_id: receive_id, + msg_type: 'text', + content: JSON.stringify({ text }), + }); + + if (msgResult.data && msgResult.data.code === 0) { + console.log('✅ 广播推送成功: ' + broadcast_title + ' → ' + receive_id); + res.json({ success: true, message_id: msgResult.data.data && msgResult.data.data.message_id }); + } else { + console.error('❌ 飞书发送失败:', JSON.stringify(msgResult.data)); + res.status(500).json({ error: true, code: 'FEISHU_API_ERROR', message: (msgResult.data && msgResult.data.msg) || 'Feishu API error' }); + } + } catch (err) { + console.error('❌ push-broadcast error:', err.message); + res.status(500).json({ error: true, code: 'PUSH_ERROR', message: err.message }); + } +}); + // ══════════════════════════════════════════════════════════ // 健康检查 + 统计 // ══════════════════════════════════════════════════════════ @@ -424,6 +489,7 @@ router.get('/health', (req, res) => { ai_chat: !!process.env.MODEL_API_KEY, collaboration_logging: true, failure_alerting: !!ALERT_CHAT_ID, + push_broadcast: !!process.env.PUSH_BROADCAST_TOKEN, }, github_token_configured: !!GITHUB_TOKEN, feishu_app_configured: !!(FEISHU_APP_ID && FEISHU_APP_SECRET), diff --git a/backend/server.js b/backend/server.js index 3637c1fd..3d799196 100644 --- a/backend/server.js +++ b/backend/server.js @@ -32,6 +32,12 @@ app.get('/', (req, res) => { }); }); +// Pipeline C 广播推送 webhook → 转发到 feishu-bot 路由 +app.post('/webhook/push-broadcast', (req, res, next) => { + req.url = '/push-broadcast'; + feishuBotRoutes(req, res, next); +}); + const PORT = process.env.PORT || 3000; // 飞书 Webhook 处理(旧版兼容入口,新事件请使用 /feishu-bot/event) app.post('/webhook/feishu', (req, res) => {