import express, { Request, Response } from 'express'; import cors from 'cors'; import helmet from 'helmet'; import rateLimit from 'express-rate-limit'; import dotenv from 'dotenv'; dotenv.config(); import authRoutes from './routes/auth'; import userRoutes from './routes/user'; import schemeRoutes from './routes/schemes'; import schemeAobRoutes from './routes/schemesAob'; import filterRoutes from './routes/filters'; import vipRoutes from './routes/vip'; import favoriteRoutes from './routes/favorites'; const app = express(); const PORT = process.env.PORT || 3001; // ============================================ // 中间件 // ============================================ // 安全头 - 开发模式禁用 CSP app.use(helmet({ contentSecurityPolicy: false, crossOriginEmbedderPolicy: false, })); // CORS app.use(cors({ origin: true, // 允许所有来源(开发模式) credentials: true, })); // JSON 解析 app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true })); // 速率限制 const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 分钟 max: 100, // 每个 IP 最多 100 次请求 message: { success: false, message: '请求过于频繁,请稍后再试' }, }); app.use('/api/', limiter); // 登录接口更严格的限制 const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 10, message: { success: false, message: '登录尝试过于频繁,请稍后再试' }, }); app.use('/api/login', loginLimiter); app.use('/api/register', loginLimiter); // ============================================ // 路由 // ============================================ app.get('/api/activity/ping', (req, res) => { res.json({ success: true, message: 'pong', timestamp: Date.now() }); }); // 版本/健康检查 (用于验证部署) app.get('/api/version', (req, res) => { res.json({ version: 'd823421' }); }); app.use('/api', authRoutes); app.use('/api/user', userRoutes); app.use('/api/schemes', schemeRoutes); app.use('/api/schemes_aob', schemeAobRoutes); app.use('/api/filter-shares', filterRoutes); app.use('/api', vipRoutes); // 收藏计数(放在 favorites 路由之前,避免 auth 中间件拦截) app.get('/api/favorites/count', async (req: Request, res: Response) => { try { const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); const count = await prisma.favorite.count(); res.json({ success: true, count }); } catch (e) { res.json({ success: true, count: 0 }); } }); app.use('/api/favorites', favoriteRoutes); // ============================================ // 缺失的存根接口(防止前端 404) // ============================================ // 二维码 app.get('/api/qrcode/public/current', (req, res) => { res.json({ success: true, data: { qrcode: null, url: '' } }); }); // 弹窗 (通用参数化路由) app.get('/api/popups/:name', (req, res) => { const { name } = req.params; const popups: Record = { test_beta_01: { id: 'test_beta_01', title: '测试弹窗', content: '', shown: false }, }; res.json({ success: true, data: popups[name] ?? null }); }); // 嘉豪弹窗 app.get('/api/jiahao', (req, res) => { res.json({ success: true, data: { enabled: false, message: '', imageUrl: '', }, }); }); // 售后教程弹窗 app.get('/api/aftersale-tutorial-popup', (req, res) => { res.json({ success: true, data: { shown: false } }); }); // 软件版本广告(空数据,dock 无广告项) app.get('/api/software-version-ad', (req, res) => { res.json({ success: true, data: { items: [] } }); }); // 游戏地图密码缓存 app.get('/api/game/map-password/cached', (req, res) => { res.json({ success: true, data: [] }); }); // 筛选分类 app.get('/api/filter-share/categories', (req, res) => { res.json({ success: true, data: [] }); }); // ============================================ // 武器调谐窗 (weapon-tuner) 所需的 API // ============================================ // 武器分类列表 app.get('/api/weapon-categories', (req, res) => { const categories = [ { category: 'AR', name: '突击步枪' }, { category: 'SMG', name: '冲锋枪' }, { category: 'SR', name: '狙击步枪' }, { category: 'LMG', name: '轻机枪' }, { category: 'SG', name: '霰弹枪' }, { category: 'Pistol', name: '手枪' }, { category: 'Launcher', name: '发射器' }, ]; res.json({ success: true, data: categories }); }); // 武器列表(按分类筛选) app.get('/api/weapons', (req, res) => { res.json({ success: true, data: [] }); }); // 分类下的武器 app.get('/api/category/:code', (req, res) => { res.json({ success: true, data: [] }); }); // 广告列表 app.get('/api/adverts/list', (req, res) => { res.json({ success: true, data: [ { id: 1, title: '码枪堂2.0 新版发布', description: '全新界面,更多功能,一键优化三角洲行动游戏体验!', author: '码枪堂官方', avatar: null, image_url: '', link_url: 'https://wwamt.lanzout.com/b00odpq4wb', isAdvert: true, isVip: true, shareTime: new Date().toISOString(), } ] }); }); // 广告点击 app.post('/api/adverts/:id/click', (req, res) => { res.json({ success: true, message: 'ok' }); }); // 头像列表 app.get('/api/avatars', (req, res) => { res.json({ success: true, data: [] }); }); // ============================================ // 更新服务 (electron-updater) // ============================================ // 更新配置 app.get('/update-config.json', (req, res) => { res.json({ version: '7.0.4', url: '', notes: '', mandatory: false, }); }); // latest.yml (electron-updater 标准格式) app.get('/latest.yml', (req, res) => { res.type('text/yaml'); res.send(`version: 7.0.4 files: [] releaseDate: '2024-01-01T00:00:00.000Z' `); }); // ============================================ // 错误处理 // ============================================ app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { console.error('Error:', err); if (err.name === 'UnauthorizedError') { return res.status(401).json({ success: false, message: '访问令牌无效', code: 'INVALID_TOKEN' }); } if (err.name === 'ZodError') { return res.status(400).json({ success: false, message: '参数验证失败', errors: err.errors }); } res.status(500).json({ success: false, message: '服务器内部错误' }); }); // 404 app.use((req, res) => { res.status(404).json({ success: false, message: '接口不存在' }); }); // ============================================ // 启动 // ============================================ app.listen(PORT, () => { console.log(`🚀 码枪堂 API 运行在 http://localhost:${PORT}`); console.log(`📋 可用接口:`); console.log(` POST /api/login`); console.log(` POST /api/register`); console.log(` POST /api/activate-vip`); console.log(` GET /api/session-status`); console.log(` GET /api/vip-status`); }); export default app;