const http = require('http') const path = require('path') const fs = require('fs') const express = require('express') const cors = require('cors') const { WebSocketServer } = require('ws') const routes = require('./routes') const { getSituation } = require('./situationData') const app = express() const PORT = process.env.API_PORT || 3001 app.set('trust proxy', 1) app.use(cors()) app.use(express.json()) app.use('/api', routes) app.get('/api/health', (_, res) => res.json({ ok: true })) app.post('/api/crawler/notify', (_, res) => { notifyCrawlerUpdate() res.json({ ok: true }) }) // 生产环境:提供前端静态文件 const distPath = path.join(__dirname, '..', 'dist') if (fs.existsSync(distPath)) { app.use(express.static(distPath)) app.get('*', (req, res, next) => { if (!req.path.startsWith('/api') && req.path !== '/ws') { res.sendFile(path.join(distPath, 'index.html')) } else next() }) } const server = http.createServer(app) const wss = new WebSocketServer({ server, path: '/ws' }) wss.on('connection', (ws) => { ws.send(JSON.stringify({ type: 'situation', data: getSituation() })) }) function broadcastSituation() { try { const data = JSON.stringify({ type: 'situation', data: getSituation() }) wss.clients.forEach((c) => { if (c.readyState === 1) c.send(data) }) } catch (_) {} } setInterval(broadcastSituation, 3000) // 供爬虫调用:更新 situation.updated_at 并立即广播 function notifyCrawlerUpdate() { try { const db = require('./db') db.prepare("INSERT OR REPLACE INTO situation (id, data, updated_at) VALUES (1, '{}', ?)").run(new Date().toISOString()) broadcastSituation() } catch (_) {} } server.listen(PORT, () => { console.log(`API + WebSocket running at http://localhost:${PORT}`) })